ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/porting.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:11:39 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22, UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

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