2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
27 ** Provide a system-independent interface to system-dependent
32 * Modified by Herbert 04/19/97:
33 * - added conditional 'OS2' to conditional 'MSDOS'
34 * - added include of new header portab.h.
35 * - changed '/' to macro.
36 * - added DOS / OS/2 specific stuff in osd_getPath.
38 * - added OS/2 specific includes before osd_getPid()
39 * - handle files like in WIN32 for OS/2 in osd_fileExists()
41 * - added OS/2 support to absolute file names
46 # include <sys/types.h>
47 # include <sys/stat.h>
48 /* Fix suggested by Lars Rasmussen */
51 /* POSIX platforms should defined getpid in unistd.h */
52 # if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
55 # define getcwd _getcwd
62 # include "splintMacros.nf"
69 extern int stat (const char *, /*@out@*/ struct stat *);
72 static bool osd_executableFileExists (char *);
74 static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
75 /*@out@*/ size_t *p_len);
77 extern cstring LSLRootName (cstring filespec)
80 char *result, *startName, *tail;
83 llassert (cstring_isDefined (filespec));
84 tail = strrchr (filespec, CONNECTCHAR);
85 startName = (tail == NULL ? filespec : &tail[1]);
86 tail = strrchr (startName, '.');
87 nameLength = (tail == NULL ? strlen (startName)
88 : size_fromInt (tail - startName));
89 result = dmalloc (nameLength + 1);
90 strncpy (result, startName, nameLength);
91 result[(int) nameLength] = '\0';
93 /*@noaccess cstring@*/
96 extern /*@observer@*/ cstring
97 osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
100 char *ret = osd_getEnvironmentVariable (env);
110 /*@noaccess cstring@*/
116 ** FUNCTIONAL DESCRIPTION:
118 ** This function attempts to locate a file in a search list. On VMS, it
119 ** just concatinates the path and file names, and then lets RMS do the
120 ** searching. On Ultrix, it searches for the file on the path.
122 ** FORMAL PARAMETERS:
124 ** path: search path where to look for the file.
125 ** file: name of file to search for.
126 ** returnPath: if a file is found, this is where the concatenated
127 ** directory and file name are returned.
131 ** OSD_FILEFOUND: the file was found on the search list.
132 ** OSD_FILENOTFOUND the file was not found.
133 ** OSD_PATHTOOLONG the concatenated directory and file name are too
142 ** Requires that parameters, path and file, are valid C strings.
148 extern /*@observer@*/ cstring osd_getHomeDir ()
150 /* Would something different be better for windows? */
151 return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
154 filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
156 return (osd_getPath (context_getLarchPath (), file, returnPath));
160 osd_getPath (cstring path, cstring file, cstring *returnPath)
165 char aPath[MAXPATHLEN];
166 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
171 llassert (cstring_isDefined (file));
173 /* 2002-01-01: make sure returnPath gets defined even when there are errors.
174 ** (fixed splint checking detected this)
177 *returnPath = cstring_undefined;
181 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
182 /* under OS/2 and MSDOS the includePath may be empty, if so, search
183 * the current directory. */
185 (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
187 (*file == CONNECTCHAR)
191 /* No path specified. Look for it in the current directory. */
193 strcpy (&aPath[0], file);
195 if (osd_fileExists (&aPath[0]))
197 rVal = OSD_FILEFOUND;
198 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
199 strcpy (*returnPath, &aPath[0]);
204 /* Path specified. Loop through directories in path looking for the */
205 /* first occurrence of the file. */
207 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
208 rVal == OSD_FILENOTFOUND)
210 if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
212 /* Cat directory and filename, and see if file exists. */
213 strncpy (&aPath[0], dirPtr, dirLen);
214 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
215 strcat (&aPath[0], CONNECTSTR);
216 strcat (&aPath[0], file);
218 if (osd_fileExists (&aPath[0]))
220 rVal = OSD_FILEFOUND;
221 *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
222 strcpy (*returnPath, &aPath[0]);
227 rVal = OSD_PATHTOOLONG;
233 /*@noaccess cstring@*/
237 osd_getExePath (cstring path, cstring file, cstring *returnPath)
242 char aPath[MAXPATHLEN];
243 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
246 *returnPath = cstring_undefined;
247 fullPath = osd_getEnvironmentVariable (path);
249 if (fullPath == NULL)
251 /* No path specified. Look for it in the current directory. */
252 llassert (cstring_isDefined (file));
253 strcpy (&aPath[0], file);
255 if (osd_fileExists (&aPath[0]))
257 rVal = OSD_FILEFOUND;
258 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
259 strcpy (*returnPath, &aPath[0]);
265 ** Path specified. Loop through directories in path looking
266 ** for the first occurrence of the file.
269 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
270 rVal == OSD_FILENOTFOUND)
272 llassert (cstring_isDefined (file));
274 if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
276 /* Cat directory and filename, and see if file exists. */
277 strncpy (&aPath[0], dirPtr, dirLen);
278 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
279 strcat (&aPath[0], CONNECTSTR);
280 strcat (&aPath[0], file);
282 if (osd_executableFileExists (&aPath[0]))
284 rVal = OSD_FILEFOUND;
285 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
286 strcpy (*returnPath, &aPath[0]);
291 rVal = OSD_PATHTOOLONG;
297 /*@noaccess cstring@*/
301 osd_fileExists (cstring filespec)
305 return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
307 # if defined (WIN32) || defined (OS2)
308 FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
312 (void) fileTable_closeFile (context_fileTable (),test);
325 # if defined(__IBMC__) && defined(OS2)
326 # define S_IFMT (unsigned short)0xFFFF
330 ** Works form Win32 at least...
335 # define S_IXUSR _S_IEXEC
340 osd_executableFileExists (/*@unused@*/ char *filespec)
344 if (stat (filespec, &buf) == 0)
346 /* mask by file type */
347 /*@-unrecog@*/ /* S_IFMT is not defined */
348 if ((buf.st_mode & S_IFMT) != S_IFDIR /*@=unrecog@*/) /* not a directory */
350 /* as long as it is an executable file */
351 # if defined(__IBMC__) && defined(OS2)
352 int com_or_exe_pos = strlen( filespec) - 4;
353 return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
354 || stricmp( &filespec[com_or_exe_pos], ".com") == 0
355 || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
356 || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
358 return (((buf.st_mode & S_IXUSR)
359 # if defined (S_IXGRP) && defined (S_IXOTH)
360 | (buf.st_mode & S_IXGRP) |
361 (buf.st_mode & S_IXOTH)
374 ** FUNCTIONAL DESCRIPTION:
376 ** Find the next directory from a directory path.
378 ** FORMAL PARAMETERS:
380 ** char ** current_dir :
381 ** Points to the current position in the path string. The first time
382 ** you call this routine, this should point to the first character of
383 ** the path. On return, this will be updated to point to the
384 ** terminating \0 or : of the first directory found. You can then pass
385 ** it unchanged for subsequent calls; this routine will correctly skip
389 ** On exit, this will point to the first character of the directory
390 ** that was found. This will be a pointer directly into the client's
393 ** unsigned int * len :
394 ** On exit, this will contain the length of the directory that was
395 ** found, not counting any terminating \0 or :. If no directory was
396 ** found, this will be 0.
399 ** TRUE if we found another directory.
404 ** We return a pointer and length, rather than a string, because of a)
405 ** historical reasons; and b) this avoids having to allocate storage.
413 nextdir (d_char *current_dir, d_char *dir, size_t *len)
417 if (**current_dir == '\0')
424 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
426 /* Find next ':' or end of string */
427 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
432 *current_dir = tchar;
433 *len = size_fromInt (tchar - *dir);
437 /*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
439 /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
440 # if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
441 char *val = getenv (cstring_toCharsSafe (var));
445 return cstring_undefined;
449 return cstring_makeLiteralTemp (val);
452 return cstring_undefined;
457 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
461 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
463 int osd_system (cstring cmd)
466 /* system ("printenv"); */
471 res = system (cstring_toCharsSafe (cmd));
476 /* This should be defined by unistd.h */
478 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
482 static s_tempError = FALSE;
484 void osd_setTempError (void)
489 int osd_unlink (cstring fname)
493 res = unlink (cstring_toCharsSafe (fname));
499 llcontbug (message ("Cannot remove temporary file: %s (%s)",
501 cstring_fromChars (strerror (errno))));
508 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
515 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
516 int pid = _getpid ();
518 pid_t pid = getpid ();
524 cstring osd_fixDefine (cstring x)
527 llassert (cstring_isDefined (x));
529 if (strchr (x, '\'') != NULL) {
531 ** If there is a single quote, check for <ident>='<string>' and
532 ** produce <ident>=<string>
535 char *eqs = strchr (x, '=');
538 if (eqs[1] == '\'') {
539 char *endqu = strrchr (x, '\'');
542 if (*(endqu - 1) != '\\') {
543 if (*(endqu + 1) == '\0') {
548 def = cstring_fromChars (eqs + 2);
550 res = cstring_concat (cstring_fromChars (x), def);
561 return cstring_copy (x);
562 /*@noaccess cstring@*/
565 bool osd_fileIsReadable (cstring f)
567 FILE *fl = fileTable_openReadFile (context_fileTable (), f);
571 check (fileTable_closeFile (context_fileTable (), fl));
580 bool osd_isConnectChar (char c)
582 if (c == CONNECTCHAR)
587 # ifdef HASALTCONNECTCHAR
588 if (c == ALTCONNECTCHAR)
598 ** Returns true if c2 starts with the same path as c1
600 ** This is called by context_isSystemDir to determine if a
601 ** directory is on the system path.
603 ** In unix, this is just a string comparison. For Win32 and OS2, we need a more
604 ** complex comparison.
607 bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
609 llassert (cstring_isDefined (prefixpath));
611 if (cstring_isEmpty (dirpath))
613 return (cstring_isEmpty (prefixpath));
616 # if defined (WIN32) || defined (OS2)
618 /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
621 ** If one has a drive specification, but the other doesn't, skip it.
624 if (strchr (dirpath, ':') == NULL
625 && strchr (prefixpath, ':') != NULL)
627 prefixpath = strchr (prefixpath, ':') + 1;
631 if (strchr (prefixpath, ':') == NULL
632 && strchr (dirpath, ':') != NULL)
634 dirpath = strchr (dirpath, ':') + 1;
639 int len = size_toInt (strlen (prefixpath));
643 for (i = 0, slen = 0; i < len; i++, slen++)
645 /* Allow any number of connect characters in any combination:
646 * c:/usr//src\/foo == c:\\usr/src\/foo
647 * After this we'll be at the last of such a sequence */
649 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
651 /* Skip one or more connect chars */
653 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
658 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
663 /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
664 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
672 /*@noaccess cstring@*/
676 return (cstring_equalPrefix (dirpath, prefixpath));
682 ** This code provided by Herbert Martin Dietze, to canonicalize path names.
685 char *osd_getcwd (/*@returned@*/ char *str, size_t size)
687 return getcwd (str, size);
690 /*@null@*/ /*@observer@*/ char *
691 osd_dirNext (char *str)
693 char *p1 = strchr (str, '/');
694 char *p2 = strchr (str, '\\');
711 else /* both not null */
713 return (p1 < p2 ? p1 : p2) + 1;
718 osd_dirShift (char *str, size_t num) /*@modifies str@*/
722 assert (num <= strlen (str));
724 for (i = 0; str[i] != '\0'; i++)
726 str[i] = str[i + num];
731 osd_dirDotdot (char *str)
733 return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
737 osd_dirNormalize (char *str)
741 for (; osd_isConnectChar (str[0]); str++)
745 for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
749 for (pos1 = pos2 = str;
751 pos2 = pos1, pos1 = osd_dirNext (pos1))
753 /* remove redundant `./' entry */
754 while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
756 osd_dirShift (pos1, 2);
759 /* remove redundant `foo/../' entry */
760 if (osd_dirDotdot (pos1) && pos2 < pos1)
762 osd_dirShift (pos2, pos1 - pos2 + 1);
763 osd_dirNormalize (str);
769 osd_dirAbsolute (char *str)
772 size_t size = PATH_MAX * sizeof (*ret);
774 DPRINTF (("Absolute for: %s", str));
776 # if defined (WIN32) || defined (OS2) || defined (MSDOS)
777 if (strlen (str) > 1 && str[1] == ':')
780 ** Its a drive letter
783 ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
788 if (osd_isConnectChar (str[0]))
790 ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
795 ret = dmalloc (size);
797 ret = osd_getcwd (ret, size);
798 ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
805 strcat (ret, CONNECTSTR);
809 osd_dirNormalize (ret);
818 ** This code is adapted from:
820 ** 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
823 ** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
824 ** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
826 ** This file is part of GNU CC.
828 ** GNU CC is free software; you can redistribute it and/or modify
829 ** it under the terms of the GNU General Public License as published by
830 ** the Free Software Foundation; either version 2, or (at your option)
831 ** any later version.
833 ** GNU CC is distributed in the hope that it will be useful,
834 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
835 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
836 ** GNU General Public License for more details.
838 ** You should have received a copy of the GNU General Public License
839 ** along with GNU CC; see the file COPYING. If not, write to
840 ** the Free Software Foundation, 59 Temple Place - Suite 330,
841 ** Boston, MA 02111-1307, USA.
845 ** Return the absolutized filename for the given relative
846 ** filename. Note that if that filename is already absolute, it may
847 ** still be returned in a modified form because this routine also
848 ** eliminates redundant slashes and single dots and eliminates double
849 ** dots to get a shortest possible filename from the given input
850 ** filename. The absolutization of relative filenames is made by
851 ** assuming that the given filename is to be taken as relative to
852 ** the first argument (cwd) or to the current directory if cwd is
856 /* A pointer to the current directory filename (used by abspath). */
857 static /*@only@*/ cstring osd_cwd = cstring_undefined;
859 static void osd_setWorkingDirectory (void)
861 # if defined (UNIX) || defined (OS2)
862 char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
863 char *cwd = getcwd (buf, MAXPATHLEN);
865 llassert (cstring_isUndefined (osd_cwd));
869 lldiagmsg (message ("Cannot get working directory: %s\n",
870 lldecodeerror (errno)));
874 osd_cwd = cstring_fromCharsNew (cwd);
879 ; /* Don't know how to do this for non-POSIX platforms */
883 void osd_initMod (void)
885 osd_setWorkingDirectory ();
888 void osd_destroyMod (void)
890 cstring_free (osd_cwd);
891 osd_cwd = cstring_undefined;
894 cstring osd_absolutePath (cstring cwd, cstring filename)
896 # if defined (UNIX) || defined (OS2)
897 /* Setup the current working directory as needed. */
898 cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
900 char *endp, *outp, *inp;
903 llassert (cstring_isDefined (cwd2));
904 llassert (cstring_isDefined (filename));
906 abs_buffer = (char *) dmalloc (size_fromInt (cstring_length (cwd2) + cstring_length (filename) + 2));
910 ** Copy the filename (possibly preceded by the current working
911 ** directory name) into the absolutization buffer.
917 if (!osd_isConnectChar (filename[0])
919 && !(isalpha (filename[0]) && filename[1] == ':')
925 while ((*endp++ = *src_p++) != '\0')
930 *(endp-1) = CONNECTCHAR; /* overwrite null */
935 while ((*endp++ = *src_p++) != '\0')
941 /* Now make a copy of abs_buffer into abs_buffer, shortening the
942 filename (by taking out slashes and dots) as we go. */
944 outp = inp = abs_buffer;
945 *outp++ = *inp++; /* copy first slash */
948 *outp++ = *inp++; /* copy second slash */
956 else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
961 else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
967 else if (osd_isConnectChar (inp[1]))
972 else if ((inp[1] == '.')
973 && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
975 inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
978 while (outp >= abs_buffer && !osd_isConnectChar (*outp))
983 if (outp < abs_buffer)
985 /* Catch cases like /.. where we try to backup to a
986 point above the absolute root of the logical file
989 llfatalbug (message ("Invalid file name: %s", filename));
1008 /* On exit, make sure that there is a trailing null, and make sure that
1009 the last character of the returned string is *not* a slash. */
1012 if (osd_isConnectChar (outp[-1]))
1015 /*@noaccess cstring@*/
1016 return cstring_fromChars (abs_buffer);
1018 DPRINTF (("Here: %s", filename));
1019 return cstring_copy (filename);
1024 ** Given a filename (and possibly a directory name from which the filename
1025 ** is relative) return a string which is the shortest possible
1026 ** equivalent for the corresponding full (absolutized) filename. The
1027 ** shortest possible equivalent may be constructed by converting the
1028 ** absolutized filename to be a relative filename (i.e. relative to
1029 ** the actual current working directory). However if a relative filename
1030 ** is longer, then the full absolute filename is returned.
1032 ** KNOWN BUG: subpart of the original filename is actually a symbolic link.
1034 ** this is really horrible code...surely someone has written a less buggy version of this!
1037 cstring osd_outputPath (cstring filename)
1039 /*@i2534 fix this junky code once and for all! */
1040 # if defined (UNIX) || defined (OS2)
1043 cstring cwd_p = osd_cwd;
1045 int unmatched_slash_count = 0;
1046 size_t filename_len = cstring_length (filename);
1048 llassertretval (filename_len > 0, filename);
1050 /*@access cstring@*/
1052 rel_buffer = (char *) dmalloc (filename_len);
1053 rel_buf_p = rel_buffer;
1056 llassert (cwd_p != NULL);
1057 llassert (path_p != NULL);
1059 while ((*cwd_p != '\0') && (*cwd_p == *path_p))
1065 if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p))) /* whole pwd matched */
1067 if (*path_p == '\0') /* input *is* the current path! */
1069 cstring_free (rel_buffer);
1070 return cstring_makeLiteral (".");
1074 /*@i324 ! splint didn't report an errors for: return ++path_p; */
1075 cstring_free (rel_buffer);
1076 return cstring_fromCharsNew (path_p + 1);
1082 /* drl 2002-10/14 I had to put this code back*/
1083 /* 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
1086 /* evans 2002-02-05 This is horrible code, which I've removed. I couldn't find any
1087 ** test cases that need it, so I hope I'm not breaking anything.
1091 if (*path_p != '\0')
1096 while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */
1103 unmatched_slash_count++;
1106 /* Find out how many directory levels in cwd were *not* matched. */
1107 while (*cwd_p != '\0')
1109 if (osd_isConnectChar (*cwd_p++))
1110 unmatched_slash_count++;
1113 /* Now we know how long the "short name" will be.
1114 Reject it if longer than the input. */
1115 if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1117 cstring_free (rel_buffer);
1118 /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */
1119 return cstring_copy (filename);
1122 /*drl 10-14-2002 end previously removed code */
1124 /* For each of them, put a `../' at the beginning of the short name. */
1125 while (unmatched_slash_count-- > 0)
1127 /* Give up if the result gets to be longer
1128 than the absolute path name. */
1129 if (rel_buffer + filename_len <= rel_buf_p + 3)
1132 return cstring_copy (filename);
1137 *rel_buf_p++ = CONNECTCHAR;
1140 /* Then tack on the unmatched part of the desired file's name. */
1144 if (rel_buffer + filename_len <= rel_buf_p)
1146 cstring_free (rel_buffer);
1147 return cstring_copy (filename);
1149 } /*@-usereleased@*/
1150 while ((*rel_buf_p++ = *path_p++) != '\0') ;
1153 /*@=usereleased@*/ /*@i523! shouldn't need these */
1156 if (osd_isConnectChar (*(rel_buf_p-1)))
1157 *--rel_buf_p = '\0';
1159 /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */
1162 /*@noaccess cstring@*/
1164 return cstring_copy (filename);
1168 cstring osd_getCurrentDirectory ()
1170 # if defined(MSDOS) || defined(OS2)
1171 return cstring_makeLiteralTemp ("");
1173 return cstring_makeLiteralTemp ("./");