ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/porting.C
(Generate patch)

Comparing deliantra/server/common/porting.C (file contents):
Revision 1.2 by root, Tue Aug 29 08:01:35 2006 UTC vs.
Revision 1.11 by pippijn, Sat Jan 6 14:42:29 2007 UTC

1/*
2 * static char *rcsid_porting_c =
3 * "$Id: porting.C,v 1.2 2006/08/29 08:01:35 root Exp $";
4 */
5
6/* 1/*
7 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
8 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
11 7
12 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
21 17
22 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 21
26 The authors can be reached via e-mail at crossfire-devel@real-time.com 22 The authors can be reached via e-mail at <crossfire@schmorp.de>
27*/ 23*/
28 24
29/* This file contains various functions that are not really unique for 25/* This file contains various functions that are not really unique for
30 * crossfire, but rather provides what should be standard functions 26 * crossfire, but rather provides what should be standard functions
31 * for systems that do not have them. In this way, most of the 27 * for systems that do not have them. In this way, most of the
32 * nasty system dependent stuff is contained here, with the program 28 * nasty system dependent stuff is contained here, with the program
33 * calling these functions. 29 * calling these functions.
34 */ 30 */
35 31
36 32
37#ifdef WIN32 /* ---win32 exclude/include headers */ 33/* Need to pull in the HAVE_... values somehow */
38#include "process.h" 34
39#define pid_t int /* we include it non global, because there is a redefinition in python.h */ 35#include <autoconf.h>
40#else 36
37#include <cstdio>
38#include <cstdlib>
39#include <cstdarg>
40
41#include <ctype.h> 41#include <cctype>
42
42#include <sys/stat.h> 43#include <sys/stat.h>
43#include <sys/wait.h> 44#include <sys/wait.h>
44 45
45#include <sys/param.h> 46#include <sys/param.h>
46#include <stdio.h>
47 47
48/* Need to pull in the HAVE_... values somehow */
49/* win32 reminder: always put this in a ifndef win32 block */
50#include <autoconf.h>
51#endif
52
53
54#ifdef HAVE_STDLIB_H
55#include <stdlib.h>
56#endif
57
58#ifdef HAVE_UNISTD_H
59#include <unistd.h> 48#include <unistd.h>
60#endif
61 49
62#include <stdarg.h>
63/* Has to be after above includes so we don't redefine some values */ 50/* Has to be after above includes so we don't redefine some values */
64#include "global.h" 51#include "global.h"
65 52
66static unsigned int curtmp = 0; 53static unsigned int curtmp = 0;
67 54
68/* This is a list of the suffix, uncompress and compress functions. Thus,
69 * if you have some other compress program you want to use, the only thing
70 * that needs to be done is to extended this.
71 * The first entry must be NULL - this is what is used for non
72 * compressed files.
73 */
74EXTERN char *uncomp[NROF_COMPRESS_METHODS][3] = {
75 {NULL, NULL, NULL},
76 {".Z", UNCOMPRESS, COMPRESS},
77 {".gz", GUNZIP, GZIP},
78 {".bz2", BUNZIP, BZIP}
79};
80
81/*****************************************************************************
82 * File related functions
83 ****************************************************************************/
84
85/*
86 * A replacement for the tempnam() function since it's not defined
87 * at some unix variants.
88 */
89
90char *tempnam_local(const char *dir, const char *pfx)
91{
92 char *name;
93 pid_t pid=getpid();
94
95/* HURD does not have a hard limit, but we do */
96#ifndef MAXPATHLEN
97#define MAXPATHLEN 4096
98#endif
99
100 if (!(name = (char *) malloc(MAXPATHLEN)))
101 return(NULL);
102
103 if (!pfx)
104 pfx = "cftmp.";
105
106 /* This is a pretty simple method - put the pid as a hex digit and
107 * just keep incrementing the last digit. Check to see if the file
108 * already exists - if so, we'll just keep looking - eventually we should
109 * find one that is free.
110 */
111 if (dir!=NULL) {
112 do {
113#ifdef HAVE_SNPRINTF
114 (void)snprintf(name, MAXPATHLEN, "%s/%s%hx.%d", dir, pfx, pid, curtmp);
115#else
116 (void)sprintf(name,"%s/%s%hx%d", dir, pfx, pid, curtmp);
117#endif
118 curtmp++;
119 } while (access(name, F_OK)!=-1);
120 return(name);
121 }
122 return(NULL);
123}
124
125
126
127/* This function removes everything in the directory. */ 55/* This function removes everything in the directory. */
56void
128void remove_directory(const char *path) 57remove_directory (const char *path)
129{ 58{
130 DIR *dirp; 59 DIR *dirp;
131 char buf[MAX_BUF]; 60 char buf[MAX_BUF];
132 struct stat statbuf; 61 struct stat statbuf;
133 int status; 62 int status;
134 63
135 if ((dirp=opendir(path))!=NULL) { 64 if ((dirp = opendir (path)) != NULL)
65 {
136 struct dirent *de; 66 struct dirent *de;
137 67
138 for (de=readdir(dirp); de; de = readdir(dirp)) { 68 for (de = readdir (dirp); de; de = readdir (dirp))
69 {
139 /* Don't remove '.' or '..' In theory we should do a better 70 /* Don't remove '.' or '..' In theory we should do a better
140 * check for .., but the directories we are removing are fairly 71 * check for .., but the directories we are removing are fairly
141 * limited and should not have dot files in them. 72 * limited and should not have dot files in them.
142 */ 73 */
143 if (de->d_name[0] == '.') continue; 74 if (de->d_name[0] == '.')
75 continue;
144 76
145 /* Linux actually has a type field in the dirent structure, 77 /* Linux actually has a type field in the dirent structure,
146 * but that is not portable - stat should be portable 78 * but that is not portable - stat should be portable
147 */ 79 */
148 status=stat(de->d_name, &statbuf); 80 status = stat (de->d_name, &statbuf);
149 if ((status!=-1) && (S_ISDIR(statbuf.st_mode))) { 81 if ((status != -1) && (S_ISDIR (statbuf.st_mode)))
82 {
150 sprintf(buf,"%s/%s", path, de->d_name); 83 sprintf (buf, "%s/%s", path, de->d_name);
151 remove_directory(buf); 84 remove_directory (buf);
152 continue; 85 continue;
153 } 86 }
154 sprintf(buf,"%s/%s", path, de->d_name); 87 sprintf (buf, "%s/%s", path, de->d_name);
155 if (unlink(buf)) { 88 if (unlink (buf))
89 {
156 LOG(llevError,"Unable to remove directory %s\n", path); 90 LOG (llevError, "Unable to remove directory %s\n", path);
157 } 91 }
158 } 92 }
159 closedir(dirp); 93 closedir (dirp);
160 } 94 }
161 if (rmdir(path)) { 95 if (rmdir (path))
96 {
162 LOG(llevError,"Unable to remove directory %s\n", path); 97 LOG (llevError, "Unable to remove directory %s\n", path);
163 } 98 }
164} 99}
165
166#if defined(sgi)
167
168#include <stdio.h>
169#include <stdlib.h>
170#include <string.h>
171
172#define popen fixed_popen
173
174FILE *popen_local(const char *command, const char *type)
175{
176 int fd[2];
177 int pd;
178 FILE *ret;
179 if (!strcmp(type,"r"))
180 {
181 pd=STDOUT_FILENO;
182 }
183 else if (!strcmp(type,"w"))
184 {
185 pd=STDIN_FILENO;
186 }
187 else
188 {
189 return NULL;
190 }
191 if (pipe(fd)!=-1)
192 {
193 switch (fork())
194 {
195 case -1:
196 close(fd[0]);
197 close(fd[1]);
198 break;
199 case 0:
200 close(fd[0]);
201 if ((fd[1]==pd)||(dup2(fd[1],pd)==pd))
202 {
203 if (fd[1]!=pd)
204 {
205 close(fd[1]);
206 }
207 execl("/bin/sh","sh","-c",command,NULL);
208 close(pd);
209 }
210 exit(1);
211 break;
212 default:
213 close(fd[1]);
214 if (ret=fdopen(fd[0],type))
215 {
216 return ret;
217 }
218 close(fd[0]);
219 break;
220 }
221 }
222 return NULL;
223}
224
225#endif /* defined(sgi) */
226
227
228/*****************************************************************************
229 * String related function
230 ****************************************************************************/
231
232
233
234/*
235 * A replacement of strdup(), since it's not defined at some
236 * unix variants.
237 */
238char *strdup_local(const char *str) {
239 char *c=(char *)malloc(sizeof(char)*(strlen(str)+1));
240 strcpy(c,str);
241 return c;
242}
243
244 100
245#define DIGIT(x) (isdigit(x) ? (x) - '0' : \ 101#define DIGIT(x) (isdigit(x) ? (x) - '0' : \
246islower (x) ? (x) + 10 - 'a' : (x) + 10 - 'A') 102islower (x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
247#define MBASE ('z' - 'a' + 1 + 10) 103#define MBASE ('z' - 'a' + 1 + 10)
248 104
249/* This seems to be lacking on some system */ 105char *
250#if !defined(HAVE_STRNCASECMP)
251int strncasecmp(const char *s1, const char *s2, int n)
252{
253 register int c1, c2;
254
255 while (*s1 && *s2 && n) {
256 c1 = tolower(*s1);
257 c2 = tolower(*s2);
258 if (c1 != c2)
259 return (c1 - c2);
260 s1++;
261 s2++;
262 n--;
263 }
264 if (!n)
265 return(0);
266 return (int) (*s1 - *s2);
267}
268#endif
269
270#if !defined(HAVE_STRCASECMP)
271int strcasecmp(const char *s1, const char*s2)
272{
273 register int c1, c2;
274
275 while (*s1 && *s2) {
276 c1 = tolower(*s1);
277 c2 = tolower(*s2);
278 if (c1 != c2)
279 return (c1 - c2);
280 s1++;
281 s2++;
282 }
283 if (*s1=='\0' && *s2=='\0')
284 return 0;
285 return (int) (*s1 - *s2);
286}
287#endif
288
289char *strcasestr_local(const char *s, const char *find) 106strcasestr_local (const char *s, const char *find)
290{ 107{
291 char c, sc; 108 char c, sc;
292 size_t len; 109 size_t len;
293 110
294 if ((c = *find++) != 0) { 111 if ((c = *find++) != 0)
112 {
295 c = tolower(c); 113 c = tolower (c);
296 len = strlen(find); 114 len = strlen (find);
115 do
297 do { 116 {
117 do
298 do { 118 {
299 if ((sc = *s++) == 0) 119 if ((sc = *s++) == 0)
300 return NULL; 120 return NULL;
121 }
301 } while (tolower(sc) != c); 122 while (tolower (sc) != c);
123 }
302 } while (strncasecmp(s, find, len) != 0); 124 while (strncasecmp (s, find, len) != 0);
303 s--; 125 s--;
304 } 126 }
305 return (char *)s; 127 return (char *) s;
306}
307
308#if !defined(HAVE_SNPRINTF)
309
310int snprintf(char *dest, int max, const char *format, ...)
311{
312 va_list var;
313 int ret;
314
315 va_start(var, format);
316 ret = vsprintf(dest, format, var);
317 va_end(var);
318 if (ret > max) abort();
319
320 return ret;
321}
322#endif
323
324
325/* This takes an err number and returns a string with a description of
326 * the error.
327 */
328char *strerror_local(int errnum)
329{
330#if defined(HAVE_STRERROR)
331 return(strerror(errnum));
332#else
333 return("strerror_local not implemented");
334#endif
335} 128}
336 129
337/* 130/*
338 * Based on (n+1)^2 = n^2 + 2n + 1 131 * Based on (n+1)^2 = n^2 + 2n + 1
339 * given that 1^2 = 1, then 132 * given that 1^2 = 1, then
343 * ... 136 * ...
344 * In other words, a square number can be express as the sum of the 137 * In other words, a square number can be express as the sum of the
345 * series n^2 = 1 + 3 + ... + (2n-1) 138 * series n^2 = 1 + 3 + ... + (2n-1)
346 */ 139 */
347int 140int
348isqrt(int n) 141isqrt (int n)
349{ 142{
350 int result, sum, prev; 143 int result, sum, prev;
144
351 result = 0; 145 result = 0;
352 prev = sum = 1; 146 prev = sum = 1;
353 while (sum <= n) { 147 while (sum <= n)
148 {
354 prev += 2; 149 prev += 2;
355 sum += prev; 150 sum += prev;
356 ++result; 151 ++result;
357 } 152 }
358 return result; 153 return result;
359} 154}
360
361 155
362/* 156/*
363 * returns a char-pointer to a static array, in which a representation 157 * returns a char-pointer to a static array, in which a representation
364 * of the decimal number given will be stored. 158 * of the decimal number given will be stored.
365 */ 159 */
366 160char *
367char *ltostr10(signed long n) { 161ltostr10 (signed long n)
162{
368 static char buf[12]; /* maximum size is n=-2 billion, i.e. 11 characters+1 163 static char buf[12]; /* maximum size is n=-2 billion, i.e. 11 characters+1
369 character for the trailing nul character */ 164 character for the trailing nul character */
370 snprintf(buf, sizeof(buf), "%ld", n); 165 snprintf (buf, sizeof (buf), "%ld", n);
371 return buf; 166 return buf;
372} 167}
168
169char *
373char *doubletostr10(double v){ 170doubletostr10 (double v)
171{
374 static char tbuf[200]; 172 static char tbuf[200];
173
375 sprintf(tbuf,"%f",v); 174 sprintf (tbuf, "%f", v);
376 return tbuf; 175 return tbuf;
377}
378
379/*
380 * A fast routine which appends the name and decimal number specified
381 * to the given buffer.
382 * Could be faster, though, if the strcat()s at the end could be changed
383 * into alternate strcat which returned a pointer to the _end_, not the
384 * start!
385 *
386 * Hey good news, it IS faster now, according to changes in get_ob_diff
387 * Completly redone prototype and made define in loader.l. See changes there.
388 * Didn't touch those for speed reason (don't use them anymore) .
389 * Tchize
390 */
391
392void save_long(char *buf, char *name, long n) {
393 char buf2[MAX_BUF];
394 strcpy(buf2,name);
395 strcat(buf2," ");
396 strcat(buf2,ltostr10(n));
397 strcat(buf2,"\n");
398 strcat(buf,buf2);
399}
400
401
402
403void save_long_long(char *buf, char *name, sint64 n) {
404 char buf2[MAX_BUF];
405
406#ifndef WIN32
407 sprintf(buf2,"%s %lld\n", name, n);
408#else
409 sprintf(buf2,"%s %I64d\n", name, n);
410#endif
411 strcat(buf,buf2);
412}
413
414/**
415 * Open and possibly uncompress a file.
416 *
417 * @param ext the extension if the file is compressed.
418 *
419 * @param uncompressor the command to uncompress the file if the file is
420 * compressed.
421 *
422 * @param name the base file name without compression extension
423 *
424 * @param flag only used for compressed files: if set, uncompress and open the
425 * file; if unset, uncompress the file via pipe
426 *
427 * @param *compressed set to zero if the file was uncompressed
428 */
429static FILE *open_and_uncompress_file(const char *ext, const char *uncompressor, const char *name, int flag, int *compressed) {
430 struct stat st;
431 char buf[MAX_BUF];
432 char buf2[MAX_BUF];
433 int ret;
434
435 if (ext == NULL) {
436 ext = "";
437 }
438
439 if (strlen(name)+strlen(ext) >= sizeof(buf)) {
440 errno = ENAMETOOLONG; /* File name too long */
441 return NULL;
442 }
443 sprintf(buf, "%s%s", name, ext);
444
445 if (stat(buf, &st) != 0) {
446 return NULL;
447 }
448
449 if (!S_ISREG(st.st_mode)) {
450 errno = EISDIR; /* Not a regular file */
451 return NULL;
452 }
453
454 if (uncompressor == NULL) {
455 /* open without uncompression */
456
457 return fopen(buf, "r");
458 }
459
460 /* The file name buf (and its substring name) is passed as an argument to a
461 * shell command, therefore check for characters that could confuse the
462 * shell.
463 */
464 if (strpbrk(buf, "'\\\r\n") != NULL) {
465 errno = ENOENT; /* Pretend the file does not exist */
466 return NULL;
467 }
468
469 if (!flag) {
470 /* uncompress via pipe */
471
472 if (strlen(uncompressor)+4+strlen(buf)+1 >= sizeof(buf2)) {
473 errno = ENAMETOOLONG; /* File name too long */
474 return NULL;
475 }
476 sprintf(buf2, "%s < '%s'", uncompressor, buf);
477
478 return popen(buf2, "r");
479 }
480
481 /* remove compression from file, then open file */
482
483 if (stat(name, &st) == 0 && !S_ISREG(st.st_mode)) {
484 errno = EISDIR;
485 return NULL;
486 }
487
488 if (strlen(uncompressor)+4+strlen(buf)+5+strlen(name)+1 >= sizeof(buf2)) {
489 errno = ENAMETOOLONG; /* File name too long */
490 return NULL;
491 }
492 sprintf(buf2, "%s < '%s' > '%s'", uncompressor, buf, name);
493
494 ret = system(buf2);
495 if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
496 LOG(llevError, "system(%s) returned %d\n", buf2, ret);
497 errno = ENOENT;
498 return NULL;
499 }
500
501 unlink(buf); /* Delete the original */
502 *compressed = 0; /* Change to "uncompressed file" */
503 chmod(name, st.st_mode); /* Copy access mode from compressed file */
504
505 return fopen(name, "r");
506} 176}
507 177
508/** 178/**
509 * open_and_uncompress() first searches for the original filename. If it exist, 179 * open_and_uncompress() first searches for the original filename. If it exist,
510 * then it opens it and returns the file-pointer. 180 * then it opens it and returns the file-pointer.
511 * 181 */
512 * If not, it does two things depending on the flag. If the flag is set, it 182FILE *
513 * tries to create the original file by appending a compression suffix to name
514 * and uncompressing it. If the flag is not set, it creates a pipe that is used
515 * for reading the file (NOTE - you can not use fseek on pipes).
516 *
517 * The compressed pointer is set to nonzero if the file is compressed (and
518 * thus, fp is actually a pipe.) It returns 0 if it is a normal file.
519 */
520FILE *open_and_uncompress(const char *name, int flag, int *compressed) { 183open_and_uncompress (const char *name, int flag, int *compressed)
521 size_t i; 184{
522 FILE *fp;
523
524 for (i = 0; i < NROF_COMPRESS_METHODS; i++) {
525 *compressed = i; 185 *compressed = 0;
526 fp = open_and_uncompress_file(uncomp[i][0], uncomp[i][1], name, flag, compressed); 186 return fopen (name, "r");
527 if (fp != NULL) { 187}
188
189/*
190 * See open_and_uncompress().
191 */
192
193void
194close_and_delete (FILE * fp, int compressed)
195{
196 fclose (fp);
197}
198
199/*
200 * If any directories in the given path doesn't exist, they are created.
201 */
202
203void
204make_path_to_file (char *filename)
205{
206 char buf[MAX_BUF], *cp = buf;
207 struct stat statbuf;
208
209 if (!filename || !*filename)
210 return;
211 strcpy (buf, filename);
212
213 while ((cp = strchr (cp + 1, (int) '/')))
214 {
215 *cp = '\0';
216 if (stat (buf, &statbuf) || !S_ISDIR (statbuf.st_mode))
217 {
218 if (mkdir (buf, SAVE_DIR_MODE))
219 {
220 LOG (llevError, "Cannot mkdir %s: %s\n", buf, strerror (errno));
528 return fp; 221 return;
222 }
529 } 223 }
530 }
531
532 errno = ENOENT;
533 return NULL;
534}
535
536/*
537 * See open_and_uncompress().
538 */
539
540void close_and_delete(FILE *fp, int compressed) {
541 if (compressed)
542 pclose(fp);
543 else
544 fclose(fp);
545}
546
547/*
548 * If any directories in the given path doesn't exist, they are created.
549 */
550
551void make_path_to_file (char *filename)
552{
553 char buf[MAX_BUF], *cp = buf;
554 struct stat statbuf;
555
556 if (!filename || !*filename)
557 return;
558 strcpy (buf, filename);
559
560 while ((cp = strchr (cp + 1, (int) '/'))) {
561 *cp = '\0';
562 if (stat(buf, &statbuf) || !S_ISDIR (statbuf.st_mode)) {
563 if (mkdir (buf, SAVE_DIR_MODE)) {
564 LOG(llevError, "Cannot mkdir %s: %s\n", buf, strerror_local(errno));
565 return;
566 }
567 }
568 *cp = '/'; 224 *cp = '/';
569 } 225 }
570} 226}
571

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines