2 ** Splint - annotation-assisted static program checker
\r
3 ** Copyright (C) 1994-2003 University of Virginia,
\r
4 ** Massachusetts Institute of Technology
\r
6 ** This program is free software; you can redistribute it and/or modify it
\r
7 ** under the terms of the GNU General Public License as published by the
\r
8 ** Free Software Foundation; either version 2 of the License, or (at your
\r
9 ** option) any later version.
\r
11 ** This program is distributed in the hope that it will be useful, but
\r
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
14 ** General Public License for more details.
\r
16 ** The GNU General Public License is available from http://www.gnu.org/ or
\r
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
\r
18 ** MA 02111-1307, USA.
\r
20 ** For information on splint: info@splint.org
\r
21 ** To report a bug: splint-bug@splint.org
\r
22 ** For more information: http://www.splint.org
\r
27 ** Provide a system-independent interface to system-dependent
\r
32 * Modified by Herbert 04/19/97:
\r
33 * - added conditional 'OS2' to conditional 'MSDOS'
\r
34 * - added include of new header portab.h.
\r
35 * - changed '/' to macro.
\r
36 * - added DOS / OS/2 specific stuff in osd_getPath.
\r
37 * Herbert 06/12/2000:
\r
38 * - added OS/2 specific includes before osd_getPid()
\r
39 * - handle files like in WIN32 for OS/2 in osd_fileExists()
\r
40 * Herbert 02/17/2002:
\r
41 * - added OS/2 support to absolute file names
\r
46 # include <sys/types.h>
\r
47 # include <sys/stat.h>
\r
48 /* Fix suggested by Lars Rasmussen */
\r
51 /* POSIX platforms should defined getpid in unistd.h */
\r
52 # if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
\r
53 # include <process.h>
\r
54 # include <direct.h>
\r
55 # define getcwd _getcwd
\r
57 # include <unistd.h>
\r
62 # include "splintMacros.nf"
\r
68 extern int stat (const char *, /*@out@*/ struct stat *);
\r
71 static bool osd_executableFileExists (char *);
\r
73 static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
\r
74 /*@out@*/ size_t *p_len);
\r
76 extern cstring LSLRootName (cstring filespec)
\r
78 /*@access cstring@*/
\r
79 char *result, *startName, *tail;
\r
82 llassert (cstring_isDefined (filespec));
\r
83 tail = strrchr (filespec, CONNECTCHAR);
\r
84 startName = (tail == NULL ? filespec : &tail[1]);
\r
85 tail = strrchr (startName, '.');
\r
86 nameLength = (tail == NULL ? strlen (startName)
\r
87 : size_fromInt (tail - startName));
\r
88 result = dmalloc (nameLength + 1);
\r
89 strncpy (result, startName, nameLength);
\r
90 result[(int) nameLength] = '\0';
\r
92 /*@noaccess cstring@*/
\r
95 extern /*@observer@*/ cstring
\r
96 osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
\r
98 /*@access cstring@*/
\r
99 char *ret = osd_getEnvironmentVariable (env);
\r
109 /*@noaccess cstring@*/
\r
115 ** FUNCTIONAL DESCRIPTION:
\r
117 ** This function attempts to locate a file in a search list. On VMS, it
\r
118 ** just concatinates the path and file names, and then lets RMS do the
\r
119 ** searching. On Ultrix, it searches for the file on the path.
\r
121 ** FORMAL PARAMETERS:
\r
123 ** path: search path where to look for the file.
\r
124 ** file: name of file to search for.
\r
125 ** returnPath: if a file is found, this is where the concatenated
\r
126 ** directory and file name are returned.
\r
130 ** OSD_FILEFOUND: the file was found on the search list.
\r
131 ** OSD_FILENOTFOUND the file was not found.
\r
132 ** OSD_PATHTOOLONG the concatenated directory and file name are too
\r
141 ** Requires that parameters, path and file, are valid C strings.
\r
147 extern /*@observer@*/ cstring osd_getHomeDir ()
\r
149 /* Would something different be better for windows? */
\r
150 return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
\r
153 filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
\r
155 return (osd_getPath (context_getLarchPath (), file, returnPath));
\r
159 osd_getPath (cstring path, cstring file, cstring *returnPath)
\r
164 char aPath[MAXPATHLEN];
\r
165 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
\r
167 /*@access cstring@*/
\r
170 llassert (cstring_isDefined (file));
\r
172 /* 2002-01-01: make sure returnPath gets defined even when there are errors.
\r
173 ** (fixed splint checking detected this)
\r
176 *returnPath = cstring_undefined;
\r
178 if (fullPath == NULL
\r
180 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
\r
181 /* under OS/2 and MSDOS the includePath may be empty, if so, search
\r
182 * the current directory. */
\r
183 *fullPath == '\0' ||
\r
184 (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
\r
186 (*file == CONNECTCHAR)
\r
190 /* No path specified. Look for it in the current directory. */
\r
192 strcpy (&aPath[0], file);
\r
194 if (osd_fileExists (&aPath[0]))
\r
196 rVal = OSD_FILEFOUND;
\r
197 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
\r
198 strcpy (*returnPath, &aPath[0]);
\r
203 /* Path specified. Loop through directories in path looking for the */
\r
204 /* first occurrence of the file. */
\r
206 while (nextdir (&fullPath, &dirPtr, &dirLen)
\r
207 && rVal == OSD_FILENOTFOUND)
\r
209 if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
\r
211 /* Cat directory and filename, and see if file exists. */
\r
212 strncpy (&aPath[0], dirPtr, dirLen);
\r
213 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
\r
214 strcat (&aPath[0], CONNECTSTR);
\r
215 strcat (&aPath[0], file);
\r
217 if (osd_fileExists (&aPath[0]))
\r
219 rVal = OSD_FILEFOUND;
\r
220 *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
\r
221 strcpy (*returnPath, &aPath[0]);
\r
226 rVal = OSD_PATHTOOLONG;
\r
232 /*@noaccess cstring@*/
\r
236 osd_getExePath (cstring path, cstring file, cstring *returnPath)
\r
241 char aPath[MAXPATHLEN];
\r
242 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
\r
243 /*@access cstring@*/
\r
245 *returnPath = cstring_undefined;
\r
246 fullPath = osd_getEnvironmentVariable (path);
\r
248 if (fullPath == NULL)
\r
250 /* No path specified. Look for it in the current directory. */
\r
251 llassert (cstring_isDefined (file));
\r
252 strcpy (&aPath[0], file);
\r
254 if (osd_fileExists (&aPath[0]))
\r
256 rVal = OSD_FILEFOUND;
\r
257 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
\r
258 strcpy (*returnPath, &aPath[0]);
\r
264 ** Path specified. Loop through directories in path looking
\r
265 ** for the first occurrence of the file.
\r
268 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
\r
269 rVal == OSD_FILENOTFOUND)
\r
271 llassert (cstring_isDefined (file));
\r
273 if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
\r
275 /* Cat directory and filename, and see if file exists. */
\r
276 strncpy (&aPath[0], dirPtr, dirLen);
\r
277 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
\r
278 strcat (&aPath[0], CONNECTSTR);
\r
279 strcat (&aPath[0], file);
\r
281 if (osd_executableFileExists (&aPath[0]))
\r
283 rVal = OSD_FILEFOUND;
\r
284 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
\r
285 strcpy (*returnPath, &aPath[0]);
\r
290 rVal = OSD_PATHTOOLONG;
\r
296 /*@noaccess cstring@*/
\r
300 osd_fileExists (cstring filespec)
\r
304 /*@i3@*/ return (stat (cstring_toCharsSafe (filespec), &buf) == 0); /* spurious */
\r
306 # if defined (WIN32) || defined (OS2)
\r
307 FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
\r
311 (void) fileTable_closeFile (context_fileTable (),test);
\r
324 # if defined(__IBMC__) && defined(OS2)
\r
325 # define S_IFMT (unsigned short)0xFFFF
\r
329 ** Works form Win32 at least...
\r
333 /*@-macrounrecog@*/
\r
334 # define S_IXUSR _S_IEXEC
\r
335 /*@=macrounrecog@*/
\r
339 osd_executableFileExists (/*@unused@*/ char *filespec)
\r
341 /*@-compdestroy@*/ /* possible memory leaks here? */
\r
344 if (stat (filespec, &buf) == 0)
\r
346 /* mask by file type */
\r
347 /*@-type@*/ /* confusion about __mode_t and mode_t types */
\r
348 if ((buf.st_mode & S_IFMT) != S_IFDIR) /* not a directory */
\r
351 /* as long as it is an executable file */
\r
352 # if defined(__IBMC__) && defined(OS2)
\r
353 int com_or_exe_pos = strlen( filespec) - 4;
\r
354 return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
\r
355 || stricmp( &filespec[com_or_exe_pos], ".com") == 0
\r
356 || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
\r
357 || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
\r
359 return (((buf.st_mode & S_IXUSR)
\r
360 # if defined (S_IXGRP) && defined (S_IXOTH)
\r
361 | (buf.st_mode & S_IXGRP) |
\r
362 (buf.st_mode & S_IXOTH)
\r
364 ) != 0); /* spurious */
\r
375 ** FUNCTIONAL DESCRIPTION:
\r
377 ** Find the next directory from a directory path.
\r
379 ** FORMAL PARAMETERS:
\r
381 ** char ** current_dir :
\r
382 ** Points to the current position in the path string. The first time
\r
383 ** you call this routine, this should point to the first character of
\r
384 ** the path. On return, this will be updated to point to the
\r
385 ** terminating \0 or : of the first directory found. You can then pass
\r
386 ** it unchanged for subsequent calls; this routine will correctly skip
\r
390 ** On exit, this will point to the first character of the directory
\r
391 ** that was found. This will be a pointer directly into the client's
\r
394 ** unsigned int * len :
\r
395 ** On exit, this will contain the length of the directory that was
\r
396 ** found, not counting any terminating \0 or :. If no directory was
\r
397 ** found, this will be 0.
\r
400 ** TRUE if we found another directory.
\r
401 ** FALSE otherwise.
\r
405 ** We return a pointer and length, rather than a string, because of a)
\r
406 ** historical reasons; and b) this avoids having to allocate storage.
\r
414 nextdir (d_char *current_dir, d_char *dir, size_t *len)
\r
418 if (**current_dir == '\0')
\r
425 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
\r
427 /* Find next ':' or end of string */
\r
428 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
\r
433 *current_dir = tchar;
\r
434 *len = size_fromInt (tchar - *dir);
\r
438 /*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
\r
440 /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
\r
441 # if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
\r
442 char *val = getenv (cstring_toCharsSafe (var));
\r
446 return cstring_undefined;
\r
450 return cstring_makeLiteralTemp (val);
\r
453 return cstring_undefined;
\r
457 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
\r
458 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
\r
462 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
\r
464 int osd_system (cstring cmd)
\r
467 /* system ("printenv"); */
\r
468 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
\r
469 (void) _flushall ();
\r
472 res = system (cstring_toCharsSafe (cmd));
\r
477 /* This should be defined by unistd.h */
\r
479 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
\r
483 static bool s_tempError = FALSE;
\r
485 void osd_setTempError (void)
\r
487 s_tempError = TRUE;
\r
490 int osd_unlink (cstring fname)
\r
494 res = unlink (cstring_toCharsSafe (fname));
\r
500 llcontbug (message ("Cannot remove temporary file: %s (%s)",
\r
502 cstring_fromChars (strerror (errno))));
\r
509 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
\r
516 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
\r
517 int pid = _getpid ();
\r
519 __pid_t pid = getpid ();
\r
525 cstring osd_fixDefine (cstring x)
\r
527 /*@access cstring@*/
\r
528 llassert (cstring_isDefined (x));
\r
530 if (strchr (x, '\'') != NULL) {
\r
532 ** If there is a single quote, check for <ident>='<string>' and
\r
533 ** produce <ident>=<string>
\r
536 char *eqs = strchr (x, '=');
\r
539 if (eqs[1] == '\'') {
\r
540 char *endqu = strrchr (x, '\'');
\r
542 if (endqu != NULL) {
\r
543 if (*(endqu - 1) != '\\') {
\r
544 if (*(endqu + 1) == '\0') {
\r
549 def = cstring_fromChars (eqs + 2);
\r
551 res = cstring_concat (cstring_fromChars (x), def);
\r
562 return cstring_copy (x);
\r
563 /*@noaccess cstring@*/
\r
566 bool osd_fileIsReadable (cstring f)
\r
568 FILE *fl = fileTable_openReadFile (context_fileTable (), f);
\r
572 check (fileTable_closeFile (context_fileTable (), fl));
\r
581 bool osd_isConnectChar (char c)
\r
583 if (c == CONNECTCHAR)
\r
588 # ifdef HASALTCONNECTCHAR
\r
589 if (c == ALTCONNECTCHAR)
\r
599 ** Returns true if c2 starts with the same path as c1
\r
601 ** This is called by context_isSystemDir to determine if a
\r
602 ** directory is on the system path.
\r
604 ** In unix, this is just a string comparison. For Win32 and OS2, we need a more
\r
605 ** complex comparison.
\r
608 bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
\r
610 llassert (cstring_isDefined (prefixpath));
\r
612 if (cstring_isEmpty (dirpath))
\r
614 return (cstring_isEmpty (prefixpath));
\r
617 # if defined (WIN32) || defined (OS2)
\r
619 /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
\r
622 ** If one has a drive specification, but the other doesn't, skip it.
\r
625 if (strchr (dirpath, ':') == NULL
\r
626 && strchr (prefixpath, ':') != NULL)
\r
628 prefixpath = strchr (prefixpath, ':') + 1;
\r
632 if (strchr (prefixpath, ':') == NULL
\r
633 && strchr (dirpath, ':') != NULL)
\r
635 dirpath = strchr (dirpath, ':') + 1;
\r
640 int len = size_toInt (strlen (prefixpath));
\r
644 for (i = 0, slen = 0; i < len; i++, slen++)
\r
646 /* Allow any number of connect characters in any combination:
\r
647 * c:/usr//src\/foo == c:\\usr/src\/foo
\r
648 * After this we'll be at the last of such a sequence */
\r
650 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
\r
652 /* Skip one or more connect chars */
\r
654 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
\r
659 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
\r
664 /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
\r
665 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
\r
673 /*@noaccess cstring@*/
\r
677 return (cstring_equalPrefix (dirpath, prefixpath));
\r
683 ** This code provided by Herbert Martin Dietze, to canonicalize path names.
\r
686 char *osd_getcwd (/*@returned@*/ char *str, size_t size)
\r
688 return getcwd (str, size);
\r
691 /*@null@*/ /*@observer@*/ char *
\r
692 osd_dirNext (char *str)
\r
694 char *p1 = strchr (str, '/');
\r
695 char *p2 = strchr (str, '\\');
\r
708 else if (p2 == NULL)
\r
712 else /* both not null */
\r
714 return (p1 < p2 ? p1 : p2) + 1;
\r
719 osd_dirShift (char *str, size_t num) /*@modifies str@*/
\r
723 assert (num <= strlen (str));
\r
725 for (i = 0; str[i] != '\0'; i++)
\r
727 str[i] = str[i + num];
\r
732 osd_dirDotdot (char *str)
\r
734 return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
\r
738 osd_dirNormalize (char *str)
\r
742 for (; osd_isConnectChar (str[0]); str++)
\r
746 for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
\r
750 for (pos1 = pos2 = str;
\r
752 pos2 = pos1, pos1 = osd_dirNext (pos1))
\r
754 /* remove redundant `./' entry */
\r
755 while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
\r
757 osd_dirShift (pos1, 2);
\r
760 /* remove redundant `foo/../' entry */
\r
761 if (osd_dirDotdot (pos1) && pos2 < pos1)
\r
763 osd_dirShift (pos2, pos1 - pos2 + 1);
\r
764 osd_dirNormalize (str);
\r
770 osd_dirAbsolute (char *str)
\r
773 size_t size = PATH_MAX * sizeof (*ret);
\r
775 DPRINTF (("Absolute for: %s", str));
\r
777 # if defined (WIN32) || defined (OS2) || defined (MSDOS)
\r
778 if (strlen (str) > 1 && str[1] == ':')
\r
781 ** Its a drive letter
\r
784 ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
\r
789 if (osd_isConnectChar (str[0]))
\r
791 ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
\r
796 ret = dmalloc (size);
\r
798 ret = osd_getcwd (ret, size);
\r
799 ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
\r
806 strcat (ret, CONNECTSTR);
\r
810 osd_dirNormalize (ret);
\r
819 ** This code is adapted from:
\r
821 ** 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
824 ** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
\r
825 ** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
\r
827 ** This file is part of GNU CC.
\r
829 ** GNU CC is free software; you can redistribute it and/or modify
\r
830 ** it under the terms of the GNU General Public License as published by
\r
831 ** the Free Software Foundation; either version 2, or (at your option)
\r
832 ** any later version.
\r
834 ** GNU CC is distributed in the hope that it will be useful,
\r
835 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
836 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
837 ** GNU General Public License for more details.
\r
839 ** You should have received a copy of the GNU General Public License
\r
840 ** along with GNU CC; see the file COPYING. If not, write to
\r
841 ** the Free Software Foundation, 59 Temple Place - Suite 330,
\r
842 ** Boston, MA 02111-1307, USA.
\r
846 ** Return the absolutized filename for the given relative
\r
847 ** filename. Note that if that filename is already absolute, it may
\r
848 ** still be returned in a modified form because this routine also
\r
849 ** eliminates redundant slashes and single dots and eliminates double
\r
850 ** dots to get a shortest possible filename from the given input
\r
851 ** filename. The absolutization of relative filenames is made by
\r
852 ** assuming that the given filename is to be taken as relative to
\r
853 ** the first argument (cwd) or to the current directory if cwd is
\r
857 /* A pointer to the current directory filename (used by abspath). */
\r
858 static /*@only@*/ cstring osd_cwd = cstring_undefined;
\r
860 static void osd_setWorkingDirectory (void)
\r
862 # if defined (UNIX)
\r
863 char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
\r
864 char *cwd = getcwd (buf, MAXPATHLEN);
\r
865 #else if defined (OS2)
\r
866 char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
\r
867 char *cwd = _getcwd2 (buf, MAXPATHLEN);
\r
869 while ((slash = strchr (cwd, '/')) != NULL)
\r
874 # if defined (UNIX) || defined (OS2)
\r
875 llassert (cstring_isUndefined (osd_cwd));
\r
879 lldiagmsg (message ("Cannot get working directory: %s\n",
\r
880 lldecodeerror (errno)));
\r
881 osd_cwd = cstring_makeLiteral ("<missing directory>");
\r
885 osd_cwd = cstring_fromCharsNew (cwd);
\r
890 ; /* Don't know how to do this for non-POSIX platforms */
\r
894 void osd_initMod (void)
\r
896 osd_setWorkingDirectory ();
\r
899 void osd_destroyMod (void)
\r
901 cstring_free (osd_cwd);
\r
902 osd_cwd = cstring_undefined;
\r
905 cstring osd_absolutePath (cstring cwd, cstring filename)
\r
907 # if defined (UNIX) || defined (OS2)
\r
908 /* Setup the current working directory as needed. */
\r
909 cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
\r
911 char *endp, *outp, *inp;
\r
913 /*@access cstring@*/
\r
914 llassert (cstring_isDefined (cwd2));
\r
915 llassert (cstring_isDefined (filename));
\r
917 abs_buffer = (char *) dmalloc (cstring_length (cwd2) + cstring_length (filename) + 2);
\r
921 ** Copy the filename (possibly preceded by the current working
\r
922 ** directory name) into the absolutization buffer.
\r
928 if (!osd_isConnectChar (filename[0])
\r
930 && !(isalpha (filename[0]) && filename[1] == ':')
\r
936 while ((*endp++ = *src_p++) != '\0')
\r
941 *(endp-1) = CONNECTCHAR; /* overwrite null */
\r
946 while ((*endp++ = *src_p++) != '\0')
\r
952 /* Now make a copy of abs_buffer into abs_buffer, shortening the
\r
953 filename (by taking out slashes and dots) as we go. */
\r
955 outp = inp = abs_buffer;
\r
956 *outp++ = *inp++; /* copy first slash */
\r
959 *outp++ = *inp++; /* copy second slash */
\r
963 if (inp[0] == '\0')
\r
967 else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
\r
972 else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
\r
974 if (inp[1] == '\0')
\r
978 else if (osd_isConnectChar (inp[1]))
\r
983 else if ((inp[1] == '.')
\r
984 && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
\r
986 inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
\r
989 while (outp >= abs_buffer && !osd_isConnectChar (*outp))
\r
994 if (outp < abs_buffer)
\r
996 /* Catch cases like /.. where we try to backup to a
\r
997 point above the absolute root of the logical file
\r
1000 llfatalbug (message ("Invalid file name: %s", filename));
\r
1019 /* On exit, make sure that there is a trailing null, and make sure that
\r
1020 the last character of the returned string is *not* a slash. */
\r
1023 if (osd_isConnectChar (outp[-1]))
\r
1026 /*@noaccess cstring@*/
\r
1027 return cstring_fromChars (abs_buffer);
\r
1029 DPRINTF (("Here: %s", filename));
\r
1030 return cstring_copy (filename);
\r
1035 ** Given a filename (and possibly a directory name from which the filename
\r
1036 ** is relative) return a string which is the shortest possible
\r
1037 ** equivalent for the corresponding full (absolutized) filename. The
\r
1038 ** shortest possible equivalent may be constructed by converting the
\r
1039 ** absolutized filename to be a relative filename (i.e. relative to
\r
1040 ** the actual current working directory). However if a relative filename
\r
1041 ** is longer, then the full absolute filename is returned.
\r
1043 ** KNOWN BUG: subpart of the original filename is actually a symbolic link.
\r
1045 ** this is really horrible code...surely someone has written a less buggy version of this!
\r
1048 cstring osd_outputPath (cstring filename)
\r
1050 # if defined (UNIX) || defined (OS2)
\r
1053 cstring cwd_p = osd_cwd;
\r
1055 int unmatched_slash_count = 0;
\r
1056 size_t filename_len = cstring_length (filename);
\r
1058 llassertretval (filename_len > 0, filename);
\r
1060 /*@access cstring@*/
\r
1061 path_p = filename;
\r
1062 rel_buffer = (char *) dmalloc (filename_len);
\r
1063 rel_buf_p = rel_buffer;
\r
1064 *rel_buf_p = '\0';
\r
1066 if (cwd_p == NULL)
\r
1068 /* Need to prevent recursive assertion failures */
\r
1069 return cstring_copy (filename);
\r
1072 llassert (cwd_p != NULL);
\r
1073 llassert (path_p != NULL);
\r
1075 while ((*cwd_p != '\0') && (*cwd_p == *path_p))
\r
1081 if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p))) /* whole pwd matched */
\r
1083 if (*path_p == '\0') /* input *is* the current path! */
\r
1085 cstring_free (rel_buffer);
\r
1086 return cstring_makeLiteral (".");
\r
1090 cstring_free (rel_buffer);
\r
1091 return cstring_fromCharsNew (path_p + 1);
\r
1097 /* drl 2002-10/14 I had to put this code back*/
\r
1098 /* 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
1101 /* evans 2002-02-05 This is horrible code, which I've removed. I couldn't find any
\r
1102 ** test cases that need it, so I hope I'm not breaking anything.
\r
1106 if (*path_p != '\0')
\r
1111 while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */
\r
1118 unmatched_slash_count++;
\r
1121 /* Find out how many directory levels in cwd were *not* matched. */
\r
1122 while (*cwd_p != '\0')
\r
1124 if (osd_isConnectChar (*cwd_p++))
\r
1125 unmatched_slash_count++;
\r
1128 /* Now we know how long the "short name" will be.
\r
1129 Reject it if longer than the input. */
\r
1130 if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
\r
1132 cstring_free (rel_buffer);
\r
1133 /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */
\r
1134 return cstring_copy (filename);
\r
1137 /*drl 10-14-2002 end previously removed code */
\r
1139 /* For each of them, put a `../' at the beginning of the short name. */
\r
1140 while (unmatched_slash_count-- > 0)
\r
1142 /* Give up if the result gets to be longer
\r
1143 than the absolute path name. */
\r
1144 char * temp_rel_buf_p;
\r
1146 /*drl This comment is necessary because for some reason Splint
\r
1147 does not realize that the pasts where rel_buf_p is released
\r
1148 do not reach here*/
\r
1149 /*@-usereleased@*/
\r
1150 temp_rel_buf_p = rel_buf_p;
\r
1151 /*@-usereleased@*/
\r
1153 if (rel_buffer + filename_len <= temp_rel_buf_p + 3)
\r
1155 sfree (rel_buffer);
\r
1156 return cstring_copy (filename);
\r
1159 *rel_buf_p++ = '.';
\r
1160 *rel_buf_p++ = '.';
\r
1161 *rel_buf_p++ = CONNECTCHAR;
\r
1164 /* Then tack on the unmatched part of the desired file's name. */
\r
1168 if (rel_buffer + filename_len <= rel_buf_p)
\r
1170 cstring_free (rel_buffer);
\r
1171 return cstring_copy (filename);
\r
1173 } /*@-usereleased@*/
\r
1174 while ((*rel_buf_p++ = *path_p++) != '\0') ;
\r
1177 /*@=usereleased@*/ /* Splint limitation: shouldn't need these */
\r
1180 if (osd_isConnectChar (*(rel_buf_p-1)))
\r
1181 *--rel_buf_p = '\0';
\r
1183 /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */
\r
1184 return rel_buffer;
\r
1186 /*@noaccess cstring@*/
\r
1188 return cstring_copy (filename);
\r
1192 cstring osd_getCurrentDirectory ()
\r
1194 # if defined(MSDOS) || defined(OS2)
\r
1195 return cstring_makeLiteralTemp ("");
\r
1197 return cstring_makeLiteralTemp ("./");
\r