/*
-** LCLint - annotation-assisted static program checker
-** Copyright (C) 1994-2000 University of Virginia,
+** 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
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA.
**
-** For information on lclint: lclint-request@cs.virginia.edu
-** To report a bug: lclint-bug@cs.virginia.edu
-** For more information: http://lclint.cs.virginia.edu
+** For information on splint: info@splint.org
+** To report a bug: splint-bug@splint.org
+** For more information: http://www.splint.org
*/
/*
** osd.c
* - 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*/
# 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 "lclintMacros.nf"
+# include "splintMacros.nf"
# include "basic.h"
# include "osd.h"
-# include "portab.h"
/* from stat.h */
/*@ignore@*/
static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
/*@out@*/ size_t *p_len);
-extern char *LSLRootName (char *filespec)
+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, '.');
strncpy (result, startName, nameLength);
result[(int) nameLength] = '\0';
return result;
+ /*@noaccess cstring@*/
}
-extern /*@observer@*/ char *
-osd_getEnvironment (char *env, /*@returned@*/ char *def)
+extern /*@observer@*/ cstring
+osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
{
+ /*@access cstring@*/
char *ret = osd_getEnvironmentVariable (env);
if (ret == NULL)
{
return ret;
}
+ /*@noaccess cstring@*/
}
**--
*/
-extern /*@null@*/ /*@observer@*/ char *
- osd_getHomeDir ()
+extern /*@observer@*/ cstring osd_getHomeDir ()
{
/* Would something different be better for windows? */
- return (osd_getEnvironmentVariable ("HOME"));
+ return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
}
-filestatus osd_findOnLarchPath (char *file, char **returnPath)
+filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
{
- return (osd_getPath (cstring_toCharsSafe (context_getLarchPath ()), file, returnPath));
+ return (osd_getPath (context_getLarchPath (), file, returnPath));
}
extern filestatus
-osd_getPath (char *path, char *file, char **returnPath)
+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 (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] == ':')))
+ /* 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
-# ifdef WIN32
- (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':')))
-# else
- (*file == CONNECTCHAR))
-# endif
+ (*file == CONNECTCHAR)
# endif
+ )
{
- /* No path specified. Look for it in the current directory. */
-
+ /* No path specified. Look for it in the current directory. */
+
strcpy (&aPath[0], file);
-
+
if (osd_fileExists (&aPath[0]))
{
rVal = OSD_FILEFOUND;
}
else
{
- /* Path specified. Loop through directories in path looking for the */
- /* first occurrence of the file. */
-
- while (nextdir (&fullPath, &dirPtr, &dirLen) &&
- rVal == OSD_FILENOTFOUND)
+ /* 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. */
+ /* 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;
}
return rVal;
+ /*@noaccess cstring@*/
}
extern filestatus
-osd_getExePath (char *path, char *file, char **returnPath)
+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. */
-
- fullPath = osd_getEnvironmentVariable (path);
+ /*@access cstring@*/
+ *returnPath = cstring_undefined;
+ fullPath = osd_getEnvironmentVariable (path);
+
if (fullPath == NULL)
{
- /* No path specified. Look for it in the current directory. */
-
+ /* 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;
while (nextdir (&fullPath, &dirPtr, &dirLen) &&
rVal == OSD_FILENOTFOUND)
{
- if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
+ 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);
}
return rVal;
+ /*@noaccess cstring@*/
}
bool
-osd_fileExists (char *filespec)
+osd_fileExists (cstring filespec)
{
# ifdef UNIX
struct stat buf;
- return (stat (filespec, &buf) == 0);
+ return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
# else
-# ifdef WIN32
- FILE *test = fopen (filespec, "r");
+# if defined (WIN32) || defined (OS2)
+ FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
+
if (test != NULL)
- {
- (void) fclose (test);
- return TRUE;
- }
+ {
+ (void) fileTable_closeFile (context_fileTable (),test);
+ return TRUE;
+ }
else
- {
- return FALSE;
- }
+ {
+ 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 defined(__IBMC__) && defined(OS2)
-# define S_IFMT (unsigned short)0xFFFF
-# endif
+ struct stat buf;
if (stat (filespec, &buf) == 0)
{
/* mask by file type */
{
/* 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;
+ 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(MSDOS) && !defined(OS2)
+# if defined (S_IXGRP) && defined (S_IXOTH)
| (buf.st_mode & S_IXGRP) |
(buf.st_mode & S_IXOTH)
# endif
# endif
}
}
-
# endif
return (FALSE);
if (**current_dir == '\0')
{
*len = 0;
+ *dir = NULL;
return FALSE;
}
- *dir = (**current_dir == SEPCHAR ? *current_dir + 1 : *current_dir);
+ *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
/* Find next ':' or end of string */
- for (tchar = *dir; *tchar != '\0' && *tchar != SEPCHAR; tchar++)
+ for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
{
;
}
return TRUE;
}
-/*@observer@*/ /*@null@*/ char *osd_getEnvironmentVariable (char *var)
+/*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
{
-# ifdef UNIX
- return getenv (var);
-# else
-# if defined(OS2) || defined(MSDOS)
- return getenv (var);
-# else
-# if defined(WIN32)
- return getenv (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 NULL;
-# endif
-# endif
+ return cstring_undefined;
# endif
}
-# ifndef NOLCL
-
-# ifdef WIN32
+# 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 (const char *cmd)
+int osd_system (cstring cmd)
{
int res;
/* system ("printenv"); */
-# ifdef WIN32
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
(void) _flushall ();
# endif
- res = system (cmd);
+ res = system (cstring_toCharsSafe (cmd));
return res;
}
-# endif
# ifndef unlink
+/* This should be defined by unistd.h */
/*@-redecl@*/
extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
/*@=redecl@*/
# endif
-int osd_unlink (const char *fname)
+static bool s_tempError = FALSE;
+
+void osd_setTempError (void)
+{
+ s_tempError = TRUE;
+}
+
+int osd_unlink (cstring fname)
{
int res;
- res = unlink (fname);
+ res = unlink (cstring_toCharsSafe (fname));
if (res != 0)
{
- llcontbug (message ("Cannot remove temporary file: %s (%s)",
- cstring_fromChars (fname),
- cstring_fromChars (strerror (errno))));
+ if (!s_tempError)
+ {
+ llcontbug (message ("Cannot remove temporary file: %s (%s)",
+ fname,
+ cstring_fromChars (strerror (errno))));
+ }
}
return res;
}
-# ifdef WIN32
-# include <process.h>
-# endif
-
-# ifdef WIN32
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
int
# else
int /* pid_t */
# endif
osd_getPid ()
{
-# ifdef WIN32
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
int pid = _getpid ();
# else
- pid_t pid = getpid ();
+ __pid_t pid = getpid ();
# endif
return (int) pid;
}
-cstring osd_fixDefine (char *x)
+cstring osd_fixDefine (cstring x)
{
+ /*@access cstring@*/
+ llassert (cstring_isDefined (x));
# ifdef UNIX
if (strchr (x, '\'') != NULL) {
/*
# endif
- return cstring_fromCharsNew (x);
+ return cstring_copy (x);
+ /*@noaccess cstring@*/
}
-bool osd_fileIsReadable (char *f)
+bool osd_fileIsReadable (cstring f)
{
- FILE *fl = fopen (f, "r");
+ FILE *fl = fileTable_openReadFile (context_fileTable (), f);
- if (fl != (FILE *) 0)
+ if (fl != NULL)
{
- check (fclose (fl) == 0);
+ check (fileTable_closeFile (context_fileTable (), fl));
return (TRUE);
}
else
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
+}
+
+
+