]> andersk Git - splint.git/blob - src/osd.c
Added fileTable tracking of open files, so they may be closed on fatal exits.
[splint.git] / src / osd.c
1 /*
2 ** LCLint - 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://lclint.cs.virginia.edu
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
This page took 0.086964 seconds and 5 git commands to generate.