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