-/*
-** Splint - annotation-assisted static program checker
-** Copyright (C) 1994-2003 University of Virginia,
-** Massachusetts Institute of Technology
-**
-** This program is free software; you can redistribute it and/or modify it
-** under the terms of the GNU General Public License as published by the
-** Free Software Foundation; either version 2 of the License, or (at your
-** option) any later version.
-**
-** This program is distributed in the hope that it will be useful, but
-** WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-**
-** The GNU General Public License is available from http://www.gnu.org/ or
-** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-** MA 02111-1307, USA.
-**
-** For information on splint: info@splint.org
-** To report a bug: splint-bug@splint.org
-** For more information: http://www.splint.org
-*/
-/*
-** osd.c
-**
-** Provide a system-independent interface to system-dependent
-** file operations.
-*/
-
-/*
- * Modified by Herbert 04/19/97:
- * - added conditional 'OS2' to conditional 'MSDOS'
- * - added include of new header portab.h.
- * - changed '/' to macro.
- * - added DOS / OS/2 specific stuff in osd_getPath.
- * Herbert 06/12/2000:
- * - added OS/2 specific includes before osd_getPid()
- * - handle files like in WIN32 for OS/2 in osd_fileExists()
- * Herbert 02/17/2002:
- * - added OS/2 support to absolute file names
- */
-
-/*@-allmacros*/
-/*@ignore@*/
-# include <sys/types.h>
-# include <sys/stat.h>
-/* Fix suggested by Lars Rasmussen */
-# include <errno.h>
-
-/* POSIX platforms should defined getpid in unistd.h */
-# if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
-# include <process.h>
-# include <direct.h>
-# define getcwd _getcwd
-# else
-# include <unistd.h>
-# endif
-
-/*@end@*/
-/*@=allmacros*/
-# include "splintMacros.nf"
-# include "basic.h"
-# include "osd.h"
-
-/* from stat.h */
-/*@ignore@*/
-extern int stat (const char *, /*@out@*/ struct stat *);
-/*@end@*/
-
-static bool osd_executableFileExists (char *);
-
-static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
- /*@out@*/ size_t *p_len);
-
-extern cstring LSLRootName (cstring filespec)
-{
- /*@access cstring@*/
- char *result, *startName, *tail;
- size_t nameLength;
-
- llassert (cstring_isDefined (filespec));
- tail = strrchr (filespec, CONNECTCHAR);
- startName = (tail == NULL ? filespec : &tail[1]);
- tail = strrchr (startName, '.');
- nameLength = (tail == NULL ? strlen (startName)
- : size_fromInt (tail - startName));
- result = dmalloc (nameLength + 1);
- strncpy (result, startName, nameLength);
- result[(int) nameLength] = '\0';
- return result;
- /*@noaccess cstring@*/
-}
-
-extern /*@observer@*/ cstring
-osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
-{
- /*@access cstring@*/
- char *ret = osd_getEnvironmentVariable (env);
-
- if (ret == NULL)
- {
- return def;
- }
- else
- {
- return ret;
- }
- /*@noaccess cstring@*/
-}
-
-
-/*
-**++
-** FUNCTIONAL DESCRIPTION:
-**
-** This function attempts to locate a file in a search list. On VMS, it
-** just concatinates the path and file names, and then lets RMS do the
-** searching. On Ultrix, it searches for the file on the path.
-**
-** FORMAL PARAMETERS:
-**
-** path: search path where to look for the file.
-** file: name of file to search for.
-** returnPath: if a file is found, this is where the concatenated
-** directory and file name are returned.
-**
-** RETURN VALUE:
-**
-** OSD_FILEFOUND: the file was found on the search list.
-** OSD_FILENOTFOUND the file was not found.
-** OSD_PATHTOOLONG the concatenated directory and file name are too
-** long.
-**
-** SIDE EFFECTS:
-**
-** None
-**
-** PRECONDITIONS:
-**
-** Requires that parameters, path and file, are valid C strings.
-**
-**
-**--
-*/
-
-extern /*@observer@*/ cstring osd_getHomeDir ()
-{
- /* Would something different be better for windows? */
- return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
-}
-
-filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
-{
- return (osd_getPath (context_getLarchPath (), file, returnPath));
-}
-
-extern filestatus
-osd_getPath (cstring path, cstring file, cstring *returnPath)
-{
- char *fullPath;
- char *dirPtr;
- size_t dirLen;
- char aPath[MAXPATHLEN];
- filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
-
- /*@access cstring@*/
-
- fullPath = path;
- llassert (cstring_isDefined (file));
-
- /* 2002-01-01: make sure returnPath gets defined even when there are errors.
- ** (fixed splint checking detected this)
- */
-
- *returnPath = cstring_undefined;
-
- if (fullPath == NULL
- ||
-# if defined(OS2) || defined(MSDOS) || defined(WIN32)
- /* under OS/2 and MSDOS the includePath may be empty, if so, search
- * the current directory. */
- *fullPath == '\0' ||
- (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
-# else
- (*file == CONNECTCHAR)
-# endif
- )
- {
- /* No path specified. Look for it in the current directory. */
-
- strcpy (&aPath[0], file);
-
- if (osd_fileExists (&aPath[0]))
- {
- rVal = OSD_FILEFOUND;
- *returnPath = dmalloc (strlen (&aPath[0]) + 1);
- strcpy (*returnPath, &aPath[0]);
- }
- }
- else
- {
- /* Path specified. Loop through directories in path looking for the */
- /* first occurrence of the file. */
-
- while (nextdir (&fullPath, &dirPtr, &dirLen)
- && rVal == OSD_FILENOTFOUND)
- {
- if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
- {
- /* Cat directory and filename, and see if file exists. */
- strncpy (&aPath[0], dirPtr, dirLen);
- strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
- strcat (&aPath[0], CONNECTSTR);
- strcat (&aPath[0], file);
-
- if (osd_fileExists (&aPath[0]))
- {
- rVal = OSD_FILEFOUND;
- *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
- strcpy (*returnPath, &aPath[0]);
- }
- }
- else
- {
- rVal = OSD_PATHTOOLONG;
- }
- }
- }
-
- return rVal;
- /*@noaccess cstring@*/
-}
-
-extern filestatus
-osd_getExePath (cstring path, cstring file, cstring *returnPath)
-{
- char *fullPath;
- char *dirPtr;
- size_t dirLen;
- char aPath[MAXPATHLEN];
- filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
- /*@access cstring@*/
-
- *returnPath = cstring_undefined;
- fullPath = osd_getEnvironmentVariable (path);
-
- if (fullPath == NULL)
- {
- /* No path specified. Look for it in the current directory. */
- llassert (cstring_isDefined (file));
- strcpy (&aPath[0], file);
-
- if (osd_fileExists (&aPath[0]))
- {
- rVal = OSD_FILEFOUND;
- *returnPath = dmalloc (strlen (&aPath[0]) + 1);
- strcpy (*returnPath, &aPath[0]);
- }
- }
- else
- {
- /*
- ** Path specified. Loop through directories in path looking
- ** for the first occurrence of the file.
- */
-
- while (nextdir (&fullPath, &dirPtr, &dirLen) &&
- rVal == OSD_FILENOTFOUND)
- {
- llassert (cstring_isDefined (file));
-
- if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
- {
- /* Cat directory and filename, and see if file exists. */
- strncpy (&aPath[0], dirPtr, dirLen);
- strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
- strcat (&aPath[0], CONNECTSTR);
- strcat (&aPath[0], file);
-
- if (osd_executableFileExists (&aPath[0]))
- {
- rVal = OSD_FILEFOUND;
- *returnPath = dmalloc (strlen (&aPath[0]) + 1);
- strcpy (*returnPath, &aPath[0]);
- }
- }
- else
- {
- rVal = OSD_PATHTOOLONG;
- }
- }
- }
-
- return rVal;
- /*@noaccess cstring@*/
-}
-
-bool
-osd_fileExists (cstring filespec)
-{
-# ifdef UNIX
- struct stat buf;
- return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
-# else
-# if defined (WIN32) || defined (OS2)
- FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
-
- if (test != NULL)
- {
- (void) fileTable_closeFile (context_fileTable (),test);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-# else
- return FALSE;
-# endif
-# endif
-}
-
-# if defined(__IBMC__) && defined(OS2)
-# define S_IFMT (unsigned short)0xFFFF
-# endif
-
-/*
-** Works form Win32 at least...
-*/
-
-# ifndef S_IXUSR
-/*@-macrounrecog@*/
-# define S_IXUSR _S_IEXEC
-/*@=macrounrecog@*/
-# endif
-
-bool
-osd_executableFileExists (/*@unused@*/ char *filespec)
-{
-# ifdef UNIX
- struct stat buf;
- if (stat (filespec, &buf) == 0)
- {
- /* mask by file type */
- /*@-unrecog@*/ /* S_IFMT is not defined */
- if ((buf.st_mode & S_IFMT) != S_IFDIR /*@=unrecog@*/) /* not a directory */
- {
- /* as long as it is an executable file */
-# if defined(__IBMC__) && defined(OS2)
- int com_or_exe_pos = strlen( filespec) - 4;
- return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
- || stricmp( &filespec[com_or_exe_pos], ".com") == 0
- || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
- || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
-# else
- return (((buf.st_mode & S_IXUSR)
-# if defined (S_IXGRP) && defined (S_IXOTH)
- | (buf.st_mode & S_IXGRP) |
- (buf.st_mode & S_IXOTH)
-# endif
- ) != 0);
-# endif
- }
- }
-# endif
- return (FALSE);
-
-}
-
-/*
-**++
-** FUNCTIONAL DESCRIPTION:
-**
-** Find the next directory from a directory path.
-**
-** FORMAL PARAMETERS:
-**
-** char ** current_dir :
-** Points to the current position in the path string. The first time
-** you call this routine, this should point to the first character of
-** the path. On return, this will be updated to point to the
-** terminating \0 or : of the first directory found. You can then pass
-** it unchanged for subsequent calls; this routine will correctly skip
-** over the :.
-**
-** char ** dir :
-** On exit, this will point to the first character of the directory
-** that was found. This will be a pointer directly into the client's
-** path string.
-**
-** unsigned int * len :
-** On exit, this will contain the length of the directory that was
-** found, not counting any terminating \0 or :. If no directory was
-** found, this will be 0.
-**
-** RETURN VALUE:
-** TRUE if we found another directory.
-** FALSE otherwise.
-**
-** DESIGN:
-**
-** We return a pointer and length, rather than a string, because of a)
-** historical reasons; and b) this avoids having to allocate storage.
-**
-**
-**
-**--
-*/
-
-static bool
-nextdir (d_char *current_dir, d_char *dir, size_t *len)
-{
- char *tchar;
-
- if (**current_dir == '\0')
- {
- *len = 0;
- *dir = NULL;
- return FALSE;
- }
-
- *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
-
- /* Find next ':' or end of string */
- for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
- {
- ;
- }
-
- *current_dir = tchar;
- *len = size_fromInt (tchar - *dir);
- return TRUE;
-}
-
-/*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
-{
- /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
-# if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
- char *val = getenv (cstring_toCharsSafe (var));
-
- if (val == NULL)
- {
- return cstring_undefined;
- }
- else
- {
- return cstring_makeLiteralTemp (val);
- }
-# else
- return cstring_undefined;
-# endif
-}
-
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
-extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
-# endif
-
-# ifndef system
-extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
-# endif
-int osd_system (cstring cmd)
-{
- int res;
- /* system ("printenv"); */
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
- (void) _flushall ();
-# endif
-
- res = system (cstring_toCharsSafe (cmd));
- return res;
-}
-
-# ifndef unlink
-/* This should be defined by unistd.h */
-/*@-redecl@*/
-extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
-/*@=redecl@*/
-# endif
-
-static bool s_tempError = FALSE;
-
-void osd_setTempError (void)
-{
- s_tempError = TRUE;
-}
-
-int osd_unlink (cstring fname)
-{
- int res;
-
- res = unlink (cstring_toCharsSafe (fname));
-
- if (res != 0)
- {
- if (!s_tempError)
- {
- llcontbug (message ("Cannot remove temporary file: %s (%s)",
- fname,
- cstring_fromChars (strerror (errno))));
- }
- }
-
- return res;
-}
-
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
-int
-# else
-int /* pid_t */
-# endif
-osd_getPid ()
-{
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
- int pid = _getpid ();
-# else
- pid_t pid = getpid ();
-# endif
-
- return (int) pid;
-}
-
-cstring osd_fixDefine (cstring x)
-{
- /*@access cstring@*/
- llassert (cstring_isDefined (x));
-# ifdef UNIX
- if (strchr (x, '\'') != NULL) {
- /*
- ** If there is a single quote, check for <ident>='<string>' and
- ** produce <ident>=<string>
- */
-
- char *eqs = strchr (x, '=');
-
- if (eqs != NULL) {
- if (eqs[1] == '\'') {
- char *endqu = strrchr (x, '\'');
-
- if (endqu != NULL) {
- if (*(endqu - 1) != '\\') {
- if (*(endqu + 1) == '\0') {
- cstring res;
- cstring def;
-
- *endqu = '\0';
- def = cstring_fromChars (eqs + 2);
- eqs[1] = '\0';
- res = cstring_concat (cstring_fromChars (x), def);
- return res;
- }
- }
- }
- }
- }
- }
-
-# endif
-
- return cstring_copy (x);
- /*@noaccess cstring@*/
-}
-
-bool osd_fileIsReadable (cstring f)
-{
- FILE *fl = fileTable_openReadFile (context_fileTable (), f);
-
- if (fl != NULL)
- {
- check (fileTable_closeFile (context_fileTable (), fl));
- return (TRUE);
- }
- else
- {
- return (FALSE);
- }
-}
-
-bool osd_isConnectChar (char c)
-{
- if (c == CONNECTCHAR)
- {
- return TRUE;
- }
-
-# ifdef HASALTCONNECTCHAR
- if (c == ALTCONNECTCHAR)
- {
- return TRUE;
- }
-# endif
-
- return FALSE;
-}
-
-/*
-** Returns true if c2 starts with the same path as c1
-**
-** This is called by context_isSystemDir to determine if a
-** directory is on the system path.
-**
-** In unix, this is just a string comparison. For Win32 and OS2, we need a more
-** complex comparison.
-*/
-
-bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
-{
- llassert (cstring_isDefined (prefixpath));
-
- if (cstring_isEmpty (dirpath))
- {
- return (cstring_isEmpty (prefixpath));
- }
-
-# if defined (WIN32) || defined (OS2)
-
- /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
-
- /*
- ** If one has a drive specification, but the other doesn't, skip it.
- */
-
- if (strchr (dirpath, ':') == NULL
- && strchr (prefixpath, ':') != NULL)
- {
- prefixpath = strchr (prefixpath, ':') + 1;
- }
- else
- {
- if (strchr (prefixpath, ':') == NULL
- && strchr (dirpath, ':') != NULL)
- {
- dirpath = strchr (dirpath, ':') + 1;
- }
- }
-
- {
- int len = size_toInt (strlen (prefixpath));
- int i = 0;
- int slen = 0;
-
- for (i = 0, slen = 0; i < len; i++, slen++)
- {
- /* Allow any number of connect characters in any combination:
- * c:/usr//src\/foo == c:\\usr/src\/foo
- * After this we'll be at the last of such a sequence */
-
- if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
- {
- /* Skip one or more connect chars */
-
- for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
- {
- ;
- }
-
- for (; osd_isConnectChar (prefixpath[i+1]); ++i)
- {
- ;
- }
- }
- /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
- else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
- {
- return FALSE;
- }
-
- }
- }
-
- /*@noaccess cstring@*/
-
- return TRUE;
-# else
- return (cstring_equalPrefix (dirpath, prefixpath));
-# endif
-}
-
-# if 0
-/*
-** This code provided by Herbert Martin Dietze, to canonicalize path names.
-*/
-
-char *osd_getcwd (/*@returned@*/ char *str, size_t size)
-{
- return getcwd (str, size);
-}
-
-/*@null@*/ /*@observer@*/ char *
-osd_dirNext (char *str)
-{
- char *p1 = strchr (str, '/');
- char *p2 = strchr (str, '\\');
-
- if (p1 == NULL)
- {
- if (p2 != NULL)
- {
- return p2 + 1;
- }
- else
- {
- return NULL;
- }
- }
- else if (p2 == NULL)
- {
- return p1 + 1;
- }
- else /* both not null */
- {
- return (p1 < p2 ? p1 : p2) + 1;
- }
-}
-
-static void
-osd_dirShift (char *str, size_t num) /*@modifies str@*/
-{
- int i;
-
- assert (num <= strlen (str));
-
- for (i = 0; str[i] != '\0'; i++)
- {
- str[i] = str[i + num];
- }
-}
-
-bool
-osd_dirDotdot (char *str)
-{
- return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
-}
-
-void
-osd_dirNormalize (char *str)
-{
- char *pos1, *pos2;
-
- for (; osd_isConnectChar (str[0]); str++)
- {
- }
-
- for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
- {
- }
-
- for (pos1 = pos2 = str;
- pos1 != NULL;
- pos2 = pos1, pos1 = osd_dirNext (pos1))
- {
- /* remove redundant `./' entry */
- while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
- {
- osd_dirShift (pos1, 2);
- }
-
- /* remove redundant `foo/../' entry */
- if (osd_dirDotdot (pos1) && pos2 < pos1)
- {
- osd_dirShift (pos2, pos1 - pos2 + 1);
- osd_dirNormalize (str);
- }
- }
-}
-
-/*@null@*/ char *
-osd_dirAbsolute (char *str)
-{
- char *ret = NULL;
- size_t size = PATH_MAX * sizeof (*ret);
-
- DPRINTF (("Absolute for: %s", str));
-
-# if defined (WIN32) || defined (OS2) || defined (MSDOS)
- if (strlen (str) > 1 && str[1] == ':')
- {
- /*
- ** Its a drive letter
- */
-
- ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
- strcpy (ret, str);
- }
- else
-# endif
- if (osd_isConnectChar (str[0]))
- {
- ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
- strcpy (ret, str);
- }
- else
- {
- ret = dmalloc (size);
-
- ret = osd_getcwd (ret, size);
- ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
-
- if (ret == NULL)
- {
- return NULL;
- }
-
- strcat (ret, CONNECTSTR);
- strcat (ret, str);
- }
-
- osd_dirNormalize (ret);
- return ret;
-}
-
-# endif
-
-/*
-** absolute paths
-**
-** This code is adapted from:
-**
-** 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
-**
-**
-** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
-** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-**
-** This file is part of GNU CC.
-**
-** GNU CC is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2, or (at your option)
-** any later version.
-**
-** GNU CC is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with GNU CC; see the file COPYING. If not, write to
-** the Free Software Foundation, 59 Temple Place - Suite 330,
-** Boston, MA 02111-1307, USA.
-*/
-
-/*
-** Return the absolutized filename for the given relative
-** filename. Note that if that filename is already absolute, it may
-** still be returned in a modified form because this routine also
-** eliminates redundant slashes and single dots and eliminates double
-** dots to get a shortest possible filename from the given input
-** filename. The absolutization of relative filenames is made by
-** assuming that the given filename is to be taken as relative to
-** the first argument (cwd) or to the current directory if cwd is
-** NULL.
-*/
-
-/* A pointer to the current directory filename (used by abspath). */
-static /*@only@*/ cstring osd_cwd = cstring_undefined;
-
-static void osd_setWorkingDirectory (void)
-{
-# if defined (UNIX) || defined (OS2)
- char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
- char *cwd = getcwd (buf, MAXPATHLEN);
-
- llassert (cstring_isUndefined (osd_cwd));
-
- if (cwd == NULL)
- {
- lldiagmsg (message ("Cannot get working directory: %s\n",
- lldecodeerror (errno)));
- osd_cwd = cstring_makeLiteral ("<missing directory>");
- }
- else
- {
- osd_cwd = cstring_fromCharsNew (cwd);
- }
-
- sfree (buf);
-# else
- ; /* Don't know how to do this for non-POSIX platforms */
-# endif
-}
-
-void osd_initMod (void)
-{
- osd_setWorkingDirectory ();
-}
-
-void osd_destroyMod (void)
-{
- cstring_free (osd_cwd);
- osd_cwd = cstring_undefined;
-}
-
-cstring osd_absolutePath (cstring cwd, cstring filename)
-{
-# if defined (UNIX) || defined (OS2)
- /* Setup the current working directory as needed. */
- cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
- char *abs_buffer;
- char *endp, *outp, *inp;
-
- /*@access cstring@*/
- llassert (cstring_isDefined (cwd2));
- llassert (cstring_isDefined (filename));
-
- abs_buffer = (char *) dmalloc (cstring_length (cwd2) + cstring_length (filename) + 2);
- endp = abs_buffer;
-
- /*
- ** Copy the filename (possibly preceded by the current working
- ** directory name) into the absolutization buffer.
- */
-
- {
- const char *src_p;
-
- if (!osd_isConnectChar (filename[0])
-# ifdef OS2
- && !(isalpha (filename[0]) && filename[1] == ':')
-# endif
- )
- {
- src_p = cwd2;
-
- while ((*endp++ = *src_p++) != '\0')
- {
- continue;
- }
-
- *(endp-1) = CONNECTCHAR; /* overwrite null */
- }
-
- src_p = filename;
-
- while ((*endp++ = *src_p++) != '\0')
- {
- continue;
- }
- }
-
- /* Now make a copy of abs_buffer into abs_buffer, shortening the
- filename (by taking out slashes and dots) as we go. */
-
- outp = inp = abs_buffer;
- *outp++ = *inp++; /* copy first slash */
-#ifdef apollo
- if (inp[0] == '/')
- *outp++ = *inp++; /* copy second slash */
-#endif
- for (;;)
- {
- if (inp[0] == '\0')
- {
- break;
- }
- else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
- {
- inp++;
- continue;
- }
- else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
- {
- if (inp[1] == '\0')
- {
- break;
- }
- else if (osd_isConnectChar (inp[1]))
- {
- inp += 2;
- continue;
- }
- else if ((inp[1] == '.')
- && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
- {
- inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
- outp -= 2;
-
- while (outp >= abs_buffer && !osd_isConnectChar (*outp))
- {
- outp--;
- }
-
- if (outp < abs_buffer)
- {
- /* Catch cases like /.. where we try to backup to a
- point above the absolute root of the logical file
- system. */
-
- llfatalbug (message ("Invalid file name: %s", filename));
- }
-
- *++outp = '\0';
- continue;
- }
- else
- {
- ;
- }
- }
- else
- {
- ;
- }
-
- *outp++ = *inp++;
- }
-
- /* On exit, make sure that there is a trailing null, and make sure that
- the last character of the returned string is *not* a slash. */
-
- *outp = '\0';
- if (osd_isConnectChar (outp[-1]))
- *--outp = '\0';
-
- /*@noaccess cstring@*/
- return cstring_fromChars (abs_buffer);
-# else
- DPRINTF (("Here: %s", filename));
- return cstring_copy (filename);
-# endif
-}
-
-/*
-** Given a filename (and possibly a directory name from which the filename
-** is relative) return a string which is the shortest possible
-** equivalent for the corresponding full (absolutized) filename. The
-** shortest possible equivalent may be constructed by converting the
-** absolutized filename to be a relative filename (i.e. relative to
-** the actual current working directory). However if a relative filename
-** is longer, then the full absolute filename is returned.
-**
-** KNOWN BUG: subpart of the original filename is actually a symbolic link.
-**
-** this is really horrible code...surely someone has written a less buggy version of this!
-*/
-
-cstring osd_outputPath (cstring filename)
-{
-# if defined (UNIX) || defined (OS2)
- char *rel_buffer;
- char *rel_buf_p;
- cstring cwd_p = osd_cwd;
- char *path_p;
- int unmatched_slash_count = 0;
- size_t filename_len = cstring_length (filename);
-
- llassertretval (filename_len > 0, filename);
-
- /*@access cstring@*/
- path_p = filename;
- rel_buffer = (char *) dmalloc (filename_len);
- rel_buf_p = rel_buffer;
- *rel_buf_p = '\0';
-
- if (cwd_p == NULL)
- {
- /* Need to prevent recursive assertion failures */
- return cstring_copy (filename);
- }
-
- llassert (cwd_p != NULL);
- llassert (path_p != NULL);
-
- while ((*cwd_p != '\0') && (*cwd_p == *path_p))
- {
- cwd_p++;
- path_p++;
- }
-
- if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p))) /* whole pwd matched */
- {
- if (*path_p == '\0') /* input *is* the current path! */
- {
- cstring_free (rel_buffer);
- return cstring_makeLiteral (".");
- }
- else
- {
- cstring_free (rel_buffer);
- return cstring_fromCharsNew (path_p + 1);
- }
- }
- else
- {
-
- /* drl 2002-10/14 I had to put this code back*/
- /* 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
- */
-
- /* evans 2002-02-05 This is horrible code, which I've removed. I couldn't find any
- ** test cases that need it, so I hope I'm not breaking anything.
- */
- /*#if 0*/
-
- if (*path_p != '\0')
- {
- --cwd_p;
- --path_p;
-
- while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */
- {
- --cwd_p;
- --path_p;
- }
- cwd_p++;
- path_p++;
- unmatched_slash_count++;
- }
-
- /* Find out how many directory levels in cwd were *not* matched. */
- while (*cwd_p != '\0')
- {
- if (osd_isConnectChar (*cwd_p++))
- unmatched_slash_count++;
- }
-
- /* Now we know how long the "short name" will be.
- Reject it if longer than the input. */
- if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
- {
- cstring_free (rel_buffer);
- /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */
- return cstring_copy (filename);
- }
-
- /*drl 10-14-2002 end previously removed code */
- /*#endif*/
- /* For each of them, put a `../' at the beginning of the short name. */
- while (unmatched_slash_count-- > 0)
- {
- /* Give up if the result gets to be longer
- than the absolute path name. */
- char * temp_rel_buf_p;
-
- /*drl This comment is necessary because for some reason Splint
- does not realize that the pasts where rel_buf_p is released
- do not reach here*/
- /*@-usereleased@*/
- temp_rel_buf_p = rel_buf_p;
- /*@-usereleased@*/
-
- if (rel_buffer + filename_len <= temp_rel_buf_p + 3)
- {
- sfree (rel_buffer);
- return cstring_copy (filename);
- }
-
- *rel_buf_p++ = '.';
- *rel_buf_p++ = '.';
- *rel_buf_p++ = CONNECTCHAR;
- }
-
- /* Then tack on the unmatched part of the desired file's name. */
-
- do
- {
- if (rel_buffer + filename_len <= rel_buf_p)
- {
- cstring_free (rel_buffer);
- return cstring_copy (filename);
- }
- } /*@-usereleased@*/
- while ((*rel_buf_p++ = *path_p++) != '\0') ;
-
-
- /*@=usereleased@*/ /* Splint limitation: shouldn't need these */
- --rel_buf_p;
-
- if (osd_isConnectChar (*(rel_buf_p-1)))
- *--rel_buf_p = '\0';
-
- /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */
- return rel_buffer;
- }
- /*@noaccess cstring@*/
-# else
- return cstring_copy (filename);
-# endif
-}
-
-cstring osd_getCurrentDirectory ()
-{
-# if defined(MSDOS) || defined(OS2)
- return cstring_makeLiteralTemp ("");
-# else
- return cstring_makeLiteralTemp ("./");
-# endif
-}
-
-
-
+/*\r
+** Splint - annotation-assisted static program checker\r
+** Copyright (C) 1994-2003 University of Virginia,\r
+** Massachusetts Institute of Technology\r
+**\r
+** This program is free software; you can redistribute it and/or modify it\r
+** under the terms of the GNU General Public License as published by the\r
+** Free Software Foundation; either version 2 of the License, or (at your\r
+** option) any later version.\r
+** \r
+** This program is distributed in the hope that it will be useful, but\r
+** WITHOUT ANY WARRANTY; without even the implied warranty of\r
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+** General Public License for more details.\r
+** \r
+** The GNU General Public License is available from http://www.gnu.org/ or\r
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\r
+** MA 02111-1307, USA.\r
+**\r
+** For information on splint: info@splint.org\r
+** To report a bug: splint-bug@splint.org\r
+** For more information: http://www.splint.org\r
+*/\r
+/*\r
+** osd.c\r
+**\r
+** Provide a system-independent interface to system-dependent\r
+** file operations.\r
+*/\r
+\r
+/*\r
+ * Modified by Herbert 04/19/97:\r
+ * - added conditional 'OS2' to conditional 'MSDOS'\r
+ * - added include of new header portab.h.\r
+ * - changed '/' to macro.\r
+ * - added DOS / OS/2 specific stuff in osd_getPath.\r
+ * Herbert 06/12/2000:\r
+ * - added OS/2 specific includes before osd_getPid()\r
+ * - handle files like in WIN32 for OS/2 in osd_fileExists()\r
+ * Herbert 02/17/2002:\r
+ * - added OS/2 support to absolute file names\r
+ */\r
+\r
+/*@-allmacros*/\r
+/*@ignore@*/\r
+# include <sys/types.h>\r
+# include <sys/stat.h>\r
+/* Fix suggested by Lars Rasmussen */\r
+# include <errno.h>\r
+\r
+/* POSIX platforms should defined getpid in unistd.h */\r
+# if defined (WIN32) || (defined(OS2) && defined(__IBMC__))\r
+# include <process.h>\r
+# include <direct.h>\r
+# define getcwd _getcwd\r
+# else\r
+# include <unistd.h>\r
+# endif\r
+\r
+/*@end@*/\r
+/*@=allmacros*/\r
+# include "splintMacros.nf"\r
+# include "basic.h"\r
+# include "osd.h"\r
+\r
+/* from stat.h */\r
+/*@ignore@*/\r
+extern int stat (const char *, /*@out@*/ struct stat *);\r
+/*@end@*/\r
+\r
+static bool osd_executableFileExists (char *);\r
+\r
+static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir, \r
+ /*@out@*/ size_t *p_len);\r
+\r
+extern cstring LSLRootName (cstring filespec)\r
+{\r
+ /*@access cstring@*/\r
+ char *result, *startName, *tail;\r
+ size_t nameLength;\r
+\r
+ llassert (cstring_isDefined (filespec));\r
+ tail = strrchr (filespec, CONNECTCHAR);\r
+ startName = (tail == NULL ? filespec : &tail[1]);\r
+ tail = strrchr (startName, '.');\r
+ nameLength = (tail == NULL ? strlen (startName) \r
+ : size_fromInt (tail - startName));\r
+ result = dmalloc (nameLength + 1);\r
+ strncpy (result, startName, nameLength);\r
+ result[(int) nameLength] = '\0';\r
+ return result;\r
+ /*@noaccess cstring@*/\r
+}\r
+\r
+extern /*@observer@*/ cstring\r
+osd_getEnvironment (cstring env, /*@returned@*/ cstring def)\r
+{\r
+ /*@access cstring@*/\r
+ char *ret = osd_getEnvironmentVariable (env);\r
+\r
+ if (ret == NULL)\r
+ {\r
+ return def;\r
+ }\r
+ else\r
+ {\r
+ return ret;\r
+ }\r
+ /*@noaccess cstring@*/\r
+}\r
+\r
+\r
+/*\r
+**++\r
+** FUNCTIONAL DESCRIPTION:\r
+**\r
+** This function attempts to locate a file in a search list. On VMS, it\r
+** just concatinates the path and file names, and then lets RMS do the\r
+** searching. On Ultrix, it searches for the file on the path.\r
+**\r
+** FORMAL PARAMETERS:\r
+**\r
+** path: search path where to look for the file.\r
+** file: name of file to search for.\r
+** returnPath: if a file is found, this is where the concatenated\r
+** directory and file name are returned.\r
+**\r
+** RETURN VALUE:\r
+**\r
+** OSD_FILEFOUND: the file was found on the search list.\r
+** OSD_FILENOTFOUND the file was not found.\r
+** OSD_PATHTOOLONG the concatenated directory and file name are too\r
+** long.\r
+**\r
+** SIDE EFFECTS:\r
+**\r
+** None\r
+**\r
+** PRECONDITIONS:\r
+**\r
+** Requires that parameters, path and file, are valid C strings.\r
+**\r
+**\r
+**--\r
+*/\r
+\r
+extern /*@observer@*/ cstring osd_getHomeDir ()\r
+{\r
+ /* Would something different be better for windows? */\r
+ return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));\r
+}\r
+\r
+filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)\r
+{\r
+ return (osd_getPath (context_getLarchPath (), file, returnPath));\r
+}\r
+\r
+extern filestatus\r
+osd_getPath (cstring path, cstring file, cstring *returnPath)\r
+{\r
+ char *fullPath;\r
+ char *dirPtr;\r
+ size_t dirLen;\r
+ char aPath[MAXPATHLEN];\r
+ filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */\r
+ \r
+ /*@access cstring@*/\r
+ \r
+ fullPath = path;\r
+ llassert (cstring_isDefined (file));\r
+ \r
+ /* 2002-01-01: make sure returnPath gets defined even when there are errors.\r
+ ** (fixed splint checking detected this)\r
+ */\r
+\r
+ *returnPath = cstring_undefined;\r
+\r
+ if (fullPath == NULL \r
+ || \r
+# if defined(OS2) || defined(MSDOS) || defined(WIN32)\r
+ /* under OS/2 and MSDOS the includePath may be empty, if so, search \r
+ * the current directory. */\r
+ *fullPath == '\0' || \r
+ (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))\r
+# else\r
+ (*file == CONNECTCHAR)\r
+# endif\r
+ )\r
+ {\r
+ /* No path specified. Look for it in the current directory. */\r
+ \r
+ strcpy (&aPath[0], file);\r
+ \r
+ if (osd_fileExists (&aPath[0]))\r
+ {\r
+ rVal = OSD_FILEFOUND;\r
+ *returnPath = dmalloc (strlen (&aPath[0]) + 1);\r
+ strcpy (*returnPath, &aPath[0]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Path specified. Loop through directories in path looking for the */\r
+ /* first occurrence of the file. */\r
+ \r
+ while (nextdir (&fullPath, &dirPtr, &dirLen) \r
+ && rVal == OSD_FILENOTFOUND)\r
+ {\r
+ if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)\r
+ {\r
+ /* Cat directory and filename, and see if file exists. */\r
+ strncpy (&aPath[0], dirPtr, dirLen);\r
+ strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */\r
+ strcat (&aPath[0], CONNECTSTR);\r
+ strcat (&aPath[0], file);\r
+ \r
+ if (osd_fileExists (&aPath[0]))\r
+ {\r
+ rVal = OSD_FILEFOUND;\r
+ *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);\r
+ strcpy (*returnPath, &aPath[0]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ rVal = OSD_PATHTOOLONG;\r
+ }\r
+ } \r
+ }\r
+\r
+ return rVal;\r
+ /*@noaccess cstring@*/\r
+}\r
+\r
+extern filestatus\r
+osd_getExePath (cstring path, cstring file, cstring *returnPath)\r
+{\r
+ char *fullPath;\r
+ char *dirPtr;\r
+ size_t dirLen;\r
+ char aPath[MAXPATHLEN];\r
+ filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */\r
+ /*@access cstring@*/ \r
+\r
+ *returnPath = cstring_undefined; \r
+ fullPath = osd_getEnvironmentVariable (path);\r
+ \r
+ if (fullPath == NULL)\r
+ {\r
+ /* No path specified. Look for it in the current directory. */\r
+ llassert (cstring_isDefined (file));\r
+ strcpy (&aPath[0], file);\r
+ \r
+ if (osd_fileExists (&aPath[0]))\r
+ {\r
+ rVal = OSD_FILEFOUND;\r
+ *returnPath = dmalloc (strlen (&aPath[0]) + 1);\r
+ strcpy (*returnPath, &aPath[0]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* \r
+ ** Path specified. Loop through directories in path looking\r
+ ** for the first occurrence of the file. \r
+ */\r
+\r
+ while (nextdir (&fullPath, &dirPtr, &dirLen) &&\r
+ rVal == OSD_FILENOTFOUND)\r
+ {\r
+ llassert (cstring_isDefined (file));\r
+\r
+ if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)\r
+ {\r
+ /* Cat directory and filename, and see if file exists. */\r
+ strncpy (&aPath[0], dirPtr, dirLen);\r
+ strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */\r
+ strcat (&aPath[0], CONNECTSTR);\r
+ strcat (&aPath[0], file);\r
+\r
+ if (osd_executableFileExists (&aPath[0]))\r
+ {\r
+ rVal = OSD_FILEFOUND;\r
+ *returnPath = dmalloc (strlen (&aPath[0]) + 1);\r
+ strcpy (*returnPath, &aPath[0]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ rVal = OSD_PATHTOOLONG;\r
+ }\r
+ }\r
+ }\r
+\r
+ return rVal;\r
+ /*@noaccess cstring@*/\r
+}\r
+\r
+bool\r
+osd_fileExists (cstring filespec)\r
+{\r
+# ifdef UNIX\r
+ struct stat buf;\r
+ /*@i3@*/ return (stat (cstring_toCharsSafe (filespec), &buf) == 0); /* spurious */\r
+# else\r
+# if defined (WIN32) || defined (OS2)\r
+ FILE *test = fileTable_openReadFile (context_fileTable (), filespec);\r
+ \r
+ if (test != NULL) \r
+ {\r
+ (void) fileTable_closeFile (context_fileTable (),test);\r
+ return TRUE;\r
+ } \r
+ else\r
+ { \r
+ return FALSE;\r
+ }\r
+# else \r
+ return FALSE;\r
+# endif\r
+# endif\r
+}\r
+\r
+# if defined(__IBMC__) && defined(OS2)\r
+# define S_IFMT (unsigned short)0xFFFF\r
+# endif\r
+\r
+/*\r
+** Works form Win32 at least...\r
+*/\r
+\r
+# ifndef S_IXUSR\r
+/*@-macrounrecog@*/\r
+# define S_IXUSR _S_IEXEC\r
+/*@=macrounrecog@*/\r
+# endif\r
+\r
+bool\r
+osd_executableFileExists (/*@unused@*/ char *filespec)\r
+{\r
+ /*@-compdestroy@*/ /* possible memory leaks here? */\r
+# ifdef UNIX\r
+ struct stat buf;\r
+ if (stat (filespec, &buf) == 0)\r
+ { \r
+ /* mask by file type */\r
+ /*@-type@*/ /* confusion about __mode_t and mode_t types */\r
+ if ((buf.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ \r
+ /*@=type@*/\r
+ {\r
+ /* as long as it is an executable file */\r
+# if defined(__IBMC__) && defined(OS2)\r
+ int com_or_exe_pos = strlen( filespec) - 4;\r
+ return stricmp( &filespec[com_or_exe_pos], ".exe") == 0\r
+ || stricmp( &filespec[com_or_exe_pos], ".com") == 0\r
+ || stricmp( &filespec[com_or_exe_pos], ".bat") == 0\r
+ || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;\r
+# else\r
+ return (((buf.st_mode & S_IXUSR)\r
+# if defined (S_IXGRP) && defined (S_IXOTH)\r
+ | (buf.st_mode & S_IXGRP) |\r
+ (buf.st_mode & S_IXOTH)\r
+# endif\r
+ ) != 0); /* spurious */\r
+# endif\r
+ }\r
+ }\r
+# endif\r
+ return (FALSE); \r
+ /*@=compdestroy@*/\r
+}\r
+\r
+/*\r
+**++\r
+** FUNCTIONAL DESCRIPTION:\r
+**\r
+** Find the next directory from a directory path.\r
+**\r
+** FORMAL PARAMETERS:\r
+**\r
+** char ** current_dir :\r
+** Points to the current position in the path string. The first time\r
+** you call this routine, this should point to the first character of\r
+** the path. On return, this will be updated to point to the\r
+** terminating \0 or : of the first directory found. You can then pass\r
+** it unchanged for subsequent calls; this routine will correctly skip\r
+** over the :.\r
+**\r
+** char ** dir :\r
+** On exit, this will point to the first character of the directory\r
+** that was found. This will be a pointer directly into the client's\r
+** path string.\r
+**\r
+** unsigned int * len :\r
+** On exit, this will contain the length of the directory that was\r
+** found, not counting any terminating \0 or :. If no directory was\r
+** found, this will be 0.\r
+**\r
+** RETURN VALUE:\r
+** TRUE if we found another directory.\r
+** FALSE otherwise.\r
+**\r
+** DESIGN:\r
+**\r
+** We return a pointer and length, rather than a string, because of a)\r
+** historical reasons; and b) this avoids having to allocate storage.\r
+**\r
+**\r
+**\r
+**--\r
+*/\r
+\r
+static bool\r
+nextdir (d_char *current_dir, d_char *dir, size_t *len)\r
+{\r
+ char *tchar;\r
+\r
+ if (**current_dir == '\0')\r
+ {\r
+ *len = 0;\r
+ *dir = NULL;\r
+ return FALSE;\r
+ }\r
+\r
+ *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);\r
+ \r
+ /* Find next ':' or end of string */\r
+ for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)\r
+ {\r
+ ;\r
+ }\r
+ \r
+ *current_dir = tchar;\r
+ *len = size_fromInt (tchar - *dir);\r
+ return TRUE;\r
+}\r
+\r
+/*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)\r
+{\r
+ /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */\r
+# if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)\r
+ char *val = getenv (cstring_toCharsSafe (var));\r
+\r
+ if (val == NULL) \r
+ {\r
+ return cstring_undefined; \r
+ } \r
+ else \r
+ {\r
+ return cstring_makeLiteralTemp (val);\r
+ }\r
+# else\r
+ return cstring_undefined;\r
+# endif\r
+}\r
+\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;\r
+# endif\r
+\r
+# ifndef system\r
+extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;\r
+# endif\r
+int osd_system (cstring cmd)\r
+{\r
+ int res;\r
+ /* system ("printenv"); */\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+ (void) _flushall (); \r
+# endif\r
+\r
+ res = system (cstring_toCharsSafe (cmd));\r
+ return res;\r
+}\r
+\r
+# ifndef unlink\r
+/* This should be defined by unistd.h */\r
+/*@-redecl@*/\r
+extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;\r
+/*@=redecl@*/\r
+# endif\r
+\r
+static bool s_tempError = FALSE;\r
+\r
+void osd_setTempError (void)\r
+{\r
+ s_tempError = TRUE;\r
+}\r
+\r
+int osd_unlink (cstring fname)\r
+{\r
+ int res;\r
+\r
+ res = unlink (cstring_toCharsSafe (fname));\r
+\r
+ if (res != 0)\r
+ {\r
+ if (!s_tempError)\r
+ {\r
+ llcontbug (message ("Cannot remove temporary file: %s (%s)",\r
+ fname,\r
+ cstring_fromChars (strerror (errno))));\r
+ }\r
+ }\r
+ \r
+ return res;\r
+}\r
+\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+int\r
+# else\r
+int /* pid_t */\r
+# endif\r
+osd_getPid ()\r
+{\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+ int pid = _getpid ();\r
+# else\r
+ __pid_t pid = getpid ();\r
+# endif\r
+\r
+ return (int) pid;\r
+}\r
+ \r
+cstring osd_fixDefine (cstring x)\r
+{\r
+ /*@access cstring@*/\r
+ llassert (cstring_isDefined (x));\r
+# ifdef UNIX\r
+ if (strchr (x, '\'') != NULL) {\r
+ /*\r
+ ** If there is a single quote, check for <ident>='<string>' and \r
+ ** produce <ident>=<string>\r
+ */\r
+\r
+ char *eqs = strchr (x, '=');\r
+\r
+ if (eqs != NULL) {\r
+ if (eqs[1] == '\'') {\r
+ char *endqu = strrchr (x, '\'');\r
+\r
+ if (endqu != NULL) {\r
+ if (*(endqu - 1) != '\\') {\r
+ if (*(endqu + 1) == '\0') {\r
+ cstring res;\r
+ cstring def;\r
+\r
+ *endqu = '\0';\r
+ def = cstring_fromChars (eqs + 2);\r
+ eqs[1] = '\0';\r
+ res = cstring_concat (cstring_fromChars (x), def);\r
+ return res;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } \r
+\r
+# endif\r
+\r
+ return cstring_copy (x);\r
+ /*@noaccess cstring@*/\r
+}\r
+\r
+bool osd_fileIsReadable (cstring f)\r
+{\r
+ FILE *fl = fileTable_openReadFile (context_fileTable (), f);\r
+\r
+ if (fl != NULL)\r
+ {\r
+ check (fileTable_closeFile (context_fileTable (), fl));\r
+ return (TRUE);\r
+ }\r
+ else\r
+ {\r
+ return (FALSE);\r
+ }\r
+}\r
+\r
+bool osd_isConnectChar (char c)\r
+{\r
+ if (c == CONNECTCHAR) \r
+ {\r
+ return TRUE;\r
+ }\r
+\r
+# ifdef HASALTCONNECTCHAR\r
+ if (c == ALTCONNECTCHAR)\r
+ {\r
+ return TRUE;\r
+ }\r
+# endif\r
+\r
+ return FALSE;\r
+}\r
+\r
+/*\r
+** Returns true if c2 starts with the same path as c1\r
+**\r
+** This is called by context_isSystemDir to determine if a\r
+** directory is on the system path.\r
+**\r
+** In unix, this is just a string comparison. For Win32 and OS2, we need a more\r
+** complex comparison.\r
+*/\r
+\r
+bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)\r
+{\r
+ llassert (cstring_isDefined (prefixpath));\r
+\r
+ if (cstring_isEmpty (dirpath)) \r
+ {\r
+ return (cstring_isEmpty (prefixpath));\r
+ }\r
+\r
+# if defined (WIN32) || defined (OS2)\r
+\r
+ /*@access cstring@*/ /* Moved this from cstring - should abstract it... */\r
+\r
+ /*\r
+ ** If one has a drive specification, but the other doesn't, skip it.\r
+ */\r
+ \r
+ if (strchr (dirpath, ':') == NULL\r
+ && strchr (prefixpath, ':') != NULL)\r
+ {\r
+ prefixpath = strchr (prefixpath, ':') + 1;\r
+ }\r
+ else \r
+ {\r
+ if (strchr (prefixpath, ':') == NULL\r
+ && strchr (dirpath, ':') != NULL)\r
+ {\r
+ dirpath = strchr (dirpath, ':') + 1;\r
+ }\r
+ }\r
+\r
+ {\r
+ int len = size_toInt (strlen (prefixpath));\r
+ int i = 0;\r
+ int slen = 0;\r
+\r
+ for (i = 0, slen = 0; i < len; i++, slen++)\r
+ {\r
+ /* Allow any number of connect characters in any combination:\r
+ * c:/usr//src\/foo == c:\\usr/src\/foo \r
+ * After this we'll be at the last of such a sequence */\r
+\r
+ if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))\r
+ {\r
+ /* Skip one or more connect chars */\r
+\r
+ for (; osd_isConnectChar (dirpath[slen+1]); ++slen)\r
+ {\r
+ ; \r
+ }\r
+ \r
+ for (; osd_isConnectChar (prefixpath[i+1]); ++i)\r
+ {\r
+ ;\r
+ }\r
+ }\r
+ /* Windows, MSDOS and OS/2 use case-insensitive path specs! */\r
+ else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))\r
+ {\r
+ return FALSE;\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ /*@noaccess cstring@*/ \r
+\r
+ return TRUE;\r
+# else\r
+ return (cstring_equalPrefix (dirpath, prefixpath));\r
+# endif\r
+}\r
+\r
+# if 0\r
+/*\r
+** This code provided by Herbert Martin Dietze, to canonicalize path names.\r
+*/\r
+\r
+char *osd_getcwd (/*@returned@*/ char *str, size_t size)\r
+{ \r
+ return getcwd (str, size);\r
+}\r
+\r
+/*@null@*/ /*@observer@*/ char *\r
+osd_dirNext (char *str)\r
+{\r
+ char *p1 = strchr (str, '/');\r
+ char *p2 = strchr (str, '\\');\r
+\r
+ if (p1 == NULL)\r
+ {\r
+ if (p2 != NULL)\r
+ {\r
+ return p2 + 1;\r
+ }\r
+ else\r
+ {\r
+ return NULL;\r
+ }\r
+ }\r
+ else if (p2 == NULL)\r
+ {\r
+ return p1 + 1;\r
+ }\r
+ else /* both not null */\r
+ {\r
+ return (p1 < p2 ? p1 : p2) + 1;\r
+ }\r
+}\r
+\r
+static void \r
+osd_dirShift (char *str, size_t num) /*@modifies str@*/\r
+{\r
+ int i;\r
+ \r
+ assert (num <= strlen (str));\r
+ \r
+ for (i = 0; str[i] != '\0'; i++)\r
+ {\r
+ str[i] = str[i + num];\r
+ }\r
+}\r
+\r
+bool\r
+osd_dirDotdot (char *str)\r
+{\r
+ return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);\r
+}\r
+\r
+void\r
+osd_dirNormalize (char *str)\r
+{\r
+ char *pos1, *pos2;\r
+\r
+ for (; osd_isConnectChar (str[0]); str++)\r
+ {\r
+ }\r
+\r
+ for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))\r
+ {\r
+ }\r
+\r
+ for (pos1 = pos2 = str; \r
+ pos1 != NULL; \r
+ pos2 = pos1, pos1 = osd_dirNext (pos1))\r
+ {\r
+ /* remove redundant `./' entry */\r
+ while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))\r
+ {\r
+ osd_dirShift (pos1, 2);\r
+ }\r
+\r
+ /* remove redundant `foo/../' entry */\r
+ if (osd_dirDotdot (pos1) && pos2 < pos1)\r
+ {\r
+ osd_dirShift (pos2, pos1 - pos2 + 1);\r
+ osd_dirNormalize (str);\r
+ }\r
+ }\r
+}\r
+\r
+/*@null@*/ char *\r
+osd_dirAbsolute (char *str)\r
+{\r
+ char *ret = NULL;\r
+ size_t size = PATH_MAX * sizeof (*ret);\r
+ \r
+ DPRINTF (("Absolute for: %s", str));\r
+\r
+# if defined (WIN32) || defined (OS2) || defined (MSDOS)\r
+ if (strlen (str) > 1 && str[1] == ':')\r
+ {\r
+ /*\r
+ ** Its a drive letter\r
+ */\r
+ \r
+ ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));\r
+ strcpy (ret, str);\r
+ }\r
+ else\r
+# endif\r
+ if (osd_isConnectChar (str[0]))\r
+ {\r
+ ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));\r
+ strcpy (ret, str);\r
+ }\r
+ else\r
+ {\r
+ ret = dmalloc (size);\r
+ \r
+ ret = osd_getcwd (ret, size);\r
+ ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));\r
+\r
+ if (ret == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ strcat (ret, CONNECTSTR);\r
+ strcat (ret, str);\r
+ }\r
+ \r
+ osd_dirNormalize (ret);\r
+ return ret;\r
+}\r
+\r
+# endif\r
+\r
+/*\r
+** absolute paths\r
+**\r
+** This code is adapted from:\r
+**\r
+** 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\r
+**\r
+**\r
+** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).\r
+** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.\r
+**\r
+** This file is part of GNU CC.\r
+**\r
+** GNU CC is free software; you can redistribute it and/or modify\r
+** it under the terms of the GNU General Public License as published by\r
+** the Free Software Foundation; either version 2, or (at your option)\r
+** any later version.\r
+**\r
+** GNU CC is distributed in the hope that it will be useful,\r
+** but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+** GNU General Public License for more details.\r
+** \r
+** You should have received a copy of the GNU General Public License\r
+** along with GNU CC; see the file COPYING. If not, write to\r
+** the Free Software Foundation, 59 Temple Place - Suite 330,\r
+** Boston, MA 02111-1307, USA. \r
+*/\r
+\r
+/* \r
+** Return the absolutized filename for the given relative\r
+** filename. Note that if that filename is already absolute, it may\r
+** still be returned in a modified form because this routine also\r
+** eliminates redundant slashes and single dots and eliminates double\r
+** dots to get a shortest possible filename from the given input\r
+** filename. The absolutization of relative filenames is made by\r
+** assuming that the given filename is to be taken as relative to\r
+** the first argument (cwd) or to the current directory if cwd is\r
+** NULL. \r
+*/\r
+\r
+/* A pointer to the current directory filename (used by abspath). */\r
+static /*@only@*/ cstring osd_cwd = cstring_undefined;\r
+\r
+static void osd_setWorkingDirectory (void)\r
+{\r
+# if defined (UNIX)\r
+ char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);\r
+ char *cwd = getcwd (buf, MAXPATHLEN);\r
+#else if defined (OS2)\r
+ char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);\r
+ char *cwd = _getcwd2 (buf, MAXPATHLEN);\r
+ char *slash;\r
+ while ((slash = strchr (cwd, '/')) != NULL)\r
+ {\r
+ *slash = '\\';\r
+ }\r
+#endif\r
+# if defined (UNIX) || defined (OS2)\r
+ llassert (cstring_isUndefined (osd_cwd));\r
+\r
+ if (cwd == NULL)\r
+ {\r
+ lldiagmsg (message ("Cannot get working directory: %s\n",\r
+ lldecodeerror (errno)));\r
+ osd_cwd = cstring_makeLiteral ("<missing directory>");\r
+ }\r
+ else\r
+ {\r
+ osd_cwd = cstring_fromCharsNew (cwd);\r
+ }\r
+\r
+ sfree (buf);\r
+# else\r
+ ; /* Don't know how to do this for non-POSIX platforms */\r
+# endif\r
+}\r
+\r
+void osd_initMod (void)\r
+{\r
+ osd_setWorkingDirectory ();\r
+}\r
+\r
+void osd_destroyMod (void)\r
+{\r
+ cstring_free (osd_cwd);\r
+ osd_cwd = cstring_undefined;\r
+}\r
+\r
+cstring osd_absolutePath (cstring cwd, cstring filename)\r
+{\r
+# if defined (UNIX) || defined (OS2)\r
+ /* Setup the current working directory as needed. */\r
+ cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;\r
+ char *abs_buffer;\r
+ char *endp, *outp, *inp;\r
+\r
+ /*@access cstring@*/\r
+ llassert (cstring_isDefined (cwd2));\r
+ llassert (cstring_isDefined (filename));\r
+\r
+ abs_buffer = (char *) dmalloc (cstring_length (cwd2) + cstring_length (filename) + 2);\r
+ endp = abs_buffer;\r
+ \r
+ /*\r
+ ** Copy the filename (possibly preceded by the current working\r
+ ** directory name) into the absolutization buffer. \r
+ */\r
+ \r
+ {\r
+ const char *src_p;\r
+\r
+ if (!osd_isConnectChar (filename[0])\r
+# ifdef OS2\r
+ && !(isalpha (filename[0]) && filename[1] == ':')\r
+# endif\r
+ )\r
+ {\r
+ src_p = cwd2;\r
+\r
+ while ((*endp++ = *src_p++) != '\0') \r
+ {\r
+ continue;\r
+ }\r
+\r
+ *(endp-1) = CONNECTCHAR; /* overwrite null */\r
+ }\r
+\r
+ src_p = filename;\r
+\r
+ while ((*endp++ = *src_p++) != '\0')\r
+ {\r
+ continue;\r
+ }\r
+ }\r
+ \r
+ /* Now make a copy of abs_buffer into abs_buffer, shortening the\r
+ filename (by taking out slashes and dots) as we go. */\r
+ \r
+ outp = inp = abs_buffer;\r
+ *outp++ = *inp++; /* copy first slash */\r
+#ifdef apollo\r
+ if (inp[0] == '/')\r
+ *outp++ = *inp++; /* copy second slash */\r
+#endif\r
+ for (;;)\r
+ {\r
+ if (inp[0] == '\0')\r
+ {\r
+ break;\r
+ }\r
+ else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))\r
+ {\r
+ inp++;\r
+ continue;\r
+ }\r
+ else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))\r
+ {\r
+ if (inp[1] == '\0')\r
+ {\r
+ break;\r
+ }\r
+ else if (osd_isConnectChar (inp[1]))\r
+ {\r
+ inp += 2;\r
+ continue;\r
+ }\r
+ else if ((inp[1] == '.') \r
+ && (inp[2] == '\0' || osd_isConnectChar (inp[2])))\r
+ {\r
+ inp += (osd_isConnectChar (inp[2])) ? 3 : 2;\r
+ outp -= 2;\r
+ \r
+ while (outp >= abs_buffer && !osd_isConnectChar (*outp))\r
+ {\r
+ outp--;\r
+ }\r
+\r
+ if (outp < abs_buffer)\r
+ {\r
+ /* Catch cases like /.. where we try to backup to a\r
+ point above the absolute root of the logical file\r
+ system. */\r
+ \r
+ llfatalbug (message ("Invalid file name: %s", filename));\r
+ }\r
+\r
+ *++outp = '\0';\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ *outp++ = *inp++;\r
+ }\r
+ \r
+ /* On exit, make sure that there is a trailing null, and make sure that\r
+ the last character of the returned string is *not* a slash. */\r
+ \r
+ *outp = '\0';\r
+ if (osd_isConnectChar (outp[-1]))\r
+ *--outp = '\0';\r
+ \r
+ /*@noaccess cstring@*/\r
+ return cstring_fromChars (abs_buffer);\r
+# else\r
+ DPRINTF (("Here: %s", filename));\r
+ return cstring_copy (filename);\r
+# endif\r
+}\r
+\r
+/* \r
+** Given a filename (and possibly a directory name from which the filename\r
+** is relative) return a string which is the shortest possible\r
+** equivalent for the corresponding full (absolutized) filename. The\r
+** shortest possible equivalent may be constructed by converting the\r
+** absolutized filename to be a relative filename (i.e. relative to\r
+** the actual current working directory). However if a relative filename\r
+** is longer, then the full absolute filename is returned.\r
+**\r
+** KNOWN BUG: subpart of the original filename is actually a symbolic link. \r
+**\r
+** this is really horrible code...surely someone has written a less buggy version of this!\r
+*/\r
+\r
+cstring osd_outputPath (cstring filename)\r
+{\r
+# if defined (UNIX) || defined (OS2)\r
+ char *rel_buffer;\r
+ char *rel_buf_p;\r
+ cstring cwd_p = osd_cwd;\r
+ char *path_p;\r
+ int unmatched_slash_count = 0;\r
+ size_t filename_len = cstring_length (filename);\r
+ \r
+ llassertretval (filename_len > 0, filename);\r
+\r
+ /*@access cstring@*/\r
+ path_p = filename;\r
+ rel_buffer = (char *) dmalloc (filename_len);\r
+ rel_buf_p = rel_buffer;\r
+ *rel_buf_p = '\0';\r
+\r
+ if (cwd_p == NULL) \r
+ {\r
+ /* Need to prevent recursive assertion failures */\r
+ return cstring_copy (filename);\r
+ }\r
+\r
+ llassert (cwd_p != NULL);\r
+ llassert (path_p != NULL);\r
+\r
+ while ((*cwd_p != '\0') && (*cwd_p == *path_p))\r
+ {\r
+ cwd_p++;\r
+ path_p++;\r
+ }\r
+ \r
+ if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p))) /* whole pwd matched */\r
+ {\r
+ if (*path_p == '\0') /* input *is* the current path! */\r
+ {\r
+ cstring_free (rel_buffer);\r
+ return cstring_makeLiteral (".");\r
+ }\r
+ else\r
+ {\r
+ cstring_free (rel_buffer);\r
+ return cstring_fromCharsNew (path_p + 1);\r
+ }\r
+ }\r
+ else\r
+ {\r
+\r
+ /* drl 2002-10/14 I had to put this code back*/\r
+ /* 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\r
+ */\r
+ \r
+ /* evans 2002-02-05 This is horrible code, which I've removed. I couldn't find any\r
+ ** test cases that need it, so I hope I'm not breaking anything.\r
+ */\r
+ /*#if 0*/\r
+\r
+ if (*path_p != '\0')\r
+ {\r
+ --cwd_p;\r
+ --path_p;\r
+\r
+ while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */\r
+ {\r
+ --cwd_p;\r
+ --path_p;\r
+ }\r
+ cwd_p++;\r
+ path_p++;\r
+ unmatched_slash_count++;\r
+ }\r
+\r
+ /* Find out how many directory levels in cwd were *not* matched. */\r
+ while (*cwd_p != '\0')\r
+ {\r
+ if (osd_isConnectChar (*cwd_p++))\r
+ unmatched_slash_count++;\r
+ }\r
+ \r
+ /* Now we know how long the "short name" will be.\r
+ Reject it if longer than the input. */\r
+ if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)\r
+ {\r
+ cstring_free (rel_buffer);\r
+ /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */\r
+ return cstring_copy (filename);\r
+ }\r
+\r
+ /*drl 10-14-2002 end previously removed code */\r
+ /*#endif*/\r
+ /* For each of them, put a `../' at the beginning of the short name. */\r
+ while (unmatched_slash_count-- > 0)\r
+ {\r
+ /* Give up if the result gets to be longer\r
+ than the absolute path name. */\r
+ char * temp_rel_buf_p;\r
+\r
+ /*drl This comment is necessary because for some reason Splint\r
+ does not realize that the pasts where rel_buf_p is released\r
+ do not reach here*/\r
+ /*@-usereleased@*/\r
+ temp_rel_buf_p = rel_buf_p;\r
+ /*@-usereleased@*/\r
+ \r
+ if (rel_buffer + filename_len <= temp_rel_buf_p + 3)\r
+ {\r
+ sfree (rel_buffer);\r
+ return cstring_copy (filename);\r
+ }\r
+\r
+ *rel_buf_p++ = '.';\r
+ *rel_buf_p++ = '.';\r
+ *rel_buf_p++ = CONNECTCHAR;\r
+ }\r
+ \r
+ /* Then tack on the unmatched part of the desired file's name. */\r
+\r
+ do\r
+ {\r
+ if (rel_buffer + filename_len <= rel_buf_p)\r
+ {\r
+ cstring_free (rel_buffer);\r
+ return cstring_copy (filename);\r
+ }\r
+ } /*@-usereleased@*/\r
+ while ((*rel_buf_p++ = *path_p++) != '\0') ;\r
+\r
+ \r
+ /*@=usereleased@*/ /* Splint limitation: shouldn't need these */\r
+ --rel_buf_p;\r
+\r
+ if (osd_isConnectChar (*(rel_buf_p-1)))\r
+ *--rel_buf_p = '\0';\r
+\r
+ /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */\r
+ return rel_buffer;\r
+ }\r
+ /*@noaccess cstring@*/\r
+# else\r
+ return cstring_copy (filename);\r
+# endif\r
+}\r
+\r
+cstring osd_getCurrentDirectory ()\r
+{\r
+# if defined(MSDOS) || defined(OS2)\r
+ return cstring_makeLiteralTemp ("");\r
+# else\r
+ return cstring_makeLiteralTemp ("./");\r
+# endif\r
+}\r
+\r
+\r
+\r