2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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.
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
27 ** Provide a system-independent interface to system-dependent
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.
38 * - added OS/2 specific includes before osd_getPid()
39 * - handle files like in WIN32 for OS/2 in osd_fileExists()
44 # include <sys/types.h>
45 # include <sys/stat.h>
46 /* Fix suggested by Lars Rasmussen */
49 /* POSIX platforms should defined getpid in unistd.h */
50 # if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
58 # include "lclintMacros.nf"
65 extern int stat (const char *, /*@out@*/ struct stat *);
68 static bool osd_executableFileExists (char *);
70 static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
71 /*@out@*/ size_t *p_len);
73 extern cstring LSLRootName (cstring filespec)
76 char *result, *startName, *tail;
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';
89 /*@noaccess cstring@*/
92 extern /*@observer@*/ cstring
93 osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
96 char *ret = osd_getEnvironmentVariable (env);
106 /*@noaccess cstring@*/
112 ** FUNCTIONAL DESCRIPTION:
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.
118 ** FORMAL PARAMETERS:
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.
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
138 ** Requires that parameters, path and file, are valid C strings.
144 extern /*@observer@*/ cstring osd_getHomeDir ()
146 /* Would something different be better for windows? */
147 return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
150 filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
152 return (osd_getPath (context_getLarchPath (), file, returnPath));
156 osd_getPath (cstring path, cstring file, cstring *returnPath)
161 char aPath[MAXPATHLEN];
162 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
167 llassert (cstring_isDefined (file));
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. */
175 (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
177 (*file == CONNECTCHAR)
181 /* No path specified. Look for it in the current directory. */
183 strcpy (&aPath[0], file);
185 if (osd_fileExists (&aPath[0]))
187 rVal = OSD_FILEFOUND;
188 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
189 strcpy (*returnPath, &aPath[0]);
194 /* Path specified. Loop through directories in path looking for the */
195 /* first occurrence of the file. */
197 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
198 rVal == OSD_FILENOTFOUND)
200 if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
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);
208 if (osd_fileExists (&aPath[0]))
210 rVal = OSD_FILEFOUND;
211 *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
212 strcpy (*returnPath, &aPath[0]);
217 rVal = OSD_PATHTOOLONG;
223 /*@noaccess cstring@*/
227 osd_getExePath (cstring path, cstring file, cstring *returnPath)
232 char aPath[MAXPATHLEN];
233 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
236 fullPath = osd_getEnvironmentVariable (path);
238 if (fullPath == NULL)
240 /* No path specified. Look for it in the current directory. */
241 llassert (cstring_isDefined (file));
242 strcpy (&aPath[0], file);
244 if (osd_fileExists (&aPath[0]))
246 rVal = OSD_FILEFOUND;
247 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
248 strcpy (*returnPath, &aPath[0]);
254 ** Path specified. Loop through directories in path looking
255 ** for the first occurrence of the file.
258 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
259 rVal == OSD_FILENOTFOUND)
261 llassert (cstring_isDefined (file));
263 if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
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);
271 if (osd_executableFileExists (&aPath[0]))
273 rVal = OSD_FILEFOUND;
274 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
275 strcpy (*returnPath, &aPath[0]);
280 rVal = OSD_PATHTOOLONG;
286 /*@noaccess cstring@*/
290 osd_fileExists (cstring filespec)
294 return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
296 # if defined (WIN32) || defined (OS2)
297 FILE *test = fopen (cstring_toCharsSafe (filespec), "r");
301 (void) fclose (test);
315 osd_executableFileExists (/*@unused@*/ char *filespec)
319 # if defined(__IBMC__) && defined(OS2)
320 # define S_IFMT (unsigned short)0xFFFF
322 if (stat (filespec, &buf) == 0)
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 */
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;
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)
353 ** FUNCTIONAL DESCRIPTION:
355 ** Find the next directory from a directory path.
357 ** FORMAL PARAMETERS:
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
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
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.
378 ** TRUE if we found another directory.
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.
392 nextdir (d_char *current_dir, d_char *dir, size_t *len)
396 if (**current_dir == '\0')
402 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
404 /* Find next ':' or end of string */
405 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
410 *current_dir = tchar;
411 *len = size_fromInt (tchar - *dir);
415 /*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
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));
423 return cstring_undefined;
427 return cstring_makeLiteralTemp (val);
430 return cstring_undefined;
437 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
441 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
443 int osd_system (cstring cmd)
446 /* system ("printenv"); */
451 res = system (cstring_toCharsSafe (cmd));
457 /* This should be defined by unistd.h */
459 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
463 int osd_unlink (cstring fname)
467 res = unlink (cstring_toCharsSafe (fname));
471 llcontbug (message ("Cannot remove temporary file: %s (%s)",
473 cstring_fromChars (strerror (errno))));
479 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
486 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
487 int pid = _getpid ();
489 pid_t pid = getpid ();
495 cstring osd_fixDefine (cstring x)
498 llassert (cstring_isDefined (x));
500 if (strchr (x, '\'') != NULL) {
502 ** If there is a single quote, check for <ident>='<string>' and
503 ** produce <ident>=<string>
506 char *eqs = strchr (x, '=');
509 if (eqs[1] == '\'') {
510 char *endqu = strrchr (x, '\'');
513 if (*(endqu - 1) != '\\') {
514 if (*(endqu + 1) == '\0') {
519 def = cstring_fromChars (eqs + 2);
521 res = cstring_concat (cstring_fromChars (x), def);
532 return cstring_copy (x);
533 /*@noaccess cstring@*/
536 bool osd_fileIsReadable (cstring f)
538 FILE *fl = fopen (cstring_toCharsSafe (f), "r");
540 if (fl != (FILE *) 0)
542 check (fclose (fl) == 0);
551 bool osd_isConnectChar (char c)
553 if (c == CONNECTCHAR)
558 # ifdef HASALTCONNECTCHAR
559 if (c == ALTCONNECTCHAR)
569 ** Returns true if c2 starts with the same path as c1
571 ** This is called by context_isSystemDir to determine if a
572 ** directory is on the system path.
574 ** In unix, this is just a string comparison. For Win32 and OS2, we need a more
575 ** complex comparison.
578 bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
580 llassert (cstring_isDefined (prefixpath));
582 if (cstring_isEmpty (dirpath))
584 return (cstring_isEmpty (prefixpath));
587 # if defined (WIN32) || defined (OS2)
589 /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
592 ** If one has a drive specification, but the other doesn't, skip it.
595 if (strchr (dirpath, ':') == NULL
596 && strchr (prefixpath, ':') != NULL)
598 prefixpath = strchr (prefixpath, ':') + 1;
602 if (strchr (prefixpath, ':') == NULL
603 && strchr (dirpath, ':') != NULL)
605 dirpath = strchr (dirpath, ':') + 1;
610 int len = size_toInt (strlen (prefixpath));
614 for (i = 0, slen = 0; i < len; i++, slen++)
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 */
620 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
622 /* Skip one or more connect chars */
624 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
629 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
634 /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
635 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
643 /*@noaccess cstring@*/
647 return (cstring_equalPrefix (dirpath, prefixpath));