1 /* File: filsubs.c
2 * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk)
3 * Copyright (C) J Thierry-Mieg and R Durbin, 1991
4 *-------------------------------------------------------------------
5 * This file is part of the ACEDB genome database package, written by
6 * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
7 * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
8 *
9 * Description:
10 * cross platform file system routines
11 *
12 * Exported functions:
13 * HISTORY:
14 * Last edited: Jan 5 16:36 1999 (fw)
15 * * Dec 8 10:20 1998 (fw): new function filAge to determine time since
16 * last modification of file
17 * * Oct 22 16:17 1998 (edgrif): Replace unsafe strtok with strstr.
18 * * Oct 15 11:47 1998 (fw): include messSysErrorText in some messges
19 * * Sep 30 09:37 1998 (edgrif): Replaced my strdup with acedb strnew.
20 * * Sep 9 14:07 1998 (edgrif): Add filGetFilename routine that will
21 * return the filename given a pathname
22 * (NOT the same as the UNIX basename).
23 * * DON'T KNOW WHO DID THE BELOW..assume Richard Bruskiewich (edgrif)
24 * - fix root path detection for default drives (in WIN32)
25 * * Oct 8 23:34 1996 (rd)
26 * filDirectory() returns a sorted Array of character
27 * strings of the names of files, with specified ending
28 * and spec's, listed in a given directory "dirName";
29 * If !dirName or directory is inaccessible,
30 * the function returns 0
31 * * Jun 6 17:58 1996 (rd)
32 * * Mar 24 02:42 1995 (mieg)
33 * * Feb 13 16:11 1993 (rd): allow "" endName, and call getwd if !*dname
34 * * Sep 14 15:57 1992 (mieg): sorted alphabetically
35 * * Sep 4 13:10 1992 (mieg): fixed NULL used improperly when 0 is meant
36 * * Jul 20 09:35 1992 (aochi): Add directory names to query file chooser
37 * * Jan 11 01:59 1992 (mieg): If file has no ending i suppress the point
38 * * Nov 29 19:15 1991 (mieg): If file had no ending, we were losing the
39 last character in dirDraw()
40 * Created: Fri Nov 29 19:15:34 1991 (mieg)
41 *-------------------------------------------------------------------
42 */
43
44 /* $Id: filsubs.c,v 1.2 2002/11/24 19:27:20 lstein Exp $ */
45
46 #include "regular.h"
47 #include "mytime.h"
48 #include "call.h" /* for callScript (to mail stuff) */
49
50 /********************************************************************/
51
52 #include "mydirent.h"
53
54 #if !defined(WIN32)
55 /* UNIX */
56 #include <sys/file.h>
57 #define HOME_DIR_ENVP "HOME"
58
59 #define ABSOLUTE_PATH(path) *path == SUBDIR_DELIMITER
60
61 #else /* Utility macros for WIN32 only */
62
63 #include <tchar.h>
64 #include <direct.h> /* for getwcd() and _getdrive() */
65
66 /* simple, single letter logical drives assumed here */
67 static const char *DRIVES = "abcdefghijklmnopqrstuvwxyz";
68 #define DRIVE_NO(drv) ((drv)-'a'+1)
69 #define GET_CURRENT_DRIVE *( DRIVES + _getdrive() - 1 )
70
71 #define HOME_DIR_ENVP "HOMEPATH"
72
73 #include <ctype.h> /* for isalpha() */
74 #define ABSOLUTE_PATH(path) \
75 ( isalpha( (int)*path ) ) && \
76 (*(path+1) == DRIVE_DELIMITER) && \
77 (*(path+2) == SUBDIR_DELIMITER)
78 #endif /* WIN32 */
79
80 /********************************************************************/
81
82 static Stack dirPath = 0 ;
83
filAddDir(char * s)84 UTIL_FUNC_DEF void filAddDir (char *s) /* add to dirPath */
85 {
86 char *home ;
87
88 if (!dirPath)
89 dirPath = stackCreate (128) ;
90
91 /* if the user directory is specified */
92 if (*s == '~' &&
93 (home = getenv (HOME_DIR_ENVP))) /* substitute */
94 {
95 #if defined(WIN32) /* in WIN32, need to prefix homepath with home drive*/
96 char *drive;
97 drive = getenv ("HOMEDRIVE") ;
98 pushText(dirPath, drive) ;
99 catText(dirPath, home) ;
100 #else
101 pushText (dirPath, home) ;
102 #endif
103 catText (dirPath, ++s) ;
104 }
105 else
106 pushText (dirPath, s) ;
107
108 catText (dirPath, SUBDIR_DELIMITER_STR) ;
109
110 return;
111 } /* filAddDir */
112
113 /*********************************************/
114
filAddPath(char * cp)115 UTIL_FUNC_DEF void filAddPath (char *cp)
116 {
117 char *cq = cp ;
118
119 while (TRUE)
120 {
121 while (*cq && *cq != PATH_DELIMITER)
122 ++cq ;
123 if (*cq == PATH_DELIMITER)
124 {
125 *cq = 0 ;
126 filAddDir (cp) ;
127 cp = ++cq ;
128 }
129 else
130 {
131 filAddDir (cp) ;
132 break ;
133 }
134 }
135
136 return;
137 } /* filAddPath */
138
139
140 /*****************************************************************************/
141 /* This function returns the filename part of a given path, */
142 /* */
143 /* Given "/some/load/of/directories/filename" returns "filename" */
144 /* */
145 /* The function returns NULL for the following errors: */
146 /* */
147 /* 1) supplying a NULL ptr as the path */
148 /* 2) supplying "" as the path */
149 /* 3) supplying a path that ends in "/" */
150 /* */
151 /* NOTE, this function is _NOT_ the same as the UNIX basename command or the */
152 /* XPG4_UNIX basename() function which do different things. */
153 /* */
154 /* The function makes a copy of the supplied path on which to work, this */
155 /* copy is thrown away each time the function is called. */
156 /* */
157 /*****************************************************************************/
158
filGetFilename(char * path)159 UTIL_FUNC_DEF char *filGetFilename(char *path)
160 {
161 static char *path_copy = NULL ;
162 const char *path_delim = SUBDIR_DELIMITER_STR ;
163 char *result = NULL, *tmp ;
164
165 if (path != NULL)
166 {
167 if (strcmp((path + strlen(path) - 1), path_delim) != 0) /* Last char = "/" ?? */
168 {
169 if (path_copy != NULL) messfree(path_copy) ;
170
171 path_copy = strnew(path, 0) ;
172
173 tmp = path ;
174 while (tmp != NULL)
175 {
176 result = tmp ;
177
178 tmp = strstr(tmp, path_delim) ;
179 if (tmp != NULL) tmp++ ;
180 }
181 }
182 }
183
184 return(result) ;
185 } /* filGetFilename */
186
187
188 /*****************************************************************************/
189 /* This function returns the file-extension part of a given path/filename, */
190 /* */
191 /* Given "/some/load/of/directories/filename.ext" returns "ext" */
192 /* */
193 /* The function returns NULL for the following errors: */
194 /* */
195 /* 1) supplying a NULL ptr as the path */
196 /* 2) supplying a path with no filename */
197 /* */
198 /* The function returns "" for a filename that has no extension */
199 /* */
200 /* The function makes a copy of the supplied path on which to work, this */
201 /* copy is thrown away each time the function is called. */
202 /* */
203 /*****************************************************************************/
filGetExtension(char * path)204 UTIL_FUNC_DEF char *filGetExtension(char *path)
205 {
206 static char *path_copy = NULL ;
207 char *extension = NULL, *cp ;
208
209 if (path == NULL)
210 return NULL;
211
212 if (strlen(path) == 0)
213 return NULL;
214
215 if (path_copy != NULL) messfree(path_copy) ;
216 path_copy = messalloc ((strlen(path)+1) * sizeof(char));
217 strcpy (path_copy, path);
218
219 cp = path_copy + (strlen(path_copy) - 1);
220 while (cp > path_copy &&
221 *cp != SUBDIR_DELIMITER &&
222 *cp != '.')
223 --cp;
224
225 extension = cp+1;
226
227 return(extension) ;
228 } /* filGetExtension */
229
230
231 /**********************************************************************/
232 /* This function takes a directory name and does the following:
233 1. Returns the name if it is "complete"
234 (an absolute path on a given platform)
235 2. On WIN32 platforms, for onto rooted paths lacking a
236 drive specification, returns the directory name prefixed with
237 the default drive letter
238 3. Otherwise, assumes that the directory name resides within the
239 current working directory and thus, returns it prefixes the
240 directory name with the working directory path */
241 /**********************************************************************/
filGetFullPath(char * dir)242 UTIL_FUNC_DEF char *filGetFullPath(char *dir)
243 {
244 static char *path_copy = NULL;
245 char *pwd ;
246 char dirbuf[MAXPATHLEN] ;
247
248 /* Return dir if absolute path already */
249 if (ABSOLUTE_PATH(dir))
250 {
251 if (path_copy)
252 messfree (path_copy);
253 path_copy = (char*) messalloc (strlen(dir) + 1) ;
254 strcpy (path_copy, dir) ;
255 return path_copy ;
256 }
257
258 #if defined(WIN32)
259 /* else if dir is a Win32 rooted path, then add current drive to rooted paths */
260 else if ( *dir == SUBDIR_DELIMITER )
261 {
262 char drive[3] = { GET_CURRENT_DRIVE, DRIVE_DELIMITER, '\0' } ;
263
264 if (path_copy)
265 messfree (path_copy);
266
267 path_copy = (char*) messalloc (strlen(dir) + strlen(drive) + 1) ;
268 strcpy (path_copy, drive) ;
269 strcat (path_copy, dir) ;
270
271 return path_copy ;
272 }
273 #endif
274
275 /* else if I can, then prefix "dir" with working directory path... */
276 else if ((pwd = getwd (dirbuf)))
277 {
278 if (path_copy)
279 messfree (path_copy);
280
281 path_copy = (char*) messalloc (strlen(pwd) + strlen(dir) + 2) ;
282
283 strcpy (path_copy, pwd) ;
284 strcat (path_copy, SUBDIR_DELIMITER_STR) ;
285 strcat (path_copy, dir) ;
286
287 return path_copy ;
288 }
289 else
290 return 0 ; /* signals error that the path was not found */
291 } /* filGetFullPath */
292
293 /*******************************/
294
filCheck(char * name,char * spec)295 static BOOL filCheck (char *name, char *spec)
296 /* allow 'd' as second value of spec for a directory */
297 {
298 char *cp ;
299 BOOL result ;
300 struct stat status ;
301
302 if (!spec) /* so filName returns full file name (for error messages) */
303 return TRUE ;
304 /* directory check */
305 if (spec[1] == 'd' &&
306 (stat (name, &status) || !(status.st_mode & S_IFDIR)))
307 return 0 ;
308
309 switch (*spec)
310 {
311 case 'r':
312 return !(access (name, R_OK)) ;
313 case 'w':
314 case 'a':
315 if (!access (name, W_OK)) /* requires file exists */
316 return TRUE ;
317 /* test directory writable */
318 cp = name + strlen (name) ;
319 while (cp > name)
320 if (*--cp == SUBDIR_DELIMITER) break ;
321 if (cp == name)
322 return !(access (".", W_OK)) ;
323 else
324 { *cp = 0 ;
325 result = !(access (name, W_OK)) ;
326 *cp = SUBDIR_DELIMITER ;
327 return result ;
328 }
329 case 'x':
330 return !(access (name, X_OK)) ;
331 default:
332 messcrash ("Unknown spec %s passed to filName", spec) ;
333 }
334 return FALSE ;
335 }
336
337 /************************************************/
338
filDoName(char * name,char * ending,char * spec,BOOL strict)339 static char *filDoName (char *name, char *ending, char *spec, BOOL strict)
340 {
341 static Stack part = 0, full = 0 ;
342 char *dir, *result ;
343 #if defined(WIN32)
344 char *cp, buf2[2] ;
345 static char driveStr[3] = { 'C', DRIVE_DELIMITER, '\0' },
346 *pDriveStr = driveStr ;
347 #endif
348
349 if (!name)
350 messcrash ("filName received a null name") ;
351
352 if (!part)
353 { part = stackCreate (128) ;
354 full = stackCreate (MAXPATHLEN) ;
355 }
356
357 stackClear (part) ;
358
359 #if defined(WIN32)
360 /* convert '/' => '\\' in path string */
361 cp = name ; buf2[1] = 0 ;
362 while (*cp)
363 {
364 if (*cp == '/')
365 catText (part, "\\") ;
366 else
367 { buf2[0] = *cp; catText (part, buf2) ; }
368 cp++ ;
369 }
370 #else
371 catText (part, name) ;
372 #endif
373 if (ending && *ending)
374 { catText (part, ".") ;
375 catText (part, ending) ;
376 }
377 /* NB filName is reentrant in the sense that it can be called
378 on strings it generates, because they first get copied into
379 part, and then the new name is constructed in full.
380 */
381 if (ABSOLUTE_PATH(name))
382 {
383 stackClear (full) ;
384 catText (full, stackText (part, 0)) ;
385 result = stackText (full, 0) ;
386 if (filCheck (result, spec))
387 return result ;
388 else
389 return 0 ;
390 }
391
392 #if defined(WIN32)
393 /* Check if path name is a root path
394 hence on the default logical drive */
395 if( name[0] == SUBDIR_DELIMITER )
396 {
397 stackClear (full) ;
398 driveStr[0] = GET_CURRENT_DRIVE ;
399 catText (full, pDriveStr ) ;
400 catText (full, stackText (part, 0)) ;
401 result = stackText (full, 0) ;
402 if (filCheck (result, spec))
403 return result ;
404 else
405 return 0 ;
406 }
407 #endif
408
409 if (!dirPath) /* add cwd as default to search */
410 filAddDir (getwd (stackText (full, 0))) ;
411 stackCursor (dirPath, 0) ;
412 while ((dir = stackNextText (dirPath)))
413 {
414 stackClear (full) ;
415 catText (full, dir) ;
416 catText (full, stackText (part, 0)) ;
417 result = stackText (full, 0) ;
418 if (filCheck (result, spec))
419 return result ;
420 if (strict)
421 break ;
422 }
423 return 0 ;
424 } /* filDoName */
425
426 /************************************************************/
427
filName(char * name,char * ending,char * spec)428 UTIL_FUNC_DEF char *filName (char *name, char *ending, char *spec)
429 { return filDoName(name, ending, spec, FALSE) ; }
430
431 /************************************************************/
432
filStrictName(char * name,char * ending,char * spec)433 UTIL_FUNC_DEF char *filStrictName (char *name, char *ending, char *spec)
434 { return filDoName(name, ending, spec, TRUE) ; }
435
436 /************************************************************/
437
filremove(char * name,char * ending)438 UTIL_FUNC_DEF BOOL filremove (char *name, char *ending)
439 /* TRUE if file is deleted. -HJC*/
440 {
441 char *s = filName (name, ending, "r") ;
442 if (s)
443 return unlink(s) ? FALSE : TRUE ;
444 else
445 return FALSE ;
446 } /* filremove */
447
448 /************************************************************/
449
filopen(char * name,char * ending,char * spec)450 UTIL_FUNC_DEF FILE *filopen (char *name, char *ending, char *spec)
451 {
452 char *s = filName (name, ending, spec) ;
453 FILE *result = 0 ;
454
455 if (!s)
456 {
457 if (spec[0] == 'r')
458 messerror ("Failed to open for reading: %s (%s)",
459 filName (name, ending,0),
460 messSysErrorText()) ;
461 else if (spec[0] == 'w')
462 messerror ("Failed to open for writing: %s (%s)",
463 filName (name, ending,0),
464 messSysErrorText()) ;
465 else if (spec[0] == 'a')
466 messerror ("Failed to open for appending: %s (%s)",
467 filName (name, ending,0),
468 messSysErrorText()) ;
469 else
470 messcrash ("filopen() received invalid filespec %s",
471 spec ? spec : "(null)");
472 }
473 else if (!(result = fopen (s, spec)))
474 {
475 messerror ("Failed to open %s (%s)",
476 s, messSysErrorText()) ;
477 }
478 return result ;
479 } /* filopen */
480
481 /********************* temporary file stuff *****************/
482
483 static Associator tmpFiles = 0 ;
484
filtmpopen(char ** nameptr,char * spec)485 UTIL_FUNC_DEF FILE *filtmpopen (char **nameptr, char *spec)
486 {
487 if (!nameptr)
488 messcrash ("filtmpopen requires a non-null nameptr") ;
489
490 if (!strcmp (spec, "r"))
491 return filopen (*nameptr, 0, spec) ;
492
493 #if defined(SUN) || defined(SOLARIS)
494 if (!(*nameptr = tempnam ("/var/tmp", "ACEDB")))
495 #else
496 if (!(*nameptr = tempnam ("/tmp", "ACEDB")))
497 #endif
498 {
499 messerror ("failed to create temporary file (%s)",
500 messSysErrorText()) ;
501 return 0 ;
502 }
503 if (!tmpFiles)
504 tmpFiles = assCreate () ;
505 assInsert (tmpFiles, *nameptr, *nameptr) ;
506
507 return filopen (*nameptr, 0, spec) ;
508 } /* filtmpopen */
509
510 /************************************************************/
511
filtmpremove(char * name)512 UTIL_FUNC_DEF BOOL filtmpremove (char *name) /* delete and free() */
513 { BOOL result = filremove (name, 0) ;
514
515 free (name) ; /* NB free since allocated by tempnam */
516 assRemove (tmpFiles, name) ;
517 return result ;
518 }
519
520 /************************************************************/
521
filtmpcleanup(void)522 UTIL_FUNC_DEF void filtmpcleanup (void)
523 { char *name = 0 ;
524
525 if (tmpFiles)
526 while (assNext (tmpFiles, &name, 0))
527 { filremove (name, 0) ;
528 free (name) ;
529 }
530 }
531
532 /************* filqueryopen() ****************/
533
534 static QueryOpenRoutine queryOpenFunc = 0 ;
535
filQueryOpenRegister(QueryOpenRoutine new)536 UTIL_FUNC_DEF QueryOpenRoutine filQueryOpenRegister (QueryOpenRoutine new)
537 { QueryOpenRoutine old = queryOpenFunc ; queryOpenFunc = new ; return old ; }
538
filqueryopen(char * dname,char * fname,char * end,char * spec,char * title)539 UTIL_FUNC_DEF FILE *filqueryopen (char *dname, char *fname, char *end, char *spec, char *title)
540 {
541 Stack s ;
542 FILE* fil = 0 ;
543 int i ;
544 /* use registered routine if available */
545 if (queryOpenFunc)
546 return (*queryOpenFunc)(dname, fname, end, spec, title) ;
547
548 /* otherwise do here and use messprompt() */
549 s = stackCreate(50);
550
551 if (dname && *dname)
552 { pushText(s, dname) ; catText(s,"/") ; }
553 if (fname)
554 catText(s,fname) ;
555 if (end && *end)
556 { catText(s,".") ; catText(s,end) ; }
557
558 lao:
559 if (!messPrompt("File name please", stackText(s,0), "w"))
560 { stackDestroy(s) ;
561 return 0 ;
562 }
563 i = stackMark(s) ;
564 pushText(s, freepath()) ; /* freepath needed by WIN32 */
565 if (spec[0] == 'w' &&
566 (fil = fopen (stackText(s,i), "r")))
567 { if ( fil != stdin && fil != stdout && fil != stderr)
568 fclose (fil) ;
569 fil = 0 ;
570 if (messQuery (messprintf ("Overwrite %s?",
571 stackText(s,i))))
572 {
573 if ((fil = fopen (stackText(s,i), spec)))
574 goto bravo ;
575 else
576 messout ("Sorry, can't open file %s for writing",
577 stackText (s,i)) ;
578 }
579 goto lao ;
580 }
581 else if (!(fil = fopen (stackText(s,i), spec)))
582 messout ("Sorry, can't open file %s",
583 stackText(s,i)) ;
584 bravo:
585 stackDestroy(s) ;
586 return fil ;
587 } /* filqueryopen */
588
589 /*********************************************/
590
591 static Associator mailFile = 0, mailAddress = 0 ;
592
filclose(FILE * fil)593 UTIL_FUNC_DEF void filclose (FILE *fil)
594 {
595 char *address ;
596 char *filename ;
597
598 if (!fil || fil == stdin || fil == stdout || fil == stderr)
599 return ;
600 fclose (fil) ;
601 if (mailFile && assFind (mailFile, fil, &filename))
602 { if (assFind (mailAddress, fil, &address))
603 callScript ("mail", messprintf ("%s %s", address, filename)) ;
604 else
605 messerror ("Have lost the address for mailfile %s", filename) ;
606 assRemove (mailFile, fil) ;
607 assRemove (mailAddress, fil) ;
608 unlink (filename) ;
609 free (filename) ;
610 }
611 } /* filclose */
612
613 /***********************************/
614
filmail(char * address)615 UTIL_FUNC_DEF FILE *filmail (char *address) /* requires filclose() */
616 {
617 char *filename ;
618 FILE *fil ;
619
620 if (!mailFile)
621 { mailFile = assCreate () ;
622 mailAddress = assCreate () ;
623 }
624 if (!(fil = filtmpopen (&filename, "w")))
625 { messout ("failed to open temporary mail file %s", filename) ;
626 return 0 ;
627 }
628 assInsert (mailFile, fil, filename) ;
629 assInsert (mailAddress, fil, address) ;
630 return fil ;
631 } /* filmail */
632
633 /******************* directory stuff *************************/
634
dirOrder(void * a,void * b)635 static int dirOrder(void *a, void *b)
636 {
637 char *cp1 = *(char **)a, *cp2 = *(char**)b;
638 return strcmp(cp1, cp2) ;
639 } /* dirOrder */
640
641 /* returns an Array of strings representing the filename in the
642 given directory according to the spec. "r" will list all files,
643 and "rd" will list all directories.
644 The behaviour of the "w" spec is undefined.
645 The array has to be destroyed using filDirectoryDestroy,
646 because the memory of the strings needs to be reclaimed as well. */
647
filDirectoryCreate(char * dirName,char * ending,char * spec)648 UTIL_FUNC_DEF Array filDirectoryCreate (char *dirName,
649 char *ending,
650 char *spec)
651 {
652 Array a ;
653 #if !defined(WIN32) && !defined(DARWIN)
654 DIR *dirp ;
655 char *dName, *dName_copy, entryPathName[MAXPATHLEN], *leaf ;
656 int dLen, endLen ;
657 MYDIRENT *dent ;
658
659 if (!dirName || !(dirp = opendir (dirName)))
660 return 0 ;
661
662 if (ending)
663 endLen = strlen (ending) ;
664 else
665 endLen = 0 ;
666
667 strcpy (entryPathName, dirName) ;
668 strcat (entryPathName, "/") ;
669 leaf = entryPathName + strlen(dirName) + 1 ;
670
671 a = arrayCreate (16, char*) ;
672 while ((dent = readdir (dirp)))
673 { dName = dent->d_name ;
674 dLen = strlen (dName) ;
675 if (endLen && (dLen <= endLen ||
676 dName[dLen-endLen-1] != '.' ||
677 strcmp (&dName[dLen-endLen],ending)))
678 continue ;
679
680 strcpy (leaf, dName) ;
681 if (!filCheck (entryPathName, spec))
682 continue ;
683
684 if (ending && dName[dLen - endLen - 1] == '.') /* remove ending */
685 dName[dLen - endLen - 1] = 0 ;
686
687 /* the memory of these strings is freed my
688 the messfree()'s in filDirectoryDestroy() */
689 dName_copy = messalloc(strlen(dName)+1) ;
690 strcpy (dName_copy, dName);
691 array(a, arrayMax(a), char*) = dName_copy;
692 }
693
694 closedir (dirp) ;
695
696 /************* reorder ********************/
697
698 arraySort(a, dirOrder) ;
699 return a ;
700 #else /* defined(WIN32) */
701 return 0 ;
702 #endif /* defined(WIN32) */
703 } /* filDirectoryCreate */
704
705 /*************************************************************/
706
filDirectoryDestroy(Array filDirArray)707 UTIL_FUNC_DEF void filDirectoryDestroy (Array filDirArray)
708 {
709 #ifndef WIN32
710 int i;
711 char *cp;
712
713 for (i = 0; i < arrayMax(filDirArray); ++i)
714 {
715 cp = arr(filDirArray, i, char*);
716
717 messfree (cp);
718 }
719 arrayDestroy (filDirArray);
720 #endif /* !WIN32 */
721 return;
722 } /* filDirectoryDestroy */
723
724 /************************************************************/
725 /* determines the age of a file, according to its last modification date.
726
727 returns TRUE if the age could determined and the int-pointers
728 (if non-NULL will be filled with the numbers).
729
730 returns FALSE if the file doesn't exist, is not readable,
731 or the age could not be detrmined. */
732 /************************************************************/
filAge(char * name,char * end,int * diffYears,int * diffMonths,int * diffDays,int * diffHours,int * diffMins,int * diffSecs)733 BOOL filAge (char *name, char *end,
734 int *diffYears, int *diffMonths, int *diffDays,
735 int *diffHours, int *diffMins, int *diffSecs)
736 {
737 struct stat status;
738 mytime_t time_now, time_modified;
739 char time_modified_str[25];
740
741 /* get the last-modification time of the file,
742 we parse the time into two acedb-style time structs
743 in order to compare them using the timediff functions */
744
745 if (!(filName (name, end, "r")))
746 return FALSE;
747
748 if (stat (filName (name, end, "r"), &status) == -1)
749 return FALSE;
750
751 {
752 time_t t = status.st_mtime;
753 struct tm *ts;
754
755 /* convert the time_t time into a tm-struct time */
756 ts = localtime(&t);
757
758 /* get a string with that time in it */
759 strftime (time_modified_str, 25, "%Y-%m-%d_%H:%M:%S", ts) ;
760
761 time_now = timeNow();
762 time_modified = timeParse(time_modified_str);
763
764 if (diffYears)
765 timeDiffYears (time_modified, time_now, diffYears);
766
767 if (diffMonths)
768 timeDiffMonths (time_modified, time_now, diffMonths);
769
770 if (diffDays)
771 timeDiffDays (time_modified, time_now, diffDays);
772
773 if (diffHours)
774 timeDiffHours (time_modified, time_now, diffHours);
775
776 if (diffMins)
777 timeDiffMins (time_modified, time_now, diffMins);
778
779 if (diffSecs)
780 timeDiffSecs (time_modified, time_now, diffSecs);
781 }
782 return TRUE;
783 } /* filAge */
784
785
786
787 /************************************************************/
788 /********** Some WIN32-specific filsub-like code ************/
789 /************************************************************/
790
791 #if defined(WIN32)
792
793 /************************************************************
794 * Converts MSDOS-like pathnames to POSIX-like ones. *
795 * Warning: This function is not reentrant, to avoid *
796 * the complexities of heap memory allocation and release *
797 ************************************************************/
DosToPosix(char * path)798 UTIL_FUNC_DEF char *DosToPosix(char *path)
799 {
800 static char newFilName[MAXPATHLEN] ;
801 char cwdpath[MAXPATHLEN], *cwd ;
802 int i , drive ;
803
804 if( !path || !*path ) return NULL ;
805
806 /* POSIX with drive letters starts with "//" */
807 newFilName[0] = SUBDIR_DELIMITER ;
808 newFilName[1] = SUBDIR_DELIMITER ;
809
810 ReScan:
811 i = 2 ;
812 /* Drive letter as "A:\" format converted to "A/" format */
813 if( strlen(path) >= 2 &&
814 (isalpha( (int)*path ) ) &&
815 (*(path+1) == DRIVE_DELIMITER) )
816 {
817 newFilName[i++] = drive = tolower(*path) ;
818 path += 2 ; /* skip over drive letter... */
819 /* If a root delimiter is present, then path from root (skip delimiter) */
820 if( *path == SUBDIR_DELIMITER )
821 path++ ;
822 else /* else, a relative path on specified drive (append to current directory) */
823 { /* If a non-NULL current working directory on specified drive is found */
824 if( (cwd = _getdcwd(DRIVE_NO(drive),cwdpath,MAXPATHLEN - 2)) != NULL )
825 { /* Then append relative path to current working directory*/
826 if( strlen(cwd)+strlen(path)-1 > MAXPATHLEN )
827 messcrash("DosToPosix(): Path buffer overflow?") ;
828 /* If current working directory is not just a root directory pathname*/
829 if( *(cwd+3) ) /* i.e. non-null fourth character?*/
830 strcat(cwd, SUBDIR_DELIMITER_STR) ; /* then tack on a SUBDIR_DELIMITER*/
831 strcat(cwd, path) ;
832 path = cwd ; /* Reset path to new total path*/
833 goto ReScan ; /* Need to rescan because cwd is of DOS format?*/
834 } /* else, assume path from root*/
835 }
836 }
837 else
838 if( *path == SUBDIR_DELIMITER /* If root directory specified only, with no drive letter? */
839 && *path++ /* always TRUE thus skips over delimiter... */ )
840 newFilName[i++] = GET_CURRENT_DRIVE ; /* Then assume current drive at root directory*/
841
842 else { /* Else, no drive letter, no root delimiter => relative path not at root */
843 if( (cwd = getwd(cwdpath)) != NULL ) /* If a non-NULL current working */
844 { /* directory on default drive is found */
845 if( strlen(cwd)+strlen(path)-1 > MAXPATHLEN ) /* Append relative path to cwd */
846 messcrash("DosToPosix(): Path buffer overflow?") ;
847
848 if( *(cwd+3) ) /* If cwd is not just a root directory */
849 strcat(cwd, SUBDIR_DELIMITER_STR) ; /* then tack on a SUBDIR_DELIMITER */
850 strcat(cwd, path) ;
851 path = cwd ; /* Reset path to new total path*/
852 goto ReScan ; /* Need to rescan because cwd is of DOS format?*/
853 }
854 else /* just use the current drive*/
855 newFilName[i++] = GET_CURRENT_DRIVE ;
856 }
857 newFilName[i++] = SUBDIR_DELIMITER ;
858
859 while(*path) /* Until '\0' encountered */
860 {
861 /* Path delimiter '\' format */
862 if( (*path == SUBDIR_DELIMITER) )
863 newFilName[i++] = SUBDIR_DELIMITER ; /* replace ...*/
864 else
865 newFilName[i++] = *path ; /* else, just copy letter */
866 ++path ; /* ... then skip over */
867 }
868 newFilName[i] = '\0' ;
869 return newFilName ;
870 }
871
872 #endif /* #defined(WIN32) */
873
874 /*************** end of file ****************/
875