]> andersk Git - splint.git/blobdiff - src/osd.c
Fixed the OS/2 specific files for the latest release.
[splint.git] / src / osd.c
index ebe214a9ac2ec7a4e56f42d86530f344e13f5aa3..c37f1ea717020e9938afd020eda3e8448de6d358 100644 (file)
--- a/src/osd.c
+++ b/src/osd.c
-/*
-** 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;
-  /*@i3@*/ return (stat (cstring_toCharsSafe (filespec), &buf) == 0); /* spurious */
-# 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)
-{
-  /*@-compdestroy@*/ /* possible memory leaks here? */
-# ifdef UNIX
-  struct stat buf;
-  if (stat (filespec, &buf) == 0)
-    { 
-      /* mask by file type */
-      /*@-type@*/ /* confusion about __mode_t and mode_t types */
-      if ((buf.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ 
-       /*@=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;
-# 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); /* spurious */
-# endif
-       }
-    }
-# endif
-  return (FALSE); 
-  /*@=compdestroy@*/
-}
-
-/*
-**++
-**  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
This page took 0.115367 seconds and 4 git commands to generate.