Various minor fixes for compiler/linter (other then splint itself) warnings.
[splint-patched.git] / src / osd.c
blob466b3f7c5ff04f492e7548be5f559efb37adbd07
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
5 **
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.
10 **
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.
15 **
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
25 ** osd.c
27 ** Provide a system-independent interface to system-dependent
28 ** file operations.
32 * Modified by Herbert 04/19/97:
33 * - added conditional 'OS2'
34 * - added include of new header portab.h.
35 * - changed occurance of '/' as path delimiter to a macro.
36 * - added DOS / OS/2 specific stuff in osd_getPath.
37 * Herbert 06/12/2000:
38 * - added OS/2 specific includes before osd_getPid()
39 * - handle files like in WIN32 for OS/2 in osd_fileExists()
40 * Herbert 02/17/2002:
41 * - added OS/2 support to absolute file names
44 /*@-allmacros*/
45 /*@ignore@*/
46 # include <sys/types.h>
47 # include <sys/stat.h>
48 # include <fcntl.h>
49 /* Fix suggested by Lars Rasmussen */
50 # include <errno.h>
52 # if defined(WIN32)
53 # include <windows.h>
54 # include <process.h>
55 # include <direct.h>
56 # include <io.h> /* _open() */
57 # define open(pathname, flags, mode) _open(pathname, flags, mode)
58 # define getpid() _getpid()
59 # define getcwd(buf, size) _getcwd(buf, size)
60 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
61 # else
62 # include <unistd.h>
63 # endif
65 # ifndef system
66 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
67 # endif
69 # ifndef unlink
70 /* This should be defined by unistd.h */
71 /*@-redecl@*/
72 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
73 /*@=redecl@*/
74 # endif
77 /*@end@*/
78 /*@=allmacros*/
79 # include "splintMacros.nf"
80 # include "basic.h"
81 # include "osd.h"
84 # if defined (WIN32)
85 /*@constant observer char *DEFAULT_TMPDIR; @*/
86 # define DEFAULT_TMPDIR "\\WINDOWS\\TEMP\\"
87 # elif defined(P_tmpdir)
88 /*@constant observer char *DEFAULT_TMPDIR; @*/
89 # define DEFAULT_TMPDIR P_tmpdir
90 # else
91 /*@constant observer char *DEFAULT_TMPDIR; @*/
92 # define DEFAULT_TMPDIR "/tmp/"
93 # endif
95 # if defined (OS2) || defined (WIN32)
96 /*@constant char ALTCONNECTCHAR@*/
97 # define ALTCONNECTCHAR '/'
98 /*@constant char DRIVECONNECTCHAR@*/
99 # define DRIVECONNECTCHAR ':'
100 # endif
103 ** MAXPATHLEN defines the longest permissable path length.
105 ** POSIX defines PATHMAX in limits.h
108 # if defined (PATH_MAX)
109 /*@constant size_t MAXPATHLEN; @*/
110 # define MAXPATHLEN PATH_MAX
111 # else
112 /*@constant size_t MAXPATHLEN; @*/
113 # define MAXPATHLEN 1024
114 # endif
116 #ifndef S_ISREG
117 /*@-macrounrecog@*/
118 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
119 /*@=macrounrecog@*/
120 #endif
122 #ifndef S_ISDIR
123 /*@-macrounrecog@*/
124 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
125 /*@=macrounrecog@*/
126 #endif
128 # ifndef S_IWUSR
129 /*@-macrounrecog@*/
130 # define S_IWUSR _S_IWRITE
131 /*@=macrounrecog@*/
132 # endif
134 # ifndef S_IRUSR
135 /*@-macrounrecog@*/
136 # define S_IRUSR _S_IREAD
137 /*@=macrounrecog@*/
138 # endif
141 # if defined (S_IRUSR) && defined (S_IWUSR) && \
142 defined (S_IRGRP) && defined (S_IWGRP) && \
143 defined (S_IROTH) && defined (S_IWOTH)
144 # define S_IRWALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
145 # else
146 # define 0666
147 # endif
149 #ifndef O_RDONLY
150 #define O_RDONLY 0
151 #endif
154 bool
155 osd_fileExists (cstring filespec)
157 # if defined (WIN32) || defined (OS2)
158 FILE *test = fileTable_openReadFile (context_fileTable (), filespec);
160 if (test != NULL)
162 (void) fileTable_closeFile (context_fileTable (),test);
163 return TRUE;
165 else
167 return FALSE;
169 # else
170 struct stat buf;
171 /*@i3@*/ return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
172 # endif
175 bool
176 osd_fileIsReadable (cstring f)
178 # if defined (WIN32) || defined (OS2)
179 FILE *fl = fileTable_openReadFile (context_fileTable (), f);
181 if (fl != NULL)
183 check (fileTable_closeFile (context_fileTable (), fl));
184 return (TRUE);
186 else
188 return (FALSE);
190 #else
191 struct stat buf;
192 /*@i3@*/ return (stat (cstring_toCharsSafe (f), &buf) == 0 && S_ISREG(buf.st_mode));
193 #endif
196 static bool
197 osd_fileIsExecutable (/*@unused@*/ char *filespec)
199 /*@-compdestroy@*/ /* possible memory leaks here? */
200 struct stat buf;
201 if (stat (filespec, &buf) == 0)
203 /* mask by file type */
204 /*@-type@*/ /* confusion about __mode_t and mode_t types */
205 if (!S_ISDIR(buf.st_mode))
206 /*@=type@*/
208 /* as long as it is an executable file */
209 # if defined (WIN32)
210 int com_or_exe_pos = strlen( filespec) - 4;
211 return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
212 || stricmp( &filespec[com_or_exe_pos], ".com") == 0
213 || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
214 || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
215 # else
216 return (((buf.st_mode & S_IXUSR)
217 # if defined (S_IXGRP) && defined (S_IXOTH)
218 | (buf.st_mode & S_IXGRP)
219 | (buf.st_mode & S_IXOTH)
220 # endif
221 ) != 0);
222 # endif
225 return (FALSE);
226 /*@=compdestroy@*/
229 cstring osd_pathListConcat (const char* p0, const char* p1)
231 char *res;
232 size_t l0, l1;
234 llassert (p0 != NULL && p1 != NULL);
236 l0 = strlen (p0);
237 l1 = strlen (p1);
239 res = dmalloc (l0 + 1 + l1 + 1);
240 strcpy (res, p0);
241 res[l0] = PATH_SEPARATOR;
242 strcpy (res + l0 + 1, p1);
244 return cstring_fromChars (res);
248 **++
249 ** FUNCTIONAL DESCRIPTION:
251 ** Find the next directory from a directory path.
253 ** FORMAL PARAMETERS:
255 ** char ** current_dir :
256 ** Points to the current position in the path string. The first time
257 ** you call this routine, this should point to the first character of
258 ** the path. On return, this will be updated to point to the
259 ** terminating \0 or : of the first directory found. You can then pass
260 ** it unchanged for subsequent calls; this routine will correctly skip
261 ** over the :.
263 ** char ** dir :
264 ** On exit, this will point to the first character of the directory
265 ** that was found. This will be a pointer directly into the client's
266 ** path string.
268 ** unsigned int * len :
269 ** On exit, this will contain the length of the directory that was
270 ** found, not counting any terminating \0 or :. If no directory was
271 ** found, this will be 0.
273 ** RETURN VALUE:
274 ** TRUE if we found another directory.
275 ** FALSE otherwise.
277 ** DESIGN:
279 ** We return a pointer and length, rather than a string, because of a)
280 ** historical reasons; and b) this avoids having to allocate storage.
284 **--
287 static bool
288 nextdir (d_char *current_dir, d_char *dir, size_t *len)
290 char *tchar;
292 if (**current_dir == '\0')
294 *len = 0;
295 *dir = NULL;
296 return FALSE;
299 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
301 /* Find next PATH_SEPARATOR or end of string */
302 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
307 *current_dir = tchar;
308 *len = size_fromInt (tchar - *dir);
309 return TRUE;
313 **++
314 ** FUNCTIONAL DESCRIPTION:
316 ** This function attempts to locate a file in a search list. On Ultrix,
317 ** it searches for the file on the path.
319 ** FORMAL PARAMETERS:
321 ** path: search path where to look for the file.
322 ** file: name of file to search for.
323 ** returnPath: if a file is found, this is where the concatenated
324 ** directory and file name are returned.
326 ** RETURN VALUE:
328 ** OSD_FILEFOUND: the file was found on the search list.
329 ** OSD_FILENOTFOUND the file was not found.
330 ** OSD_PATHTOOLONG the concatenated directory and file name are too
331 ** long.
333 ** SIDE EFFECTS:
335 ** None
337 ** PRECONDITIONS:
339 ** Requires that parameters, path and file, are valid C strings.
342 **--
345 static filestatus
346 osd_getPathFilter (cstring path, cstring file, cstring *returnPath,
347 bool (*pathFilter) (cstring filespec))
349 filestatus rVal = OSD_FILENOTFOUND;
351 /*@access cstring@*/
353 llassert (cstring_isDefined (file));
354 llassert (returnPath != NULL);
356 *returnPath = cstring_undefined;
358 if ( osd_pathIsAbsolute (file)
359 || path == NULL
360 || *path == '\0'
363 if (pathFilter (file))
365 rVal = OSD_FILEFOUND;
366 *returnPath = cstring_fromCharsNew (file);
369 else
371 char *fullPath;
372 char *dirPtr;
373 size_t dirLen;
374 char aPath[MAXPATHLEN];
376 fullPath = path;
377 while (nextdir (&fullPath, &dirPtr, &dirLen)
378 && rVal == OSD_FILENOTFOUND)
380 if ((dirLen + 1 + strlen (file) + 1) <= sizeof(aPath))
382 strncpy (aPath, dirPtr, dirLen);
383 aPath[dirLen] = CONNECTCHAR;
384 strcpy (aPath + dirLen + 1, file);
385 if (pathFilter (aPath))
387 rVal = OSD_FILEFOUND;
388 *returnPath = cstring_fromCharsNew (aPath);
391 else
393 rVal = OSD_PATHTOOLONG;
398 return rVal;
399 /*@noaccess cstring@*/
402 extern filestatus
403 osd_getPath (cstring path, cstring file, cstring *returnPath)
405 return osd_getPathFilter (path, file, returnPath, osd_fileExists);
408 extern filestatus
409 osd_getExePath (cstring path, cstring file, cstring *returnPath)
411 return osd_getPathFilter (path, file, returnPath, osd_fileIsExecutable);
414 static bool s_tempError = FALSE;
416 static void osd_setTempError (void)
417 /*@modifies internalState@*/
419 s_tempError = TRUE;
422 int osd_system (cstring cmd)
424 int res;
425 # if defined (WIN32)
426 (void) _flushall ();
427 # endif
429 res = system (cstring_toCharsSafe (cmd));
430 return res;
433 int osd_unlink (cstring fname)
435 int res;
437 res = unlink (cstring_toCharsSafe (fname));
439 if (res != 0)
441 if (!s_tempError)
443 llcontbug (message ("Cannot remove temporary file: %s (%s)",
444 fname,
445 cstring_fromChars (strerror (errno))));
449 return res;
453 osd_getPid (void)
455 return (int) getpid ();
458 bool osd_isConnectChar (char c)
460 if (c == CONNECTCHAR)
462 return TRUE;
465 # if defined (OS2) || defined (WIN32)
466 if (c == ALTCONNECTCHAR)
468 return TRUE;
470 # endif
472 return FALSE;
476 ** Returns true if c2 starts with the same path as c1
478 ** This is called by context_isSystemDir to determine if a
479 ** directory is on the system path.
481 ** In unix, this is just a string comparison. For Win32 and OS2, we need a more
482 ** complex comparison.
485 static bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
487 llassert (cstring_isDefined (prefixpath));
489 if (cstring_isEmpty (dirpath))
491 return (cstring_isEmpty (prefixpath));
494 # if defined (WIN32) || defined (OS2)
496 /*@access cstring@*/
499 int len = size_toInt (strlen (prefixpath));
500 int i = 0;
501 int slen = 0;
502 char *dirdrive, *prefixdrive;
505 ** If one has a drive specification, but the other doesn't, skip it.
508 dirdrive = strchr (dirpath, DRIVECONNECTCHAR);
509 prefixdrive = strchr (prefixpath, DRIVECONNECTCHAR);
510 if (dirdrive == NULL && prefixdrive != NULL)
512 prefixpath = prefixdrive + 1;
514 else if (prefixdrive == NULL && dirdrive != NULL)
516 dirpath = dirdrive + 1;
519 for (i = 0, slen = 0; i < len; i++, slen++)
521 /* Allow any number of connect characters in any combination:
522 * c:/usr//src\/foo == c:\\usr/src\/foo
523 * After this we'll be at the last of such a sequence */
525 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
527 /* Skip one or more connect chars */
529 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
534 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
539 /* DOS-like systems use case-insensitive path specs! */
540 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
542 return FALSE;
548 /*@noaccess cstring@*/
550 return TRUE;
551 # else
552 return (cstring_equalPrefix (dirpath, prefixpath));
553 # endif
556 bool
557 osd_pathPrefixInPathList (cstring path, cstring pathList)
559 cstring tmpPathList, curPathList;
560 cstring curPath;
561 bool res, finished;
563 llassert (cstring_isDefined (pathList));
565 tmpPathList = cstring_copy (pathList);
566 curPathList = tmpPathList;
568 res = FALSE;
569 finished = FALSE;
572 curPath = curPathList;
573 curPathList = cstring_afterChar (curPath, PATH_SEPARATOR);
574 if (cstring_isDefined (curPathList))
576 /*@access cstring@*/
577 *curPathList = '\0';
578 curPathList += 1;
579 /*@noaccess cstring@*/
581 else
583 finished = TRUE;
586 /* 2001-09-09:
587 ** herbert: don't compare with an empty name!
588 ** should return false for empty directory path
590 if (cstring_isEmpty (curPath))
592 break;
595 if (osd_equalCanonicalPrefix (path, curPath))
597 res = TRUE;
598 break;
601 while (!finished);
603 cstring_free (tmpPathList);
604 return res;
609 ** absolute paths
611 ** This code is adapted from:
613 ** 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
616 ** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
617 ** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
619 ** This file is part of GNU CC.
621 ** GNU CC is free software; you can redistribute it and/or modify
622 ** it under the terms of the GNU General Public License as published by
623 ** the Free Software Foundation; either version 2, or (at your option)
624 ** any later version.
626 ** GNU CC is distributed in the hope that it will be useful,
627 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
628 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
629 ** GNU General Public License for more details.
631 ** You should have received a copy of the GNU General Public License
632 ** along with GNU CC; see the file COPYING. If not, write to
633 ** the Free Software Foundation, 59 Temple Place - Suite 330,
634 ** Boston, MA 02111-1307, USA.
638 ** Return the absolutized filename for the given relative
639 ** filename. Note that if that filename is already absolute, it may
640 ** still be returned in a modified form because this routine also
641 ** eliminates redundant slashes and single dots and eliminates double
642 ** dots to get a shortest possible filename from the given input
643 ** filename. The absolutization of relative filenames is made by
644 ** assuming that the given filename is to be taken as relative to
645 ** the first argument (cwd) or to the current directory if cwd is
646 ** NULL.
649 /* A pointer to the current directory filename (used by abspath). */
650 static /*@only@*/ cstring osd_cwd = cstring_undefined;
652 static void osd_setWorkingDirectory (void)
654 # if !(defined (WIN32))
655 char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
656 char *cwd = getcwd (buf, MAXPATHLEN);
658 llassert (cstring_isUndefined (osd_cwd));
660 if (cwd == NULL)
662 lldiagmsg (message ("Cannot get working directory: %s\n",
663 lldecodeerror (errno)));
664 osd_cwd = cstring_makeLiteral ("<missing directory>");
666 else
668 osd_pathMakeNative (cwd);
669 osd_cwd = cstring_fromCharsNew (cwd);
672 sfree (buf);
673 # else
674 ; /* Don't know how to do this for non-POSIX platforms */
675 # endif
678 void osd_initMod (void)
680 osd_setWorkingDirectory ();
683 void osd_destroyMod (void)
685 cstring_free (osd_cwd);
686 osd_cwd = cstring_undefined;
689 cstring osd_absolutePath (cstring filename)
691 # if !(defined (WIN32))
692 char *abs_buffer;
693 char *endp, *outp, *inp;
695 /*@access cstring@*/
696 llassert (cstring_isDefined (osd_cwd));
697 llassert (cstring_isDefined (filename));
699 abs_buffer = (char *) dmalloc (cstring_length (osd_cwd) + cstring_length (filename) + 2);
700 endp = abs_buffer;
703 ** Copy the filename (possibly preceded by the current working
704 ** directory name) into the absolutization buffer.
708 const char *src_p;
710 if (!osd_pathIsAbsolute (filename))
712 src_p = osd_cwd;
714 while ((*endp++ = *src_p++) != '\0')
716 continue;
719 *(endp-1) = CONNECTCHAR; /* overwrite null */
722 src_p = filename;
724 while ((*endp++ = *src_p++) != '\0')
726 continue;
730 /* Now make a copy of abs_buffer into abs_buffer, shortening the
731 filename (by taking out slashes and dots) as we go. */
733 outp = inp = abs_buffer;
734 *outp++ = *inp++; /* copy first slash */
735 # if defined (apollo)
736 if (inp[0] == '/')
737 *outp++ = *inp++; /* copy second slash */
738 # endif
739 for (;;)
741 if (inp[0] == '\0')
743 break;
745 else if (osd_isConnectChar (inp[0]) && osd_isConnectChar (outp[-1]))
747 inp++;
748 continue;
750 else if (inp[0] == '.' && osd_isConnectChar (outp[-1]))
752 if (inp[1] == '\0')
754 break;
756 else if (osd_isConnectChar (inp[1]))
758 inp += 2;
759 continue;
761 else if ((inp[1] == '.')
762 && (inp[2] == '\0' || osd_isConnectChar (inp[2])))
764 inp += (osd_isConnectChar (inp[2])) ? 3 : 2;
765 outp -= 2;
767 while (outp >= abs_buffer && !osd_isConnectChar (*outp))
769 outp--;
772 if (outp < abs_buffer)
774 /* Catch cases like /.. where we try to backup to a
775 point above the absolute root of the logical file
776 system. */
778 llfatalbug (message ("Invalid file name: %s", filename));
781 *++outp = '\0';
782 continue;
784 else
789 else
794 *outp++ = *inp++;
797 /* On exit, make sure that there is a trailing null, and make sure that
798 the last character of the returned string is *not* a slash. */
800 *outp = '\0';
801 if (osd_isConnectChar (outp[-1]))
802 *--outp = '\0';
804 /*@noaccess cstring@*/
805 return cstring_fromChars (abs_buffer);
806 # else
807 DPRINTF (("Here: %s", filename));
808 return cstring_copy (filename);
809 # endif
813 ** Given a filename (and possibly a directory name from which the filename
814 ** is relative) return a string which is the shortest possible
815 ** equivalent for the corresponding full (absolutized) filename. The
816 ** shortest possible equivalent may be constructed by converting the
817 ** absolutized filename to be a relative filename (i.e. relative to
818 ** the actual current working directory). However if a relative filename
819 ** is longer, then the full absolute filename is returned.
821 ** KNOWN BUG: subpart of the original filename is actually a symbolic link.
823 ** this is really horrible code...surely someone has written a less buggy version of this!
826 cstring osd_outputPath (cstring filename)
828 # if !(defined (WIN32))
829 char *rel_buffer;
830 char *rel_buf_p;
831 cstring cwd_p = osd_cwd;
832 char *path_p;
833 int unmatched_slash_count = 0;
834 size_t filename_len = cstring_length (filename);
836 llassertretval (filename_len > 0, filename);
838 /*@access cstring@*/
839 path_p = filename;
840 rel_buffer = (char *) dmalloc (filename_len);
841 rel_buf_p = rel_buffer;
842 *rel_buf_p = '\0';
844 if (cwd_p == NULL)
846 /* Need to prevent recursive assertion failures */
847 return cstring_copy (filename);
850 llassert (cwd_p != NULL);
851 llassert (path_p != NULL);
853 while ((*cwd_p != '\0') && (*cwd_p == *path_p))
855 cwd_p++;
856 path_p++;
859 if ((*cwd_p == '\0') && (*path_p == '\0' || osd_isConnectChar (*path_p))) /* whole pwd matched */
861 if (*path_p == '\0') /* input *is* the current path! */
863 cstring_free (rel_buffer);
864 return cstring_makeLiteral (".");
866 else
868 cstring_free (rel_buffer);
869 return cstring_fromCharsNew (path_p + 1);
872 else
874 #if 1
875 /* evans 2002-02-05 This is horrible code, which I've removed. I couldn't
876 ** find any test cases that need it, so I hope I'm not breaking anything.
879 /* drl 2002-10/14 I had to put this code back.
880 ** The case that needs it is when splint is given an absolute path name of
881 ** a file outside of the current directory and the subdirectories below the
882 ** current directory. e.g. cd /home/; splint /tmp/prog.c
885 if (*path_p != '\0')
887 --cwd_p;
888 --path_p;
890 while (cwd_p >= osd_cwd && !osd_isConnectChar (*cwd_p)) /* backup to last slash */
892 --cwd_p;
893 --path_p;
895 cwd_p++;
896 path_p++;
897 unmatched_slash_count++;
900 /* Find out how many directory levels in cwd were *not* matched. */
901 while (*cwd_p != '\0')
903 if (osd_isConnectChar (*cwd_p++))
904 unmatched_slash_count++;
907 /* Now we know how long the "short name" will be.
908 Reject it if longer than the input. */
909 if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
911 cstring_free (rel_buffer);
912 /* fprintf (stderr, "Returning filename: %s [%p]\n", filename); */
913 return cstring_copy (filename);
915 #endif
917 /* For each of them, put a `../' at the beginning of the short name. */
918 while (unmatched_slash_count-- > 0)
920 /* Give up if the result gets to be longer
921 than the absolute path name. */
922 char * temp_rel_buf_p;
924 /*drl This comment is necessary because for some reason Splint
925 does not realize that the pasts where rel_buf_p is released
926 do not reach here*/
927 /*@-usereleased@*/
928 temp_rel_buf_p = rel_buf_p;
929 /*@-usereleased@*/
931 if (rel_buffer + filename_len <= temp_rel_buf_p + 3)
933 sfree (rel_buffer);
934 return cstring_copy (filename);
937 *rel_buf_p++ = '.';
938 *rel_buf_p++ = '.';
939 *rel_buf_p++ = CONNECTCHAR;
942 /* Then tack on the unmatched part of the desired file's name. */
946 if (rel_buffer + filename_len <= rel_buf_p)
948 cstring_free (rel_buffer);
949 return cstring_copy (filename);
951 } /*@-usereleased@*/
952 while ((*rel_buf_p++ = *path_p++) != '\0') ;
955 /*@=usereleased@*/ /* Splint limitation: shouldn't need these */
956 --rel_buf_p;
958 if (osd_isConnectChar (*(rel_buf_p-1)))
959 *--rel_buf_p = '\0';
961 /* fprintf (stderr, "Returning buffer: %s [%p]\n", rel_buffer, rel_buffer); */
962 return rel_buffer;
964 /*@noaccess cstring@*/
965 # else
966 return cstring_copy (filename);
967 # endif
970 cstring osd_getCurrentDirectory (void)
972 # if defined(WIN32) || defined(OS2)
973 return cstring_makeLiteralTemp ("");
974 # else
975 return cstring_makeLiteralTemp ("./");
976 # endif
980 int osd_openForReading (const char *pathname)
982 return open(pathname, O_RDONLY, S_IRWALL);
985 /* Read LEN bytes at PTR from descriptor DESC, retrying if necessary.
986 Return a negative value if an error occurs, otherwise return the
987 actual number of bytes read, which must be LEN unless end-of-file
988 was reached. */
990 int osd_readSafe (int desc, char *ptr, int len)
992 int left = len;
994 while (left > 0)
996 # if defined (WIN32)
997 /*@-compdef@*/ /* ptr is an out parameter */
998 int nchars = _read (desc, ptr, (unsigned) left);
999 /*@=compdef@*/
1000 # else
1001 int nchars = (int) read (desc, ptr, size_fromInt (left));
1002 # endif
1004 if (nchars < 0)
1006 # if defined (EINTR)
1007 if (errno == EINTR)
1008 continue;
1009 # endif
1010 return nchars;
1013 if (nchars == 0) {
1014 break;
1017 ptr += nchars;
1018 left -= nchars;
1021 return len - left;
1024 int osd_close(int fid)
1026 return close(fid);
1030 FILE *osd_createTmpFile (cstring fname, bool read)
1032 int fdesc;
1033 int flags;
1034 FILE *res;
1036 flags = (read ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC | O_EXCL;
1037 fdesc = open (cstring_toCharsSafe (fname), flags, S_IRUSR | S_IWUSR);
1038 if (fdesc == -1)
1040 osd_setTempError ();
1041 return NULL;
1043 res = fdopen (fdesc, read ? "w+" : "w");
1044 if (res == NULL)
1046 DPRINTF (("Error opening: %s", fname));
1047 osd_setTempError ();
1048 close(fdesc);
1049 return NULL;
1051 DPRINTF (("Opening file: %s / %p", fname, res));
1052 return res;
1055 int osd_fcloseall(void)
1057 # if defined (WIN32)
1058 /*@-unrecog@*/
1059 return _fcloseall ();
1060 /*@=unrecog@*/
1061 # else
1062 return 0;
1063 # endif
1067 ** Get the file-mode and data size of the file open on FD
1068 ** and store them in *MODE_POINTER and *SIZE_POINTER.
1072 osd_file_mode_and_size (int fd, filemode *mode_pointer, size_t *size_pointer)
1074 struct stat sbuf;
1076 if (fstat (fd, &sbuf) < 0) {
1077 *mode_pointer = 0;
1078 *size_pointer = 0;
1079 /*@-compdestroy@*/ /* possibly spurious warnings here (or memory leak) */
1080 return (-1);
1081 /*@=compdestroy@*/
1084 if (mode_pointer != NULL)
1086 if (S_ISREG (sbuf.st_mode))
1088 *mode_pointer = OSD_MODEREGULAR;
1090 else if (S_ISDIR (sbuf.st_mode))
1092 *mode_pointer = OSD_MODEDIRECTORY;
1094 else
1096 *mode_pointer = OSD_MODEOTHER;
1100 if (size_pointer != NULL)
1102 *size_pointer = (size_t) sbuf.st_size;
1105 /*@-compdestroy@*/ /* possibly spurious warnings here (or memory leak) */
1106 return 0;
1107 /*@=compdestroy@*/
1110 bool osd_pathIsAbsolute (const char* pathname)
1112 llassert (pathname != NULL && *pathname != '\0');
1114 return (osd_isConnectChar (*pathname)
1115 # if defined (WIN32) || defined (OS2)
1116 || (isalpha(*pathname) && *(pathname + 1) == DRIVECONNECTCHAR)
1117 # endif
1121 void osd_pathMakePosix (char *pathname)
1123 #if defined (WIN32) || defined (OS2)
1124 cstring_replaceAll (fname, CONNECTCHAR, ALTCONNECTCHAR);
1125 #endif
1128 void osd_pathMakeNative (char *pathname)
1130 #if defined (WIN32) || defined (OS2)
1131 cstring_replaceAll (fname, ALTCONNECTCHAR, CONNECTCHAR);
1132 #endif
1135 char* osd_pathBase (char *path)
1137 char *base;
1139 base = strrchr (path, CONNECTCHAR);
1140 # if defined (OS2) || defined (WIN32)
1142 char *altbase = strrchr (path, ALTCONNECTCHAR);
1143 if (altbase != NULL && (base == NULL || (altbase > base)))
1145 base = altbase;
1148 # endif
1150 if (base == NULL)
1152 base = path;
1154 else
1156 ++base; /* skip found char */
1159 return base;
1163 cstring osd_getTempDir(void)
1165 # if defined (WIN32) || defined (OS2)
1166 const char *env;
1167 env = getenv ("TMP");
1168 if (env == NULL)
1170 env = getenv ("TEMP");
1172 if (env != NULL)
1174 return cstring_makeLiteral (env);
1176 # endif
1178 return cstring_makeLiteral (DEFAULT_TMPDIR);
1181 cstring osd_removePreDirs (cstring s)
1183 /*@access cstring@*/
1185 llassert (cstring_isDefined (s));
1187 while (*s == '.' && *(s + 1) == CONNECTCHAR)
1189 s += 2;
1192 # if defined (OS2)
1193 /* remove remainders from double path delimiters... */
1194 while (*s == CONNECTCHAR)
1196 ++s;
1198 # endif
1200 return s;
1201 /*@noaccess cstring@*/
1204 bool osd_pathHasDir(const char* pathname)
1206 return strchr (pathname, CONNECTCHAR) != NULL
1207 # if defined (OS2) || defined (WIN32)
1208 || strchr (pathname, ALTCONNECTCHAR) != NULL
1209 # endif