]> andersk Git - splint.git/blob - src/osd.c
8ba1c6045d2bba2bc41246203b566420045a50ee
[splint.git] / src / osd.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 ** 
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 ** 
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** osd.c
26 **
27 ** Provide a system-independent interface to system-dependent
28 ** file operations.
29 */
30
31 /*
32  * Modified by Herbert 04/19/97:
33  * - added conditional 'OS2' to conditional 'MSDOS'
34  * - added include of new header portab.h.
35  * - changed '/' to macro.
36  * - added DOS / OS/2 specific stuff in osd_getPath.
37  * Herbert 06/12/2000:
38  * - added OS/2 specific includes before osd_getPid()
39  * - handle files like in WIN32 for OS/2 in osd_fileExists()
40  * Herbert 02/17/2002:
41  * - added OS/2 support to absolute file names
42  */
43
44 /*@-allmacros*/
45 /*@ignore@*/
46 # include <sys/types.h>
47 # include <sys/stat.h>
48 /* Fix suggested by Lars Rasmussen */
49 # include <errno.h>
50
51 /* POSIX platforms should defined getpid in unistd.h */
52 # if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
53 # include <process.h>
54 # include <direct.h>
55 # define getcwd _getcwd
56 # else
57 # include <unistd.h>
58 # endif
59
60 /*@end@*/
61 /*@=allmacros*/
62 # include "splintMacros.nf"
63 # include "basic.h"
64 # include "osd.h"
65 # include "portab.h"
66
67 /* from stat.h */
68 /*@ignore@*/
69 extern int stat (const char *, /*@out@*/ struct stat *);
70 /*@end@*/
71
72 static bool osd_executableFileExists (char *);
73
74 static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir, 
75                      /*@out@*/ size_t *p_len);
76
77 extern cstring LSLRootName (cstring filespec)
78 {
79   /*@access cstring@*/
80   char *result, *startName, *tail;
81   size_t nameLength;
82
83   llassert (cstring_isDefined (filespec));
84   tail = strrchr (filespec, CONNECTCHAR);
85   startName = (tail == NULL ? filespec : &tail[1]);
86   tail = strrchr (startName, '.');
87   nameLength = (tail == NULL ? strlen (startName) 
88                 : size_fromInt (tail - startName));
89   result = dmalloc (nameLength + 1);
90   strncpy (result, startName, nameLength);
91   result[(int) nameLength] = '\0';
92   return result;
93   /*@noaccess cstring@*/
94 }
95
96 extern /*@observer@*/ cstring
97 osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
98 {
99   /*@access cstring@*/
100   char *ret = osd_getEnvironmentVariable (env);
101
102   if (ret == NULL)
103     {
104       return def;
105     }
106   else
107     {
108       return ret;
109     }
110   /*@noaccess cstring@*/
111 }
112
113
114 /*
115 **++
116 **  FUNCTIONAL DESCRIPTION:
117 **
118 **      This function attempts to locate a file in a search list.  On VMS, it
119 **      just concatinates the path and file names, and then lets RMS do the
120 **      searching.  On Ultrix, it searches for the file on the path.
121 **
122 **  FORMAL PARAMETERS:
123 **
124 **      path:       search path where to look for the file.
125 **      file:       name of file to search for.
126 **      returnPath: if a file is found, this is where the concatenated
127 **                  directory and file name are returned.
128 **
129 **  RETURN VALUE:
130 **
131 **      OSD_FILEFOUND:      the file was found on the search list.
132 **      OSD_FILENOTFOUND    the file was not found.
133 **      OSD_PATHTOOLONG     the concatenated directory and file name are too
134 **                          long.
135 **
136 **  SIDE EFFECTS:
137 **
138 **      None
139 **
140 **  PRECONDITIONS:
141 **
142 **      Requires that parameters, path and file, are valid C strings.
143 **
144 **
145 **--
146 */
147
148 extern /*@observer@*/ cstring osd_getHomeDir ()
149 {
150   /* Would something different be better for windows? */
151   return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
152 }
153
154 filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
155 {
156   return (osd_getPath (context_getLarchPath (), file, returnPath));
157 }
158
159 extern filestatus
160 osd_getPath (cstring path, cstring file, cstring *returnPath)
161 {
162   char *fullPath;
163   char *dirPtr;
164   size_t dirLen;
165   char aPath[MAXPATHLEN];
166   filestatus rVal = OSD_FILENOTFOUND;   /* assume file not found. */
167   
168   /*@access cstring@*/
169   
170   fullPath = path;
171   llassert (cstring_isDefined (file));
172   
173   /* 2002-01-01: make sure returnPath gets defined even when there are errors.
174   **             (fixed splint checking detected this)
175   */
176
177   *returnPath = cstring_undefined;
178
179   if (fullPath == NULL 
180       || 
181 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
182       /* under OS/2 and MSDOS the includePath may be empty, if so, search 
183        * the current directory. */
184       *fullPath == '\0' || 
185       (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
186 # else
187     (*file == CONNECTCHAR)
188 # endif
189       )
190     {
191       /* No path specified. Look for it in the current directory.           */
192       
193       strcpy (&aPath[0], file);
194       
195       if (osd_fileExists (&aPath[0]))
196         {
197           rVal = OSD_FILEFOUND;
198           *returnPath = dmalloc (strlen (&aPath[0]) + 1);
199           strcpy (*returnPath, &aPath[0]);
200         }
201     }
202   else
203     {
204       /* Path specified. Loop through directories in path looking for the */
205       /* first occurrence of the file.                              */
206       
207       while (nextdir (&fullPath, &dirPtr, &dirLen) &&
208              rVal == OSD_FILENOTFOUND)
209         {
210           if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
211             {
212               /* Cat directory and filename, and see if file exists.  */
213               strncpy (&aPath[0], dirPtr, dirLen);
214               strcpy (&aPath[0] + dirLen, "");  /* Null terminate aPath. */
215               strcat (&aPath[0], CONNECTSTR);
216               strcat (&aPath[0], file);
217               
218               if (osd_fileExists (&aPath[0]))
219                 {
220                   rVal = OSD_FILEFOUND;
221                   *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
222                   strcpy (*returnPath, &aPath[0]);
223                 }
224             }
225           else
226             {
227               rVal = OSD_PATHTOOLONG;
228             }
229         }       
230     }
231
232   return rVal;
233   /*@noaccess cstring@*/
234 }
235
236 extern filestatus
237 osd_getExePath (cstring path, cstring file, cstring *returnPath)
238 {
239   char *fullPath;
240   char *dirPtr;
241   size_t dirLen;
242   char aPath[MAXPATHLEN];
243   filestatus rVal = OSD_FILENOTFOUND;   /* assume file not found. */
244   /*@access cstring@*/ 
245
246   *returnPath = cstring_undefined;  
247   fullPath = osd_getEnvironmentVariable (path);
248   
249   if (fullPath == NULL)
250     {
251       /* No path specified. Look for it in the current directory. */
252       llassert (cstring_isDefined (file));
253       strcpy (&aPath[0], file);
254       
255       if (osd_fileExists (&aPath[0]))
256         {
257           rVal = OSD_FILEFOUND;
258           *returnPath = dmalloc (strlen (&aPath[0]) + 1);
259           strcpy (*returnPath, &aPath[0]);
260         }
261     }
262   else
263     {
264      /* 
265      ** Path specified. Loop through directories in path looking
266      ** for the first occurrence of the file.                               
267      */
268
269       while (nextdir (&fullPath, &dirPtr, &dirLen) &&
270              rVal == OSD_FILENOTFOUND)
271         {
272           llassert (cstring_isDefined (file));
273
274           if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
275             {
276               /* Cat directory and filename, and see if file exists.  */
277               strncpy (&aPath[0], dirPtr, dirLen);
278               strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
279               strcat (&aPath[0], CONNECTSTR);
280               strcat (&aPath[0], file);
281
282               if (osd_executableFileExists (&aPath[0]))
283                 {
284                   rVal = OSD_FILEFOUND;
285                   *returnPath = dmalloc (strlen (&aPath[0]) + 1);
286                   strcpy (*returnPath, &aPath[0]);
287                 }
288             }
289           else
290             {
291               rVal = OSD_PATHTOOLONG;
292             }
293         }
294     }
295
296   return rVal;
297   /*@noaccess cstring@*/
298 }
299
300 bool
301 osd_fileExists (cstring filespec)
302 {
303 # ifdef UNIX
304   struct stat buf;
305   return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
306 # else
307 # if defined (WIN32) || defined (OS2)
308   FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
309   
310   if (test != NULL) 
311     {
312       (void) fileTable_closeFile (context_fileTable (),test);
313       return TRUE;
314     } 
315   else
316     { 
317       return FALSE;
318     }
319 # else 
320   return FALSE;
321 # endif
322 # endif
323 }
324
325 # if defined(__IBMC__) && defined(OS2)
326 # define S_IFMT (unsigned short)0xFFFF
327 # endif
328
329 /*
330 ** Works form Win32 at least...
331 */
332
333 # ifndef S_IXUSR
334 /*@-macrounrecog@*/
335 # define S_IXUSR _S_IEXEC
336 /*@=macrounrecog@*/
337 # endif
338
339 bool
340 osd_executableFileExists (/*@unused@*/ char *filespec)
341 {
342 # ifdef UNIX
343   struct stat buf;
344   if (stat (filespec, &buf) == 0)
345     { 
346       /* mask by file type */
347       /*@-unrecog@*/ /* S_IFMT is not defined */
348       if ((buf.st_mode & S_IFMT) != S_IFDIR /*@=unrecog@*/) /* not a directory */
349         {
350           /* as long as it is an executable file */
351 # if defined(__IBMC__) && defined(OS2)
352           int com_or_exe_pos = strlen( filespec) - 4;
353           return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
354             || stricmp( &filespec[com_or_exe_pos], ".com") == 0
355             || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
356             || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
357 # else
358           return (((buf.st_mode & S_IXUSR)
359 # if defined (S_IXGRP) && defined (S_IXOTH)
360                    | (buf.st_mode & S_IXGRP) |
361                    (buf.st_mode & S_IXOTH)
362 # endif
363                    ) != 0);
364 # endif
365         }
366     }
367 # endif
368   return (FALSE);
369
370 }
371
372 /*
373 **++
374 **  FUNCTIONAL DESCRIPTION:
375 **
376 **      Find the next directory from a directory path.
377 **
378 **  FORMAL PARAMETERS:
379 **
380 **      char ** current_dir :
381 **          Points to the current position in the path string.  The first time
382 **          you call this routine, this should point to the first character of
383 **          the path.  On return, this will be updated to point to the
384 **          terminating \0 or : of the first directory found.  You can then pass
385 **          it unchanged for subsequent calls; this routine will correctly skip
386 **          over the :.
387 **
388 **      char ** dir :
389 **          On exit, this will point to the first character of the directory
390 **          that was found.  This will be a pointer directly into the client's
391 **          path string.
392 **
393 **      unsigned int * len :
394 **          On exit, this will contain the length of the directory that was
395 **          found, not counting any terminating \0 or :.  If no directory was
396 **          found, this will be 0.
397 **
398 **  RETURN VALUE:
399 **      TRUE if we found another directory.
400 **      FALSE otherwise.
401 **
402 **  DESIGN:
403 **
404 **      We return a pointer and length, rather than a string, because of a)
405 **      historical reasons; and b) this avoids having to allocate storage.
406 **
407 **
408 **
409 **--
410 */
411
412 static bool
413 nextdir (d_char *current_dir, d_char *dir, size_t *len)
414 {
415   char *tchar;
416
417   if (**current_dir == '\0')
418     {
419       *len = 0;
420       *dir = NULL;
421       return FALSE;
422     }
423
424   *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
425   
426   /* Find next ':' or end of string */
427   for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
428     {
429       ;
430     }
431   
432   *current_dir = tchar;
433   *len = size_fromInt (tchar - *dir);
434   return TRUE;
435 }
436
437 /*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
438 {
439   /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
440 # if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
441   char *val = getenv (cstring_toCharsSafe (var));
442
443   if (val == NULL) 
444     {
445       return cstring_undefined;      
446     } 
447   else 
448     {
449       return cstring_makeLiteralTemp (val);
450     }
451 # else
452   return cstring_undefined;
453 # endif
454 }
455
456 # ifndef NOLCL
457
458 # ifdef WIN32
459 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
460 # endif
461
462 # ifndef system
463 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
464 # endif
465 int osd_system (cstring cmd)
466 {
467   int res;
468     /* system ("printenv"); */
469 # ifdef WIN32
470   (void) _flushall (); 
471 # endif
472
473   res = system (cstring_toCharsSafe (cmd));
474   return res;
475 }
476 # endif
477
478 # ifndef unlink
479 /* This should be defined by unistd.h */
480 /*@-redecl@*/
481 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
482 /*@=redecl@*/
483 # endif
484
485 static s_tempError = FALSE;
486
487 void osd_setTempError (void)
488 {
489   s_tempError = TRUE;
490 }
491
492 int osd_unlink (cstring fname)
493 {
494   int res;
495
496   res = unlink (cstring_toCharsSafe (fname));
497
498   if (res != 0)
499     {
500       if (!s_tempError)
501         {
502           llcontbug (message ("Cannot remove temporary file: %s (%s)",
503                               fname,
504                               cstring_fromChars (strerror (errno))));
505         }
506     }
507   
508   return res;
509 }
510
511 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
512 int
513 # else
514 int /* pid_t */
515 # endif
516 osd_getPid ()
517 {
518 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
519   int pid = _getpid ();
520 # else
521   pid_t pid = getpid ();
522 # endif
523
524   return (int) pid;
525 }
526   
527 cstring osd_fixDefine (cstring x)
528 {
529   /*@access cstring@*/
530   llassert (cstring_isDefined (x));
531 # ifdef UNIX
532   if (strchr (x, '\'') != NULL) {
533     /*
534     ** If there is a single quote, check for <ident>='<string>' and 
535     ** produce <ident>=<string>
536     */
537
538     char *eqs = strchr (x, '=');
539
540     if (eqs != NULL) {
541       if (eqs[1] == '\'') {
542         char *endqu = strrchr (x, '\'');
543
544         if (endqu != NULL) {
545           if (*(endqu - 1) != '\\') {
546             if (*(endqu + 1) == '\0') {
547               cstring res;
548               cstring def;
549
550               *endqu = '\0';
551               def = cstring_fromChars (eqs + 2);
552               eqs[1] = '\0';
553               res = cstring_concat (cstring_fromChars (x), def);
554                       return res;
555             }
556           }
557         }
558       }
559     }
560   } 
561
562 # endif
563
564   return cstring_copy (x);
565   /*@noaccess cstring@*/
566 }
567
568 bool osd_fileIsReadable (cstring f)
569 {
570   FILE *fl = fileTable_openReadFile (context_fileTable (), f);
571
572   if (fl != NULL)
573     {
574       check (fileTable_closeFile (context_fileTable (), fl));
575       return (TRUE);
576     }
577   else
578     {
579       return (FALSE);
580     }
581 }
582
583 bool osd_isConnectChar (char c)
584 {
585   if (c == CONNECTCHAR) 
586     {
587       return TRUE;
588     }
589
590 # ifdef HASALTCONNECTCHAR
591   if (c == ALTCONNECTCHAR)
592     {
593       return TRUE;
594     }
595 # endif
596
597   return FALSE;
598 }
599
600 /*
601 ** Returns true if c2 starts with the same path as c1
602 **
603 ** This is called by context_isSystemDir to determine if a
604 ** directory is on the system path.
605 **
606 ** In unix, this is just a string comparison.  For Win32 and OS2, we need a more
607 ** complex comparison.
608 */
609
610 bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
611 {
612   llassert (cstring_isDefined (prefixpath));
613
614   if (cstring_isEmpty (dirpath)) 
615     {
616       return (cstring_isEmpty (prefixpath));
617     }
618
619 # if defined (WIN32) || defined (OS2)
620
621   /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
622
623   /*
624   ** If one has a drive specification, but the other doesn't, skip it.
625   */
626   
627   if (strchr (dirpath, ':') == NULL
628       && strchr (prefixpath, ':') != NULL)
629     {
630       prefixpath = strchr (prefixpath, ':') + 1;
631     }
632   else 
633     {
634       if (strchr (prefixpath, ':') == NULL
635           && strchr (dirpath, ':') != NULL)
636         {
637           dirpath = strchr (dirpath, ':') + 1;
638         }
639     }
640
641   {
642     int len = size_toInt (strlen (prefixpath));
643     int i = 0;
644     int slen = 0;
645
646     for (i = 0, slen = 0; i < len; i++, slen++)
647       {
648         /* Allow any number of connect characters in any combination:
649          * c:/usr//src\/foo == c:\\usr/src\/foo 
650          * After this we'll be at the last of such a sequence */
651
652         if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
653           {
654             /* Skip one or more connect chars */
655
656             for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
657               {
658                 ; 
659               }
660             
661             for (; osd_isConnectChar (prefixpath[i+1]); ++i)
662               {
663                 ;
664               }
665           }
666         /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
667         else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
668           {
669             return FALSE;
670           }
671
672       }
673   }
674
675   /*@noaccess cstring@*/ 
676
677   return TRUE;
678 # else
679   return (cstring_equalPrefix (dirpath, prefixpath));
680 # endif
681 }
682
683 # if 0
684 /*
685 ** This code provided by Herbert Martin Dietze, to canonicalize path names.
686 */
687
688 char *osd_getcwd (/*@returned@*/ char *str, size_t size)
689
690   return getcwd (str, size);
691 }
692
693 /*@null@*/ /*@observer@*/ char *
694 osd_dirNext (char *str)
695 {
696   char *p1 = strchr (str, '/');
697   char *p2 = strchr (str, '\\');
698
699   if (p1 == NULL)
700     {
701       if (p2 != NULL)
702         {
703           return p2 + 1;
704         }
705       else
706         {
707           return NULL;
708         }
709     }
710   else if (p2 == NULL)
711     {
712       return p1 + 1;
713     }
714   else /* both not null */
715     {
716       return (p1 < p2 ? p1 : p2) + 1;
717     }
718 }
719
720 static void 
721 osd_dirShift (char *str, size_t num) /*@modifies str@*/
722 {
723   int i;
724   
725   assert (num <= strlen (str));
726   
727   for (i = 0; str[i] != '\0'; i++)
728     {
729       str[i] = str[i + num];
730     }
731 }
732
733 bool
734 osd_dirDotdot (char *str)
735 {
736   return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
737 }
738
739 void
740 osd_dirNormalize (char *str)
741 {
742   char *pos1, *pos2;
743
744   for (; osd_isConnectChar (str[0]); str++)
745     {
746     }
747
748   for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
749     {
750     }
751
752   for (pos1 = pos2 = str; 
753        pos1 != NULL; 
754        pos2 = pos1, pos1 = osd_dirNext (pos1))
755     {
756       /* remove redundant `./' entry */
757       while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
758         {
759           osd_dirShift (pos1, 2);
760         }
761
762       /* remove redundant `foo/../' entry */
763       if (osd_dirDotdot (pos1) && pos2 < pos1)
764         {
765           osd_dirShift (pos2, pos1 - pos2 + 1);
766           osd_dirNormalize (str);
767         }
768     }
769 }
770
771 /*@null@*/ char *
772 osd_dirAbsolute (char *str)
773 {
774   char *ret = NULL;
775   size_t size = PATH_MAX * sizeof (*ret);
776   
777   DPRINTF (("Absolute for: %s", str));
778
779 # if defined (WIN32) || defined (OS2) || defined (MSDOS)
780   if (strlen (str) > 1 && str[1] == ':')
781     {
782       /*
783       ** Its a drive letter
784       */
785       
786       ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
787       strcpy (ret, str);
788     }
789   else
790 # endif
791   if (osd_isConnectChar (str[0]))
792     {
793       ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
794       strcpy (ret, str);
795     }
796   else
797     {
798       ret = dmalloc (size);
799       
800       ret = osd_getcwd (ret, size);
801       ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
802
803       if (ret == NULL)
804         {
805           return NULL;
806         }
807
808       strcat (ret, CONNECTSTR);
809       strcat (ret, str);
810     }
811   
812   osd_dirNormalize (ret);
813   return ret;
814 }
815
816 # endif
817
818 /*
819 ** absolute paths
820 **
821 ** This code is adapted from:
822 **
823 ** http://src.openresources.com/debian/src/devel/HTML/S/altgcc_2.7.2.2.orig%20altgcc-2.7.2.2.orig%20protoize.c.html#1297
824 **
825 **
826 **  Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
827 **   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
828 **
829 ** This file is part of GNU CC.
830 **
831 ** GNU CC is free software; you can redistribute it and/or modify
832 ** it under the terms of the GNU General Public License as published by
833 ** the Free Software Foundation; either version 2, or (at your option)
834 ** any later version.
835 **
836 ** GNU CC is distributed in the hope that it will be useful,
837 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
838 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
839 ** GNU General Public License for more details.
840 ** 
841 ** You should have received a copy of the GNU General Public License
842 ** along with GNU CC; see the file COPYING.  If not, write to
843 ** the Free Software Foundation, 59 Temple Place - Suite 330,
844 ** Boston, MA 02111-1307, USA.  
845 */
846
847 /* 
848 ** Return the absolutized filename for the given relative
849 ** filename.  Note that if that filename is already absolute, it may
850 ** still be returned in a modified form because this routine also
851 ** eliminates redundant slashes and single dots and eliminates double
852 ** dots to get a shortest possible filename from the given input
853 ** filename.  The absolutization of relative filenames is made by
854 ** assuming that the given filename is to be taken as relative to
855 ** the first argument (cwd) or to the current directory if cwd is
856 ** NULL.  
857 */
858
859 /* A pointer to the current directory filename (used by abspath).  */
860 static /*@only@*/ cstring osd_cwd = cstring_undefined;
861
862 static void osd_setWorkingDirectory (void)
863 {
864 # if defined (UNIX) || defined (OS2)
865   char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
866   char *cwd = getcwd (buf, MAXPATHLEN);
867
868   llassert (cstring_isUndefined (osd_cwd));
869
870   if (cwd == NULL)
871     {
872       lldiagmsg (message ("Cannot get working directory: %s\n",
873                           lldecodeerror (errno)));
874     }
875   else
876     {
877       osd_cwd = cstring_fromCharsNew (cwd);
878     }
879
880   sfree (buf);
881 # else
882   ; /* Don't know how to do this for non-POSIX platforms */
883 # endif
884 }
885
886 void osd_initMod (void)
887 {
888   osd_setWorkingDirectory ();
889 }
890
891 cstring osd_absolutePath (cstring cwd, cstring filename)
892 {
893 # if defined (UNIX) || defined (OS2)
894   /* Setup the current working directory as needed.  */
895   cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
896   char *abs_buffer;
897   char *endp, *outp, *inp;
898
899   /*@access cstring@*/
900   llassert (cstring_isDefined (cwd2));
901   llassert (cstring_isDefined (filename));
902
903   abs_buffer = (char *) dmalloc (size_fromInt (cstring_length (cwd2) + cstring_length (filename) + 2));
904   endp = abs_buffer;
905   
906   /*
907   ** Copy the  filename (possibly preceded by the current working
908   ** directory name) into the absolutization buffer.  
909   */
910   
911   {
912     const char *src_p;
913
914     if (!osd_isConnectChar (filename[0])
915 # ifdef OS2
916         && !(isalpha (filename[0]) && filename[1] == ':')
917 # endif
918         )
919       {
920         src_p = cwd2;
921
922         while ((*endp++ = *src_p++) != '\0') 
923           {
924             continue;
925           }
926
927         *(endp-1) = CONNECTCHAR;                        /* overwrite null */
928       }
929
930     src_p = filename;
931
932     while ((*endp++ = *src_p++) != '\0')
933       {
934         continue;
935       }
936   }
937   
938   /* Now make a copy of abs_buffer into abs_buffer, shortening the
939      filename (by taking out slashes and dots) as we go.  */
940   
941   outp = inp = abs_buffer;
942   *outp++ = *inp++;             /* copy first slash */
943 #ifdef apollo
944   if (inp[0] == '/')
945     *outp++ = *inp++;           /* copy second slash */
946 #endif
947   for (;;)
948     {
949       if (inp[0] == '\0')
950         {
951           break;
952         }
953       else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
954         {
955           inp++;
956           continue;
957         }
958       else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
959         {
960           if (inp[1] == '\0')
961             {
962               break;
963             }
964           else if (osd_isConnectChar (inp[1]))
965             {
966               inp += 2;
967               continue;
968             }
969           else if ((inp[1] == '.') 
970                    && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
971             {
972               inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
973               outp -= 2;
974         
975               while (outp >= abs_buffer && !osd_isConnectChar (*outp))
976                 {
977                   outp--;
978                 }
979
980               if (outp < abs_buffer)
981                 {
982                   /* Catch cases like /.. where we try to backup to a
983                      point above the absolute root of the logical file
984                      system.  */
985                   
986                   llfatalbug (message ("Invalid file name: %s", filename));
987                 }
988
989               *++outp = '\0';
990               continue;
991             }
992           else
993             {
994               ;
995             }
996         }
997       else
998         {
999           ;
1000         }
1001
1002       *outp++ = *inp++;
1003     }
1004   
1005   /* On exit, make sure that there is a trailing null, and make sure that
1006      the last character of the returned string is *not* a slash.  */
1007   
1008   *outp = '\0';
1009   if (osd_isConnectChar (outp[-1]))
1010     *--outp  = '\0';
1011   
1012   /*@noaccess cstring@*/
1013   return cstring_fromChars (abs_buffer);
1014 # else
1015   DPRINTF (("Here: %s", filename));
1016   return cstring_copy (filename);
1017 # endif
1018 }
1019
1020 /* 
1021 ** Given a filename (and possibly a directory name from which the filename
1022 ** is relative) return a string which is the shortest possible
1023 ** equivalent for the corresponding full (absolutized) filename.  The
1024 ** shortest possible equivalent may be constructed by converting the
1025 ** absolutized filename to be a relative filename (i.e. relative to
1026 ** the actual current working directory).  However if a relative filename
1027 ** is longer, then the full absolute filename is returned.
1028 **
1029 ** KNOWN BUG:   subpart of the original filename is actually a symbolic link.  
1030 **
1031 ** this is really horrible code...surely someone has written a less buggy version of this!
1032 */
1033
1034 cstring osd_outputPath (cstring filename)
1035 {
1036 # if defined (UNIX) || defined (OS2)
1037   char *rel_buffer;
1038   char *rel_buf_p;
1039   cstring cwd_p = osd_cwd;
1040   char *path_p;
1041   int unmatched_slash_count = 0;
1042   size_t filename_len = cstring_length (filename);
1043   
1044   llassertretval (filename_len > 0, filename);
1045
1046   /*@access cstring@*/
1047   path_p = filename;
1048   rel_buf_p = rel_buffer = (char *) dmalloc (filename_len);
1049   *rel_buf_p = '\0';
1050
1051   llassert (cwd_p != NULL);
1052   llassert (path_p != NULL);
1053
1054   while ((*cwd_p != '\0') && (*cwd_p == *path_p))
1055     {
1056       cwd_p++;
1057       path_p++;
1058     }
1059   
1060   if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p)))  /* whole pwd matched */
1061     {
1062       if (*path_p == '\0')             /* input *is* the current path! */
1063         return cstring_makeLiteral (".");
1064       else
1065         {
1066           /*@i324 ! splint didn't report an errors for: return ++path_p; */
1067           return cstring_fromCharsNew (++path_p);
1068         }
1069     }
1070   else
1071     {
1072       /* evans 2002-02-05 This is horrible code, which I've removed.  I couldn't find any
1073       ** test cases that need it, so I hope I'm not breaking anything.
1074       */
1075
1076 # if 0      
1077       if (*path_p != '\0')
1078         {
1079           --cwd_p;
1080           --path_p;
1081           while (!osd_isConnectChar (*cwd_p))         /* backup to last slash */
1082             {
1083               --cwd_p;
1084               --path_p;
1085             }
1086           cwd_p++;
1087           path_p++;
1088           unmatched_slash_count++;
1089         }
1090
1091       /* Find out how many directory levels in cwd were *not* matched.  */
1092       while (*cwd_p != '\0')
1093         {
1094           if (osd_isConnectChar (*cwd_p++))
1095             unmatched_slash_count++;
1096         }
1097       
1098       /* Now we know how long the "short name" will be.
1099          Reject it if longer than the input.  */
1100       if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1101         {
1102           return cstring_copy (filename);
1103         }
1104 # endif
1105       
1106       /* For each of them, put a `../' at the beginning of the short name.  */
1107       while (unmatched_slash_count-- > 0)
1108         {
1109           /* Give up if the result gets to be longer
1110              than the absolute path name.  */
1111           if (rel_buffer + filename_len <= rel_buf_p + 3)
1112             {
1113               sfree (rel_buffer);
1114               return cstring_copy (filename);
1115             }
1116
1117           *rel_buf_p++ = '.';
1118           *rel_buf_p++ = '.';
1119           *rel_buf_p++ = CONNECTCHAR;
1120         }
1121       
1122       /* Then tack on the unmatched part of the desired file's name.  */
1123       do
1124         {
1125           if (rel_buffer + filename_len <= rel_buf_p)
1126             {
1127               cstring_free (rel_buffer);
1128               return cstring_copy (filename);
1129             }
1130         } /*@-usereleased@*/
1131       while ((*rel_buf_p++ = *path_p++) != '\0') ;
1132
1133       /*@=usereleased@*/ /*@i523! shouldn't need these */
1134       --rel_buf_p;
1135
1136       if (osd_isConnectChar (*(rel_buf_p-1)))
1137         *--rel_buf_p = '\0';
1138
1139       return rel_buffer;
1140     }
1141   /*@noaccess cstring@*/
1142 # else
1143   return cstring_copy (filename);
1144 # endif
1145 }
1146
1147 cstring osd_getCurrentDirectory ()
1148 {
1149 # if defined(MSDOS) || defined(OS2)
1150   return cstring_makeLiteralTemp ("");
1151 # else
1152   return cstring_makeLiteralTemp ("./");
1153 # endif
1154 }
1155
1156
1157
This page took 0.113127 seconds and 3 git commands to generate.