]> andersk Git - splint.git/blob - src/osd.c
da780fc69f690c0112ffa65952fe9f6cb5752bab
[splint.git] / src / osd.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 # ifdef WIN32
457 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
458 # endif
459
460 # ifndef system
461 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
462 # endif
463 int osd_system (cstring cmd)
464 {
465   int res;
466     /* system ("printenv"); */
467 # ifdef WIN32
468   (void) _flushall (); 
469 # endif
470
471   res = system (cstring_toCharsSafe (cmd));
472   return res;
473 }
474
475 # ifndef unlink
476 /* This should be defined by unistd.h */
477 /*@-redecl@*/
478 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
479 /*@=redecl@*/
480 # endif
481
482 static bool s_tempError = FALSE;
483
484 void osd_setTempError (void)
485 {
486   s_tempError = TRUE;
487 }
488
489 int osd_unlink (cstring fname)
490 {
491   int res;
492
493   res = unlink (cstring_toCharsSafe (fname));
494
495   if (res != 0)
496     {
497       if (!s_tempError)
498         {
499           llcontbug (message ("Cannot remove temporary file: %s (%s)",
500                               fname,
501                               cstring_fromChars (strerror (errno))));
502         }
503     }
504   
505   return res;
506 }
507
508 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
509 int
510 # else
511 int /* pid_t */
512 # endif
513 osd_getPid ()
514 {
515 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
516   int pid = _getpid ();
517 # else
518   pid_t pid = getpid ();
519 # endif
520
521   return (int) pid;
522 }
523   
524 cstring osd_fixDefine (cstring x)
525 {
526   /*@access cstring@*/
527   llassert (cstring_isDefined (x));
528 # ifdef UNIX
529   if (strchr (x, '\'') != NULL) {
530     /*
531     ** If there is a single quote, check for <ident>='<string>' and 
532     ** produce <ident>=<string>
533     */
534
535     char *eqs = strchr (x, '=');
536
537     if (eqs != NULL) {
538       if (eqs[1] == '\'') {
539         char *endqu = strrchr (x, '\'');
540
541         if (endqu != NULL) {
542           if (*(endqu - 1) != '\\') {
543             if (*(endqu + 1) == '\0') {
544               cstring res;
545               cstring def;
546
547               *endqu = '\0';
548               def = cstring_fromChars (eqs + 2);
549               eqs[1] = '\0';
550               res = cstring_concat (cstring_fromChars (x), def);
551                       return res;
552             }
553           }
554         }
555       }
556     }
557   } 
558
559 # endif
560
561   return cstring_copy (x);
562   /*@noaccess cstring@*/
563 }
564
565 bool osd_fileIsReadable (cstring f)
566 {
567   FILE *fl = fileTable_openReadFile (context_fileTable (), f);
568
569   if (fl != NULL)
570     {
571       check (fileTable_closeFile (context_fileTable (), fl));
572       return (TRUE);
573     }
574   else
575     {
576       return (FALSE);
577     }
578 }
579
580 bool osd_isConnectChar (char c)
581 {
582   if (c == CONNECTCHAR) 
583     {
584       return TRUE;
585     }
586
587 # ifdef HASALTCONNECTCHAR
588   if (c == ALTCONNECTCHAR)
589     {
590       return TRUE;
591     }
592 # endif
593
594   return FALSE;
595 }
596
597 /*
598 ** Returns true if c2 starts with the same path as c1
599 **
600 ** This is called by context_isSystemDir to determine if a
601 ** directory is on the system path.
602 **
603 ** In unix, this is just a string comparison.  For Win32 and OS2, we need a more
604 ** complex comparison.
605 */
606
607 bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
608 {
609   llassert (cstring_isDefined (prefixpath));
610
611   if (cstring_isEmpty (dirpath)) 
612     {
613       return (cstring_isEmpty (prefixpath));
614     }
615
616 # if defined (WIN32) || defined (OS2)
617
618   /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
619
620   /*
621   ** If one has a drive specification, but the other doesn't, skip it.
622   */
623   
624   if (strchr (dirpath, ':') == NULL
625       && strchr (prefixpath, ':') != NULL)
626     {
627       prefixpath = strchr (prefixpath, ':') + 1;
628     }
629   else 
630     {
631       if (strchr (prefixpath, ':') == NULL
632           && strchr (dirpath, ':') != NULL)
633         {
634           dirpath = strchr (dirpath, ':') + 1;
635         }
636     }
637
638   {
639     int len = size_toInt (strlen (prefixpath));
640     int i = 0;
641     int slen = 0;
642
643     for (i = 0, slen = 0; i < len; i++, slen++)
644       {
645         /* Allow any number of connect characters in any combination:
646          * c:/usr//src\/foo == c:\\usr/src\/foo 
647          * After this we'll be at the last of such a sequence */
648
649         if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
650           {
651             /* Skip one or more connect chars */
652
653             for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
654               {
655                 ; 
656               }
657             
658             for (; osd_isConnectChar (prefixpath[i+1]); ++i)
659               {
660                 ;
661               }
662           }
663         /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
664         else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
665           {
666             return FALSE;
667           }
668
669       }
670   }
671
672   /*@noaccess cstring@*/ 
673
674   return TRUE;
675 # else
676   return (cstring_equalPrefix (dirpath, prefixpath));
677 # endif
678 }
679
680 # if 0
681 /*
682 ** This code provided by Herbert Martin Dietze, to canonicalize path names.
683 */
684
685 char *osd_getcwd (/*@returned@*/ char *str, size_t size)
686
687   return getcwd (str, size);
688 }
689
690 /*@null@*/ /*@observer@*/ char *
691 osd_dirNext (char *str)
692 {
693   char *p1 = strchr (str, '/');
694   char *p2 = strchr (str, '\\');
695
696   if (p1 == NULL)
697     {
698       if (p2 != NULL)
699         {
700           return p2 + 1;
701         }
702       else
703         {
704           return NULL;
705         }
706     }
707   else if (p2 == NULL)
708     {
709       return p1 + 1;
710     }
711   else /* both not null */
712     {
713       return (p1 < p2 ? p1 : p2) + 1;
714     }
715 }
716
717 static void 
718 osd_dirShift (char *str, size_t num) /*@modifies str@*/
719 {
720   int i;
721   
722   assert (num <= strlen (str));
723   
724   for (i = 0; str[i] != '\0'; i++)
725     {
726       str[i] = str[i + num];
727     }
728 }
729
730 bool
731 osd_dirDotdot (char *str)
732 {
733   return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
734 }
735
736 void
737 osd_dirNormalize (char *str)
738 {
739   char *pos1, *pos2;
740
741   for (; osd_isConnectChar (str[0]); str++)
742     {
743     }
744
745   for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
746     {
747     }
748
749   for (pos1 = pos2 = str; 
750        pos1 != NULL; 
751        pos2 = pos1, pos1 = osd_dirNext (pos1))
752     {
753       /* remove redundant `./' entry */
754       while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
755         {
756           osd_dirShift (pos1, 2);
757         }
758
759       /* remove redundant `foo/../' entry */
760       if (osd_dirDotdot (pos1) && pos2 < pos1)
761         {
762           osd_dirShift (pos2, pos1 - pos2 + 1);
763           osd_dirNormalize (str);
764         }
765     }
766 }
767
768 /*@null@*/ char *
769 osd_dirAbsolute (char *str)
770 {
771   char *ret = NULL;
772   size_t size = PATH_MAX * sizeof (*ret);
773   
774   DPRINTF (("Absolute for: %s", str));
775
776 # if defined (WIN32) || defined (OS2) || defined (MSDOS)
777   if (strlen (str) > 1 && str[1] == ':')
778     {
779       /*
780       ** Its a drive letter
781       */
782       
783       ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
784       strcpy (ret, str);
785     }
786   else
787 # endif
788   if (osd_isConnectChar (str[0]))
789     {
790       ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
791       strcpy (ret, str);
792     }
793   else
794     {
795       ret = dmalloc (size);
796       
797       ret = osd_getcwd (ret, size);
798       ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
799
800       if (ret == NULL)
801         {
802           return NULL;
803         }
804
805       strcat (ret, CONNECTSTR);
806       strcat (ret, str);
807     }
808   
809   osd_dirNormalize (ret);
810   return ret;
811 }
812
813 # endif
814
815 /*
816 ** absolute paths
817 **
818 ** This code is adapted from:
819 **
820 ** 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
821 **
822 **
823 **  Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
824 **   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
825 **
826 ** This file is part of GNU CC.
827 **
828 ** GNU CC is free software; you can redistribute it and/or modify
829 ** it under the terms of the GNU General Public License as published by
830 ** the Free Software Foundation; either version 2, or (at your option)
831 ** any later version.
832 **
833 ** GNU CC is distributed in the hope that it will be useful,
834 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
835 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
836 ** GNU General Public License for more details.
837 ** 
838 ** You should have received a copy of the GNU General Public License
839 ** along with GNU CC; see the file COPYING.  If not, write to
840 ** the Free Software Foundation, 59 Temple Place - Suite 330,
841 ** Boston, MA 02111-1307, USA.  
842 */
843
844 /* 
845 ** Return the absolutized filename for the given relative
846 ** filename.  Note that if that filename is already absolute, it may
847 ** still be returned in a modified form because this routine also
848 ** eliminates redundant slashes and single dots and eliminates double
849 ** dots to get a shortest possible filename from the given input
850 ** filename.  The absolutization of relative filenames is made by
851 ** assuming that the given filename is to be taken as relative to
852 ** the first argument (cwd) or to the current directory if cwd is
853 ** NULL.  
854 */
855
856 /* A pointer to the current directory filename (used by abspath).  */
857 static /*@only@*/ cstring osd_cwd = cstring_undefined;
858
859 static void osd_setWorkingDirectory (void)
860 {
861 # if defined (UNIX) || defined (OS2)
862   char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
863   char *cwd = getcwd (buf, MAXPATHLEN);
864
865   llassert (cstring_isUndefined (osd_cwd));
866
867   if (cwd == NULL)
868     {
869       lldiagmsg (message ("Cannot get working directory: %s\n",
870                           lldecodeerror (errno)));
871       osd_cwd = cstring_makeLiteral ("<missing directory>");
872     }
873   else
874     {
875       osd_cwd = cstring_fromCharsNew (cwd);
876     }
877
878   sfree (buf);
879 # else
880   ; /* Don't know how to do this for non-POSIX platforms */
881 # endif
882 }
883
884 void osd_initMod (void)
885 {
886   osd_setWorkingDirectory ();
887 }
888
889 void osd_destroyMod (void)
890 {
891   cstring_free (osd_cwd);
892   osd_cwd = cstring_undefined;
893 }
894
895 cstring osd_absolutePath (cstring cwd, cstring filename)
896 {
897 # if defined (UNIX) || defined (OS2)
898   /* Setup the current working directory as needed.  */
899   cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
900   char *abs_buffer;
901   char *endp, *outp, *inp;
902
903   /*@access cstring@*/
904   llassert (cstring_isDefined (cwd2));
905   llassert (cstring_isDefined (filename));
906
907   abs_buffer = (char *) dmalloc (cstring_length (cwd2) + cstring_length (filename) + 2);
908   endp = abs_buffer;
909   
910   /*
911   ** Copy the  filename (possibly preceded by the current working
912   ** directory name) into the absolutization buffer.  
913   */
914   
915   {
916     const char *src_p;
917
918     if (!osd_isConnectChar (filename[0])
919 # ifdef OS2
920         && !(isalpha (filename[0]) && filename[1] == ':')
921 # endif
922         )
923       {
924         src_p = cwd2;
925
926         while ((*endp++ = *src_p++) != '\0') 
927           {
928             continue;
929           }
930
931         *(endp-1) = CONNECTCHAR;                        /* overwrite null */
932       }
933
934     src_p = filename;
935
936     while ((*endp++ = *src_p++) != '\0')
937       {
938         continue;
939       }
940   }
941   
942   /* Now make a copy of abs_buffer into abs_buffer, shortening the
943      filename (by taking out slashes and dots) as we go.  */
944   
945   outp = inp = abs_buffer;
946   *outp++ = *inp++;             /* copy first slash */
947 #ifdef apollo
948   if (inp[0] == '/')
949     *outp++ = *inp++;           /* copy second slash */
950 #endif
951   for (;;)
952     {
953       if (inp[0] == '\0')
954         {
955           break;
956         }
957       else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
958         {
959           inp++;
960           continue;
961         }
962       else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
963         {
964           if (inp[1] == '\0')
965             {
966               break;
967             }
968           else if (osd_isConnectChar (inp[1]))
969             {
970               inp += 2;
971               continue;
972             }
973           else if ((inp[1] == '.') 
974                    && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
975             {
976               inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
977               outp -= 2;
978         
979               while (outp >= abs_buffer && !osd_isConnectChar (*outp))
980                 {
981                   outp--;
982                 }
983
984               if (outp < abs_buffer)
985                 {
986                   /* Catch cases like /.. where we try to backup to a
987                      point above the absolute root of the logical file
988                      system.  */
989                   
990                   llfatalbug (message ("Invalid file name: %s", filename));
991                 }
992
993               *++outp = '\0';
994               continue;
995             }
996           else
997             {
998               ;
999             }
1000         }
1001       else
1002         {
1003           ;
1004         }
1005
1006       *outp++ = *inp++;
1007     }
1008   
1009   /* On exit, make sure that there is a trailing null, and make sure that
1010      the last character of the returned string is *not* a slash.  */
1011   
1012   *outp = '\0';
1013   if (osd_isConnectChar (outp[-1]))
1014     *--outp  = '\0';
1015   
1016   /*@noaccess cstring@*/
1017   return cstring_fromChars (abs_buffer);
1018 # else
1019   DPRINTF (("Here: %s", filename));
1020   return cstring_copy (filename);
1021 # endif
1022 }
1023
1024 /* 
1025 ** Given a filename (and possibly a directory name from which the filename
1026 ** is relative) return a string which is the shortest possible
1027 ** equivalent for the corresponding full (absolutized) filename.  The
1028 ** shortest possible equivalent may be constructed by converting the
1029 ** absolutized filename to be a relative filename (i.e. relative to
1030 ** the actual current working directory).  However if a relative filename
1031 ** is longer, then the full absolute filename is returned.
1032 **
1033 ** KNOWN BUG:   subpart of the original filename is actually a symbolic link.  
1034 **
1035 ** this is really horrible code...surely someone has written a less buggy version of this!
1036 */
1037
1038 cstring osd_outputPath (cstring filename)
1039 {
1040 # if defined (UNIX) || defined (OS2)
1041   char *rel_buffer;
1042   char *rel_buf_p;
1043   cstring cwd_p = osd_cwd;
1044   char *path_p;
1045   int unmatched_slash_count = 0;
1046   size_t filename_len = cstring_length (filename);
1047   
1048   llassertretval (filename_len > 0, filename);
1049
1050   /*@access cstring@*/
1051   path_p = filename;
1052   rel_buffer = (char *) dmalloc (filename_len);
1053   rel_buf_p = rel_buffer;
1054   *rel_buf_p = '\0';
1055
1056   if (cwd_p == NULL) 
1057     {
1058       /* Need to prevent recursive assertion failures */
1059       return cstring_copy (filename);
1060     }
1061
1062   llassert (cwd_p != NULL);
1063   llassert (path_p != NULL);
1064
1065   while ((*cwd_p != '\0') && (*cwd_p == *path_p))
1066     {
1067       cwd_p++;
1068       path_p++;
1069     }
1070   
1071   if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p)))  /* whole pwd matched */
1072     {
1073       if (*path_p == '\0')             /* input *is* the current path! */
1074         {
1075           cstring_free (rel_buffer);
1076           return cstring_makeLiteral (".");
1077         }
1078       else
1079         {
1080           cstring_free (rel_buffer);
1081           return cstring_fromCharsNew (path_p + 1);
1082         }
1083     }
1084   else
1085     {
1086
1087       /* drl   2002-10/14 I had to put this code back*/
1088       /* the case that needs it is when splint is given an absolute path name of a file outside of the current directory and the subdirectories below the current directory. e.g. cd /home/; splint /tmp/prog.c
1089        */
1090       
1091       /* evans 2002-02-05 This is horrible code, which I've removed.  I couldn't find any
1092       ** test cases that need it, so I hope I'm not breaking anything.
1093       */
1094       /*#if 0*/
1095
1096       if (*path_p != '\0')
1097         {
1098           --cwd_p;
1099           --path_p;
1100
1101           while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */
1102             {
1103               --cwd_p;
1104               --path_p;
1105             }
1106           cwd_p++;
1107           path_p++;
1108           unmatched_slash_count++;
1109         }
1110
1111       /* Find out how many directory levels in cwd were *not* matched.  */
1112       while (*cwd_p != '\0')
1113         {
1114           if (osd_isConnectChar (*cwd_p++))
1115             unmatched_slash_count++;
1116         }
1117       
1118       /* Now we know how long the "short name" will be.
1119          Reject it if longer than the input.  */
1120       if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1121         {
1122           cstring_free (rel_buffer);
1123           /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */
1124           return cstring_copy (filename);
1125         }
1126
1127       /*drl 10-14-2002 end previously removed code */
1128       /*#endif*/
1129       /* For each of them, put a `../' at the beginning of the short name.  */
1130       while (unmatched_slash_count-- > 0)
1131         {
1132           /* Give up if the result gets to be longer
1133              than the absolute path name.  */
1134           char * temp_rel_buf_p;
1135
1136           /*drl This comment is necessary because for some reason Splint
1137             does not realize that the pasts where rel_buf_p is released
1138             do not reach here*/
1139           /*@-usereleased@*/
1140           temp_rel_buf_p = rel_buf_p;
1141           /*@-usereleased@*/
1142           
1143           if (rel_buffer + filename_len <= temp_rel_buf_p + 3)
1144             {
1145               sfree (rel_buffer);
1146               return cstring_copy (filename);
1147             }
1148
1149           *rel_buf_p++ = '.';
1150           *rel_buf_p++ = '.';
1151           *rel_buf_p++ = CONNECTCHAR;
1152         }
1153       
1154       /* Then tack on the unmatched part of the desired file's name.  */
1155
1156       do
1157         {
1158           if (rel_buffer + filename_len <= rel_buf_p)
1159             {
1160               cstring_free (rel_buffer);
1161               return cstring_copy (filename);
1162             }
1163         } /*@-usereleased@*/
1164       while ((*rel_buf_p++ = *path_p++) != '\0') ;
1165
1166       
1167       /*@=usereleased@*/ /* Splint limitation: shouldn't need these */
1168       --rel_buf_p;
1169
1170       if (osd_isConnectChar (*(rel_buf_p-1)))
1171         *--rel_buf_p = '\0';
1172
1173       /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */
1174       return rel_buffer;
1175     }
1176   /*@noaccess cstring@*/
1177 # else
1178   return cstring_copy (filename);
1179 # endif
1180 }
1181
1182 cstring osd_getCurrentDirectory ()
1183 {
1184 # if defined(MSDOS) || defined(OS2)
1185   return cstring_makeLiteralTemp ("");
1186 # else
1187   return cstring_makeLiteralTemp ("./");
1188 # endif
1189 }
1190
1191
1192
This page took 2.203503 seconds and 3 git commands to generate.