|
|
1.1 root 1: /* dirwrap.c */
2:
3: /* Directory-related system-call wrappers */
4:
5: /* $Id: dirwrap.c,v 1.42 2004/10/28 22:00:56 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <string.h> /* strrchr */
39:
40: #if defined(_WIN32)
41:
42: #include <windows.h> /* WINAPI, etc */
43: #include <io.h> /* _findfirst */
44:
45: #elif defined __unix__
46:
47: #include <unistd.h> /* usleep */
48: #include <fcntl.h> /* O_NOCCTY */
49: #include <ctype.h> /* toupper */
50: #include <sys/param.h>
51:
52: #if defined(BSD)
53: #include <sys/mount.h>
54: #if defined(__FreeBSD__)
55: #include <sys/kbio.h>
56: #endif
57: #endif
58:
59: #include <sys/ioctl.h> /* ioctl */
60:
61: #if defined(__GLIBC__) /* actually, BSD, but will work for now */
62: #include <sys/vfs.h> /* statfs() */
63: #endif
64:
65: #if defined(__solaris__)
66: #include <sys/statvfs.h>
67: #endif
68:
69: #endif /* __unix__ */
70:
71: #if defined(__WATCOMC__)
72: #include <dos.h>
73: #endif
74:
75: #include <sys/types.h> /* _dev_t */
76: #include <sys/stat.h> /* struct stat */
77:
78: #include <stdio.h> /* sprintf */
79: #include <stdlib.h> /* rand */
80: #include <errno.h> /* ENOENT definitions */
81:
82: #include "genwrap.h" /* strupr/strlwr */
83: #include "dirwrap.h" /* DLLCALL */
84:
85: /****************************************************************************/
86: /* Return the filename portion of a full pathname */
87: /****************************************************************************/
88: char* DLLCALL getfname(const char* path)
89: {
90: const char* fname;
91: const char* bslash;
92:
93: fname=strrchr(path,'/');
94: bslash=strrchr(path,'\\');
95: if(bslash>fname)
96: fname=bslash;
97: if(fname!=NULL)
98: fname++;
99: else
100: fname=(char*)path;
101: return((char*)fname);
102: }
103:
104: /****************************************************************************/
105: /* Return a pointer to a file's extesion (beginning with '.') */
106: /****************************************************************************/
107: char* DLLCALL getfext(const char* path)
108: {
109: char *fname;
110: char *fext;
111:
112: fname=getfname(path);
113: fext=strrchr(fname,'.');
114: if(fext==NULL || fext==fname)
115: return(NULL);
116: return(fext);
117: }
118:
119: /****************************************************************************/
120: /* Break a path name into components. */
121: /****************************************************************************/
122: #if defined(__unix__)
123: void DLLCALL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
124: {
125: char* p;
126:
127: ext[0]=0;
128: drive[0]=0; /* no drive letters on Unix */
129:
130: strcpy(dir,path); /* Optional directory path, including trailing slash. */
131: p=getfname(dir);
132: strcpy(fname,p); /* Base filename (no extension) */
133: if(p==dir)
134: dir[0]=0; /* no directory specified in path */
135: else
136: *p=0; /* truncate dir at filename */
137: p=getfext(fname);
138: if(p!=NULL) {
139: strcpy(ext,p); /* Optional filename extension, including leading period (.) */
140: *p=0;
141: }
142: }
143: #endif
144:
145: /****************************************************************************/
146: /* Win32 (minimal) implementation of POSIX.2 glob() function */
147: /* This code _may_ work on other DOS-based platforms (e.g. OS/2) */
148: /****************************************************************************/
149: #if !defined(__unix__)
150: static int glob_compare( const void *arg1, const void *arg2 )
151: {
152: /* Compare all of both strings: */
153: return stricmp( * ( char** ) arg1, * ( char** ) arg2 );
154: }
155:
156: #if defined(__BORLANDC__)
157: #pragma argsused
158: #endif
159:
160: #if defined(__WATCOMC__)
161:
162: int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t* glob)
163: {
164: struct find_t ff;
165: size_t found=0;
166: char path[MAX_PATH+1];
167: char* p;
168: char** new_pathv;
169:
170: if(!(flags&GLOB_APPEND)) {
171: glob->gl_pathc=0;
172: glob->gl_pathv=NULL;
173: }
174:
175: if(_dos_findfirst((char*)pattern,_A_NORMAL,&ff)!=0)
176: return(GLOB_NOMATCH);
177:
178: do {
179: if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
180: (!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
181: if((new_pathv=realloc(glob->gl_pathv
182: ,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
183: globfree(glob);
184: return(GLOB_NOSPACE);
185: }
186: glob->gl_pathv=new_pathv;
187:
188: /* build the full pathname */
189: SAFECOPY(path,pattern);
190: p=getfname(path);
191: *p=0;
192: strcat(path,ff.name);
193:
194: if((glob->gl_pathv[glob->gl_pathc]=malloc(strlen(path)+2))==NULL) {
195: globfree(glob);
196: return(GLOB_NOSPACE);
197: }
198: strcpy(glob->gl_pathv[glob->gl_pathc],path);
199: if(flags&GLOB_MARK && ff.attrib&_A_SUBDIR)
200: strcat(glob->gl_pathv[glob->gl_pathc],"/");
201:
202: glob->gl_pathc++;
203: found++;
204: }
205: } while(_dos_findnext(&ff)==0);
206: _dos_findclose(&ff);
207:
208: if(found==0)
209: return(GLOB_NOMATCH);
210:
211: if(!(flags&GLOB_NOSORT)) {
212: qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
213: }
214:
215: return(0); /* success */
216: }
217:
218: #else
219:
220: int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t* glob)
221: {
222: struct _finddata_t ff;
223: long ff_handle;
224: size_t found=0;
225: char path[MAX_PATH+1];
226: char* p;
227: char** new_pathv;
228:
229: if(!(flags&GLOB_APPEND)) {
230: glob->gl_pathc=0;
231: glob->gl_pathv=NULL;
232: }
233:
234: ff_handle=_findfirst((char*)pattern,&ff);
235: while(ff_handle!=-1) {
236: if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
237: (!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
238: if((new_pathv=(char**)realloc(glob->gl_pathv
239: ,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
240: globfree(glob);
241: return(GLOB_NOSPACE);
242: }
243: glob->gl_pathv=new_pathv;
244:
245: /* build the full pathname */
246: SAFECOPY(path,pattern);
247: p=getfname(path);
248: *p=0;
249: strcat(path,ff.name);
250:
251: if((glob->gl_pathv[glob->gl_pathc]=(char*)malloc(strlen(path)+2))==NULL) {
252: globfree(glob);
253: return(GLOB_NOSPACE);
254: }
255: strcpy(glob->gl_pathv[glob->gl_pathc],path);
256: if(flags&GLOB_MARK && ff.attrib&_A_SUBDIR)
257: strcat(glob->gl_pathv[glob->gl_pathc],"/");
258:
259: glob->gl_pathc++;
260: found++;
261: }
262: if(_findnext(ff_handle, &ff)!=0) {
263: _findclose(ff_handle);
264: ff_handle=-1;
265: }
266: }
267:
268: if(found==0)
269: return(GLOB_NOMATCH);
270:
271: if(!(flags&GLOB_NOSORT)) {
272: qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
273: }
274:
275: return(0); /* success */
276: }
277:
278: #endif
279:
280: void DLLCALL globfree(glob_t* glob)
281: {
282: size_t i;
283:
284: if(glob==NULL)
285: return;
286:
287: if(glob->gl_pathv!=NULL) {
288: for(i=0;i<glob->gl_pathc;i++)
289: if(glob->gl_pathv[i]!=NULL)
290: free(glob->gl_pathv[i]);
291:
292: free(glob->gl_pathv);
293: glob->gl_pathv=NULL;
294: }
295: glob->gl_pathc=0;
296: }
297:
298: #endif /* !defined(__unix__) */
299:
300: /****************************************************************************/
301: /* POSIX directory operations using Microsoft _findfirst/next API. */
302: /****************************************************************************/
303: #if defined(_MSC_VER) || defined(__DMC__)
304: DIR* opendir(const char* dirname)
305: {
306: DIR* dir;
307:
308: if((dir=(DIR*)calloc(1,sizeof(DIR)))==NULL) {
309: errno=ENOMEM;
310: return(NULL);
311: }
312: sprintf(dir->filespec,"%.*s",sizeof(dir->filespec)-5,dirname);
313: if(*dir->filespec && dir->filespec[strlen(dir->filespec)-1]!='\\')
314: strcat(dir->filespec,"\\");
315: strcat(dir->filespec,"*.*");
316: dir->handle=_findfirst(dir->filespec,&dir->finddata);
317: if(dir->handle==-1) {
318: errno=ENOENT;
319: free(dir);
320: return(NULL);
321: }
322: return(dir);
323: }
324: struct dirent* readdir(DIR* dir)
325: {
326: if(dir==NULL)
327: return(NULL);
328: if(dir->end==TRUE)
329: return(NULL);
330: if(dir->handle==-1)
331: return(NULL);
332: sprintf(dir->dirent.d_name,"%.*s",sizeof(struct dirent)-1,dir->finddata.name);
333: if(_findnext(dir->handle,&dir->finddata)!=0)
334: dir->end=TRUE;
335: return(&dir->dirent);
336: }
337: int closedir (DIR* dir)
338: {
339: if(dir==NULL)
340: return(-1);
341: _findclose(dir->handle);
342: free(dir);
343: return(0);
344: }
345: void rewinddir(DIR* dir)
346: {
347: if(dir==NULL)
348: return;
349: _findclose(dir->handle);
350: dir->end=FALSE;
351: dir->handle=_findfirst(dir->filespec,&dir->finddata);
352: }
353: #endif /* defined(_MSC_VER) */
354:
355: /****************************************************************************/
356: /* Returns the time/date of the file in 'filename' in time_t (unix) format */
357: /****************************************************************************/
358: time_t DLLCALL fdate(const char* filename)
359: {
360: struct stat st;
361:
362: if(access(filename,0)==-1)
363: return(-1);
364:
365: if(stat(filename, &st)!=0)
366: return(-1);
367:
368: return(st.st_mtime);
369: }
370:
371: /****************************************************************************/
372: /* Change the access and modification times for specified filename */
373: /****************************************************************************/
374: int DLLCALL setfdate(const char* filename, time_t t)
375: {
376: struct utimbuf ut;
377:
378: memset(&ut,0,sizeof(ut));
379:
380: ut.actime=t;
381: ut.modtime=t;
382:
383: return(utime(filename,&ut));
384: }
385:
386: /****************************************************************************/
387: /* Returns the length of the file in 'filename' */
388: /****************************************************************************/
389: long DLLCALL flength(const char *filename)
390: {
391: #if defined(__BORLANDC__) && !defined(__unix__) /* stat() doesn't work right */
392:
393: long handle;
394: struct _finddata_t f;
395:
396: if(access((char*)filename,0)==-1)
397: return(-1L);
398:
399: if((handle=_findfirst((char*)filename,&f))==-1)
400: return(-1);
401:
402: _findclose(handle);
403:
404: return(f.size);
405:
406: #else
407:
408: struct stat st;
409:
410: if(access(filename,0)==-1)
411: return(-1L);
412:
413: if(stat(filename, &st)!=0)
414: return(-1L);
415:
416: return(st.st_size);
417:
418: #endif
419: }
420:
421: /****************************************************************************/
422: /* Checks the file system for the existence of one or more files. */
423: /* Returns TRUE if it exists, FALSE if it doesn't. */
424: /* 'filespec' may contain wildcards! */
425: /****************************************************************************/
426: BOOL DLLCALL fexist(const char *filespec)
427: {
428: #if defined(_WIN32)
429:
430: long handle;
431: struct _finddata_t f;
432:
433: if(access(filespec,0)==-1 && !strchr(filespec,'*') && !strchr(filespec,'?'))
434: return(FALSE);
435:
436: if((handle=_findfirst((char*)filespec,&f))==-1)
437: return(FALSE);
438:
439: _findclose(handle);
440:
441: if(f.attrib&_A_SUBDIR)
442: return(FALSE);
443:
444: return(TRUE);
445:
446: #else /* Unix or OS/2 */
447:
448: /* portion by cmartin */
449:
450: glob_t g;
451: int c;
452:
453: if(access(filespec,0)==-1 && !strchr(filespec,'*') && !strchr(filespec,'?'))
454: return(FALSE);
455:
456: // start the search
457: glob(filespec, GLOB_MARK | GLOB_NOSORT, NULL, &g);
458:
459: if (!g.gl_pathc) {
460: // no results
461: globfree(&g);
462: return FALSE;
463: }
464:
465: // make sure it's not a directory
466: c = g.gl_pathc;
467: while (c--) {
468: if (*lastchar(g.gl_pathv[c]) != '/') {
469: globfree(&g);
470: return TRUE;
471: }
472: }
473:
474: globfree(&g);
475: return FALSE;
476:
477: #endif
478: }
479:
480: /****************************************************************************/
481: /* Fixes upper/lowercase filename for Unix file systems */
482: /****************************************************************************/
483: BOOL DLLCALL fexistcase(char *path)
484: {
485: #if defined(_WIN32)
486:
487: char* fname;
488: long handle;
489: struct _finddata_t f;
490:
491: if(access(path,0)==-1 && !strchr(path,'*') && !strchr(path,'?'))
492: return(FALSE);
493:
494: if((handle=_findfirst((char*)path,&f))==-1)
495: return(FALSE);
496:
497: _findclose(handle);
498:
499: if(f.attrib&_A_SUBDIR)
500: return(FALSE);
501:
502: fname=getfname(path); /* Find filename in path */
503: strcpy(fname,f.name); /* Correct filename */
504:
505: return(TRUE);
506:
507: #else /* Unix or OS/2 */
508:
509: char globme[MAX_PATH*4+1];
510: char fname[MAX_PATH+1];
511: char tmp[5];
512: char *p;
513: int i;
514: glob_t glb;
515:
516: SAFECOPY(globme,path);
517: p=getfname(globme);
518: SAFECOPY(fname,p);
519: *p=0;
520: for(i=0;fname[i];i++) {
521: if(isalpha(fname[i]))
522: sprintf(tmp,"[%c%c]",toupper(fname[i]),tolower(fname[i]));
523: else
524: sprintf(tmp,"%c",fname[i]);
525: strncat(globme,tmp,MAX_PATH*4);
526: }
527: if(strcspn(path,"?*")!=strlen(path)) {
528: sprintf(path,"%.*s",MAX_PATH,globme);
529: return(fexist(path));
530: }
531:
532: if(glob(globme,GLOB_MARK,NULL,&glb) != 0)
533: return(FALSE);
534:
535: if(glb.gl_pathc>0) {
536: for(i=0;i<glb.gl_pathc;i++) {
537: if(*lastchar(glb.gl_pathv[i]) != '/')
538: break;
539: }
540: if(i<glb.gl_pathc) {
541: sprintf(path,"%.*s",MAX_PATH,glb.gl_pathv[i]);
542: globfree(&glb);
543: return TRUE;
544: }
545: }
546:
547: globfree(&glb);
548: return FALSE;
549:
550: #endif
551: }
552:
553: #if !defined(S_ISDIR)
554: #define S_ISDIR(x) ((x)&S_IFDIR)
555: #endif
556:
557: /****************************************************************************/
558: /* Returns TRUE if the filename specified is a directory */
559: /****************************************************************************/
560: BOOL DLLCALL isdir(const char *filename)
561: {
562: char path[MAX_PATH+1];
563: char* p;
564: struct stat st;
565:
566: SAFECOPY(path,filename);
567:
568: p=lastchar(path);
569: if(p!=path && IS_PATH_DELIM(*p)) { /* chop off trailing slash */
570: #if !defined(__unix__)
571: if(*(p-1)!=':') /* Don't change C:\ to C: */
572: #endif
573: *p=0;
574: }
575:
576: if(stat(path, &st)!=0)
577: return(FALSE);
578:
579: return(S_ISDIR(st.st_mode) ? TRUE : FALSE);
580: }
581:
582: /****************************************************************************/
583: /* Returns the attributes (mode) for specified 'filename' */
584: /****************************************************************************/
585: int DLLCALL getfattr(const char* filename)
586: {
587: #if defined(_WIN32)
588: long handle;
589: struct _finddata_t finddata;
590:
591: if((handle=_findfirst((char*)filename,&finddata))==-1) {
592: errno=ENOENT;
593: return(-1);
594: }
595: _findclose(handle);
596: return(finddata.attrib);
597: #else
598: struct stat st;
599:
600: if(stat(filename, &st)!=0) {
601: errno=ENOENT;
602: return(-1L);
603: }
604:
605: return(st.st_mode);
606: #endif
607: }
608:
609: /****************************************************************************/
610: /* Deletes all files in dir 'path' that match file spec 'spec' */
611: /****************************************************************************/
612: ulong DLLCALL delfiles(char *inpath, char *spec)
613: {
614: char path[MAX_PATH+1];
615: char lastch;
616: uint i,files=0;
617: glob_t g;
618:
619: lastch=*lastchar(inpath);
620: if(!IS_PATH_DELIM(lastch))
621: sprintf(path,"%s%c",inpath,PATH_DELIM);
622: else
623: strcpy(path,inpath);
624: strcat(path,spec);
625: glob(path,0,NULL,&g);
626: for(i=0;i<g.gl_pathc;i++) {
627: if(isdir(g.gl_pathv[i]))
628: continue;
629: CHMOD(g.gl_pathv[i],S_IWRITE); // Incase it's been marked RDONLY
630: if(remove(g.gl_pathv[i])==0)
631: files++;
632: }
633: globfree(&g);
634: return(files);
635: }
636:
637: /****************************************************************************/
638: /* Return free disk space in bytes (up to a maximum of 4GB) */
639: /****************************************************************************/
640: #if defined(_WIN32)
641: typedef BOOL(WINAPI * GetDiskFreeSpaceEx_t)
642: (LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
643:
644: static int bit_num(ulong val)
645: {
646: int i;
647:
648: for(i=31;i>=0;i--)
649: if(val&(1<<i))
650: return(i);
651:
652: return(-1);
653: }
654: #endif
655:
656: /* Unit should be a power-of-2 (e.g. 1024 to report kilobytes) */
657: ulong DLLCALL getfreediskspace(const char* path, ulong unit)
658: {
659: #if defined(_WIN32)
660: char root[16];
661: DWORD TotalNumberOfClusters;
662: DWORD NumberOfFreeClusters;
663: DWORD BytesPerSector;
664: DWORD SectorsPerCluster;
665: ULARGE_INTEGER avail;
666: ULARGE_INTEGER size;
667: static HINSTANCE hK32;
668: GetDiskFreeSpaceEx_t GetDiskFreeSpaceEx;
669:
670: if(hK32 == NULL)
671: hK32 = LoadLibrary("KERNEL32");
672: GetDiskFreeSpaceEx
673: = (GetDiskFreeSpaceEx_t)GetProcAddress(hK32,"GetDiskFreeSpaceExA");
674:
675: if (GetDiskFreeSpaceEx!=NULL) { /* Windows 95-OSR2 or later */
676: if(!GetDiskFreeSpaceEx(
677: path, // pointer to the directory name
678: &avail, // receives the number of bytes on disk avail to the caller
679: &size, // receives the number of bytes on disk
680: NULL)) // receives the free bytes on disk
681: return(0);
682:
683: if(unit>1)
684: avail.QuadPart=Int64ShrlMod32(avail.QuadPart,bit_num(unit));
685:
686: #if defined(_ANONYMOUS_STRUCT)
687: if(avail.HighPart)
688: #else
689: if(avail.u.HighPart)
690: #endif
691: return(0xffffffff); /* 4GB max */
692:
693: #if defined(_ANONYMOUS_STRUCT)
694: return(avail.LowPart);
695: #else
696: return(avail.u.LowPart);
697: #endif
698: }
699:
700: /* Windows 95 (old way), limited to 2GB */
701: sprintf(root,"%.3s",path);
702: if(!GetDiskFreeSpace(
703: root, // pointer to root path
704: &SectorsPerCluster, // pointer to sectors per cluster
705: &BytesPerSector, // pointer to bytes per sector
706: &NumberOfFreeClusters, // pointer to number of free clusters
707: &TotalNumberOfClusters // pointer to total number of clusters
708: ))
709: return(0);
710:
711: if(unit>1)
712: NumberOfFreeClusters/=unit;
713: return(NumberOfFreeClusters*SectorsPerCluster*BytesPerSector);
714:
715:
716: /* statfs is also used under FreeBSD */
717: #elif defined(__GLIBC__) || defined(BSD)
718:
719: struct statfs fs;
720:
721: if (statfs(path, &fs) < 0)
722: return 0;
723:
724: if(unit>1)
725: fs.f_bavail/=unit;
726: return fs.f_bsize * fs.f_bavail;
727:
728: #elif defined(__solaris__)
729:
730: struct statvfs fs;
731:
732: if (statvfs(path, &fs) < 0)
733: return 0;
734:
735: if(unit>1)
736: fs.f_bavail/=unit;
737: return fs.f_bsize * fs.f_bavail;
738:
739: #else
740:
741: fprintf(stderr,"\n*** !Missing getfreediskspace implementation ***\n");
742: return(0);
743:
744: #endif
745: }
746:
747: /****************************************************************************/
748: /* Resolves //, /./, and /../ in a path. Should work indetically to Windows */
749: /****************************************************************************/
750: #if defined(__unix__)
751: char * DLLCALL _fullpath(char *target, const char *path, size_t size) {
752: char *out;
753: char *p;
754:
755: if(target==NULL) {
756: if((target=malloc(MAX_PATH+1))==NULL) {
757: return(NULL);
758: }
759: }
760: out=target;
761: *out=0;
762:
763: if(*path != '/') {
764: p=getcwd(target,size);
765: if(p==NULL || strlen(p)+strlen(path)>=size)
766: return(NULL);
767: out=strrchr(target,'\0');
768: *(out++)='/';
769: *out=0;
770: out--;
771: }
772: strncat(target,path,size-1);
773:
774: /* if(stat(target,&sb))
775: return(NULL);
776: if(sb.st_mode&S_IFDIR)
777: strcat(target,"/"); */
778:
779: for(;*out;out++) {
780: while(*out=='/') {
781: if(*(out+1)=='/')
782: memmove(out,out+1,strlen(out));
783: else if(*(out+1)=='.' && (*(out+2)=='/' || *(out+2)==0))
784: memmove(out,out+2,strlen(out)-1);
785: else if(*(out+1)=='.' && *(out+2)=='.' && (*(out+3)=='/' || *(out+3)==0)) {
786: *out=0;
787: p=strrchr(target,'/');
788: memmove(p,out+3,strlen(out+3)+1);
789: out=p;
790: }
791: else {
792: out++;
793: }
794: }
795: }
796: return(target);
797: }
798: #endif
799:
800: /****************************************************************************/
801: /* Adds a trailing slash/backslash (path delimiter) on path strings */
802: /****************************************************************************/
803: char* DLLCALL backslash(char* path)
804: {
805: char* p;
806:
807: p=lastchar(path);
808:
809: if(*p!='/' && *p!='\\') {
810: *(++p)=PATH_DELIM;
811: *(++p)=0;
812: }
813: return(path);
814: }
815:
816: /****************************************************************************/
817: /* Returns true if the specified filename an aboslute pathname */
818: /****************************************************************************/
819: BOOL DLLCALL isabspath(const char *filename)
820: {
821: char path[MAX_PATH+1];
822:
823: return(stricmp(filename,FULLPATH(path,filename,sizeof(path)))==0);
824: }
825:
826: /****************************************************************************/
827: /* Returns true if the specified filename is a full ("rooted") path */
828: /****************************************************************************/
829: BOOL DLLCALL isfullpath(const char* filename)
830: {
831: return(filename[0]=='/'
832: #ifdef WIN32
833: || filename[0]=='\\' || filename[1]==':'
834: #endif
835: );
836: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.