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