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