]> andersk Git - splint.git/blame - src/osd.c
Fixed branch state bug with definitely null values (reported by Jon Wilson).
[splint.git] / src / osd.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
28bf4b0b 3** Copyright (C) 1994-2001 University of Virginia,
616915dd 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.
19**
20** For information on lclint: lclint-request@cs.virginia.edu
21** To report a bug: lclint-bug@cs.virginia.edu
11db3170 22** For more information: http://www.splint.org
616915dd 23*/
24/*
25** osd.c
26**
27** Provide a system-independent interface to system-dependent
28** file operations.
29*/
30
31/*
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.
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 */
41
42/*@-allmacros*/
43/*@ignore@*/
44# include <sys/types.h>
45# include <sys/stat.h>
46/* Fix suggested by Lars Rasmussen */
47# include <errno.h>
b7e84605 48
49/* POSIX platforms should defined getpid in unistd.h */
50# if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
51# include <process.h>
52# else
53# include <unistd.h>
54# endif
55
616915dd 56/*@end@*/
57/*@=allmacros*/
58# include "lclintMacros.nf"
59# include "basic.h"
60# include "osd.h"
61# include "portab.h"
62
63/* from stat.h */
64/*@ignore@*/
65extern int stat (const char *, /*@out@*/ struct stat *);
66/*@end@*/
67
68static bool osd_executableFileExists (char *);
69
70static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
71 /*@out@*/ size_t *p_len);
72
28bf4b0b 73extern cstring LSLRootName (cstring filespec)
616915dd 74{
28bf4b0b 75 /*@access cstring@*/
616915dd 76 char *result, *startName, *tail;
77 size_t nameLength;
78
28bf4b0b 79 llassert (cstring_isDefined (filespec));
616915dd 80 tail = strrchr (filespec, CONNECTCHAR);
81 startName = (tail == NULL ? filespec : &tail[1]);
82 tail = strrchr (startName, '.');
83 nameLength = (tail == NULL ? strlen (startName)
84 : size_fromInt (tail - startName));
85 result = dmalloc (nameLength + 1);
86 strncpy (result, startName, nameLength);
87 result[(int) nameLength] = '\0';
88 return result;
28bf4b0b 89 /*@noaccess cstring@*/
616915dd 90}
91
28bf4b0b 92extern /*@observer@*/ cstring
93osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
616915dd 94{
28bf4b0b 95 /*@access cstring@*/
616915dd 96 char *ret = osd_getEnvironmentVariable (env);
97
98 if (ret == NULL)
99 {
100 return def;
101 }
102 else
103 {
104 return ret;
105 }
28bf4b0b 106 /*@noaccess cstring@*/
616915dd 107}
108
109
110/*
111**++
112** FUNCTIONAL DESCRIPTION:
113**
114** This function attempts to locate a file in a search list. On VMS, it
115** just concatinates the path and file names, and then lets RMS do the
116** searching. On Ultrix, it searches for the file on the path.
117**
118** FORMAL PARAMETERS:
119**
120** path: search path where to look for the file.
121** file: name of file to search for.
122** returnPath: if a file is found, this is where the concatenated
123** directory and file name are returned.
124**
125** RETURN VALUE:
126**
127** OSD_FILEFOUND: the file was found on the search list.
128** OSD_FILENOTFOUND the file was not found.
129** OSD_PATHTOOLONG the concatenated directory and file name are too
130** long.
131**
132** SIDE EFFECTS:
133**
134** None
135**
136** PRECONDITIONS:
137**
138** Requires that parameters, path and file, are valid C strings.
139**
140**
141**--
142*/
143
28bf4b0b 144extern /*@observer@*/ cstring osd_getHomeDir ()
616915dd 145{
146 /* Would something different be better for windows? */
28bf4b0b 147 return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
616915dd 148}
149
28bf4b0b 150filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
616915dd 151{
28bf4b0b 152 return (osd_getPath (context_getLarchPath (), file, returnPath));
616915dd 153}
154
155extern filestatus
28bf4b0b 156osd_getPath (cstring path, cstring file, cstring *returnPath)
616915dd 157{
158 char *fullPath;
159 char *dirPtr;
160 size_t dirLen;
161 char aPath[MAXPATHLEN];
162 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
28bf4b0b 163
164 /*@access cstring@*/
165
616915dd 166 fullPath = path;
28bf4b0b 167 llassert (cstring_isDefined (file));
168
169 if (fullPath == NULL
170 ||
616915dd 171# if defined(OS2) || defined(MSDOS) || defined(WIN32)
28bf4b0b 172 /* under OS/2 and MSDOS the includePath may be empty, if so, search
173 * the current directory. */
174 *fullPath == '\0' ||
175 (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
616915dd 176# else
28bf4b0b 177 (*file == CONNECTCHAR)
616915dd 178# endif
28bf4b0b 179 )
616915dd 180 {
28bf4b0b 181 /* No path specified. Look for it in the current directory. */
182
616915dd 183 strcpy (&aPath[0], file);
28bf4b0b 184
616915dd 185 if (osd_fileExists (&aPath[0]))
186 {
187 rVal = OSD_FILEFOUND;
188 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
189 strcpy (*returnPath, &aPath[0]);
190 }
191 }
192 else
193 {
28bf4b0b 194 /* Path specified. Loop through directories in path looking for the */
195 /* first occurrence of the file. */
196
616915dd 197 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
198 rVal == OSD_FILENOTFOUND)
199 {
200 if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
201 {
28bf4b0b 202 /* Cat directory and filename, and see if file exists. */
616915dd 203 strncpy (&aPath[0], dirPtr, dirLen);
204 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
205 strcat (&aPath[0], CONNECTSTR);
206 strcat (&aPath[0], file);
28bf4b0b 207
616915dd 208 if (osd_fileExists (&aPath[0]))
209 {
210 rVal = OSD_FILEFOUND;
211 *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
212 strcpy (*returnPath, &aPath[0]);
213 }
214 }
215 else
216 {
217 rVal = OSD_PATHTOOLONG;
218 }
219 }
220 }
28bf4b0b 221
616915dd 222 return rVal;
28bf4b0b 223 /*@noaccess cstring@*/
616915dd 224}
225
226extern filestatus
28bf4b0b 227osd_getExePath (cstring path, cstring file, cstring *returnPath)
616915dd 228{
229 char *fullPath;
230 char *dirPtr;
231 size_t dirLen;
232 char aPath[MAXPATHLEN];
233 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
28bf4b0b 234 /*@access cstring@*/
616915dd 235
236 fullPath = osd_getEnvironmentVariable (path);
28bf4b0b 237
616915dd 238 if (fullPath == NULL)
239 {
28bf4b0b 240 /* No path specified. Look for it in the current directory. */
241 llassert (cstring_isDefined (file));
616915dd 242 strcpy (&aPath[0], file);
28bf4b0b 243
616915dd 244 if (osd_fileExists (&aPath[0]))
245 {
246 rVal = OSD_FILEFOUND;
247 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
248 strcpy (*returnPath, &aPath[0]);
249 }
250 }
251 else
252 {
253 /*
254 ** Path specified. Loop through directories in path looking
255 ** for the first occurrence of the file.
256 */
257
258 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
259 rVal == OSD_FILENOTFOUND)
260 {
28bf4b0b 261 llassert (cstring_isDefined (file));
262
263 if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
616915dd 264 {
265 /* Cat directory and filename, and see if file exists. */
266 strncpy (&aPath[0], dirPtr, dirLen);
267 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
268 strcat (&aPath[0], CONNECTSTR);
269 strcat (&aPath[0], file);
270
271 if (osd_executableFileExists (&aPath[0]))
272 {
273 rVal = OSD_FILEFOUND;
274 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
275 strcpy (*returnPath, &aPath[0]);
276 }
277 }
278 else
279 {
280 rVal = OSD_PATHTOOLONG;
281 }
282 }
283 }
284
285 return rVal;
28bf4b0b 286 /*@noaccess cstring@*/
616915dd 287}
288
289bool
28bf4b0b 290osd_fileExists (cstring filespec)
616915dd 291{
292# ifdef UNIX
293 struct stat buf;
28bf4b0b 294 return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
616915dd 295# else
296# if defined (WIN32) || defined (OS2)
dfd82dce 297 FILE *test = fileTable_openFile (context_fileTable (), filespec, "r");
28bf4b0b 298
616915dd 299 if (test != NULL)
28bf4b0b 300 {
dfd82dce 301 (void) fileTable_closeFile (context_fileTable (),test);
28bf4b0b 302 return TRUE;
303 }
616915dd 304 else
28bf4b0b 305 {
306 return FALSE;
307 }
616915dd 308# else
309 return FALSE;
310# endif
311# endif
312}
313
314bool
315osd_executableFileExists (/*@unused@*/ char *filespec)
316{
317# ifdef UNIX
318 struct stat buf;
319# if defined(__IBMC__) && defined(OS2)
320# define S_IFMT (unsigned short)0xFFFF
321# endif
322 if (stat (filespec, &buf) == 0)
323 {
324 /* mask by file type */
325 /*@-unrecog@*/ /* S_IFMT is not defined */
326 if ((buf.st_mode & S_IFMT) != S_IFDIR /*@=unrecog@*/) /* not a directory */
327 {
328 /* as long as it is an executable file */
329# if defined(__IBMC__) && defined(OS2)
330 int com_or_exe_pos = strlen( filespec) - 4;
331 return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
332 || stricmp( &filespec[com_or_exe_pos], ".com") == 0
333 || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
334 || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
335# else
336 return (((buf.st_mode & S_IXUSR)
337# if !defined(MSDOS) && !defined(OS2)
338 | (buf.st_mode & S_IXGRP) |
339 (buf.st_mode & S_IXOTH)
340# endif
341 ) != 0);
342# endif
343 }
344 }
345
346# endif
347 return (FALSE);
348
349}
350
351/*
352**++
353** FUNCTIONAL DESCRIPTION:
354**
355** Find the next directory from a directory path.
356**
357** FORMAL PARAMETERS:
358**
359** char ** current_dir :
360** Points to the current position in the path string. The first time
361** you call this routine, this should point to the first character of
362** the path. On return, this will be updated to point to the
363** terminating \0 or : of the first directory found. You can then pass
364** it unchanged for subsequent calls; this routine will correctly skip
365** over the :.
366**
367** char ** dir :
368** On exit, this will point to the first character of the directory
369** that was found. This will be a pointer directly into the client's
370** path string.
371**
372** unsigned int * len :
373** On exit, this will contain the length of the directory that was
374** found, not counting any terminating \0 or :. If no directory was
375** found, this will be 0.
376**
377** RETURN VALUE:
378** TRUE if we found another directory.
379** FALSE otherwise.
380**
381** DESIGN:
382**
383** We return a pointer and length, rather than a string, because of a)
384** historical reasons; and b) this avoids having to allocate storage.
385**
386**
387**
388**--
389*/
390
391static bool
392nextdir (d_char *current_dir, d_char *dir, size_t *len)
393{
394 char *tchar;
395
396 if (**current_dir == '\0')
397 {
398 *len = 0;
399 return FALSE;
400 }
401
7272a1c1 402 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
616915dd 403
404 /* Find next ':' or end of string */
7272a1c1 405 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
616915dd 406 {
407 ;
408 }
409
410 *current_dir = tchar;
411 *len = size_fromInt (tchar - *dir);
412 return TRUE;
413}
414
28bf4b0b 415/*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
616915dd 416{
1d239d69 417 /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
418# if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
28bf4b0b 419 char *val = getenv (cstring_toCharsSafe (var));
420
421 if (val == NULL)
422 {
423 return cstring_undefined;
424 }
425 else
426 {
427 return cstring_makeLiteralTemp (val);
428 }
616915dd 429# else
28bf4b0b 430 return cstring_undefined;
616915dd 431# endif
432}
433
434# ifndef NOLCL
435
436# ifdef WIN32
437extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
438# endif
439
440# ifndef system
441extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
442# endif
28bf4b0b 443int osd_system (cstring cmd)
616915dd 444{
445 int res;
446 /* system ("printenv"); */
447# ifdef WIN32
448 (void) _flushall ();
449# endif
450
28bf4b0b 451 res = system (cstring_toCharsSafe (cmd));
616915dd 452 return res;
453}
454# endif
455
456# ifndef unlink
b7e84605 457/* This should be defined by unistd.h */
616915dd 458/*@-redecl@*/
459extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
460/*@=redecl@*/
461# endif
462
28bf4b0b 463int osd_unlink (cstring fname)
616915dd 464{
465 int res;
466
28bf4b0b 467 res = unlink (cstring_toCharsSafe (fname));
616915dd 468
469 if (res != 0)
470 {
471 llcontbug (message ("Cannot remove temporary file: %s (%s)",
28bf4b0b 472 fname,
616915dd 473 cstring_fromChars (strerror (errno))));
474 }
475
476 return res;
477}
478
616915dd 479# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
480int
481# else
482int /* pid_t */
483# endif
484osd_getPid ()
485{
486# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
487 int pid = _getpid ();
488# else
28bf4b0b 489 pid_t pid = getpid ();
616915dd 490# endif
491
492 return (int) pid;
493}
494
28bf4b0b 495cstring osd_fixDefine (cstring x)
616915dd 496{
28bf4b0b 497 /*@access cstring@*/
498 llassert (cstring_isDefined (x));
616915dd 499# ifdef UNIX
500 if (strchr (x, '\'') != NULL) {
501 /*
502 ** If there is a single quote, check for <ident>='<string>' and
503 ** produce <ident>=<string>
504 */
505
506 char *eqs = strchr (x, '=');
507
508 if (eqs != NULL) {
509 if (eqs[1] == '\'') {
510 char *endqu = strrchr (x, '\'');
511
512 if (endqu != NULL) {
513 if (*(endqu - 1) != '\\') {
514 if (*(endqu + 1) == '\0') {
515 cstring res;
516 cstring def;
517
518 *endqu = '\0';
519 def = cstring_fromChars (eqs + 2);
520 eqs[1] = '\0';
521 res = cstring_concat (cstring_fromChars (x), def);
522 return res;
523 }
524 }
525 }
526 }
527 }
528 }
529
530# endif
531
28bf4b0b 532 return cstring_copy (x);
533 /*@noaccess cstring@*/
616915dd 534}
535
28bf4b0b 536bool osd_fileIsReadable (cstring f)
616915dd 537{
dfd82dce 538 FILE *fl = fileTable_openFile (context_fileTable (), f, "r");
616915dd 539
dfd82dce 540 if (fl != NULL)
616915dd 541 {
dfd82dce 542 check (fileTable_closeFile (context_fileTable (), fl));
616915dd 543 return (TRUE);
544 }
545 else
546 {
547 return (FALSE);
548 }
549}
550
551bool osd_isConnectChar (char c)
552{
553 if (c == CONNECTCHAR)
554 {
555 return TRUE;
556 }
557
558# ifdef HASALTCONNECTCHAR
559 if (c == ALTCONNECTCHAR)
560 {
561 return TRUE;
562 }
563# endif
564
565 return FALSE;
566}
567
68de3f33 568/*
569** Returns true if c2 starts with the same path as c1
570**
571** This is called by context_isSystemDir to determine if a
572** directory is on the system path.
573**
574** In unix, this is just a string comparison. For Win32 and OS2, we need a more
575** complex comparison.
576*/
577
578bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
579{
580 llassert (cstring_isDefined (prefixpath));
581
582 if (cstring_isEmpty (dirpath))
583 {
584 return (cstring_isEmpty (prefixpath));
585 }
586
587# if defined (WIN32) || defined (OS2)
588
589 /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
590
591 /*
592 ** If one has a drive specification, but the other doesn't, skip it.
593 */
594
595 if (strchr (dirpath, ':') == NULL
596 && strchr (prefixpath, ':') != NULL)
597 {
598 prefixpath = strchr (prefixpath, ':') + 1;
599 }
600 else
601 {
602 if (strchr (prefixpath, ':') == NULL
603 && strchr (dirpath, ':') != NULL)
604 {
605 dirpath = strchr (dirpath, ':') + 1;
606 }
607 }
608
609 {
610 int len = size_toInt (strlen (prefixpath));
611 int i = 0;
612 int slen = 0;
613
614 for (i = 0, slen = 0; i < len; i++, slen++)
615 {
616 /* Allow any number of connect characters in any combination:
617 * c:/usr//src\/foo == c:\\usr/src\/foo
618 * After this we'll be at the last of such a sequence */
619
620 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
621 {
622 /* Skip one or more connect chars */
623
624 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
625 {
626 ;
627 }
628
629 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
630 {
631 ;
632 }
633 }
634 /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
635 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
636 {
637 return FALSE;
638 }
639
640 }
641 }
642
643 /*@noaccess cstring@*/
644
645 return TRUE;
646# else
647 return (cstring_equalPrefix (dirpath, prefixpath));
648# endif
649}
650
107b60d6 651# if 0
652/*
653** This code provided by Herbert Martin Dietze, to canonicalize path names.
654*/
655
656char *osd_getcwd (/*@returned@*/ char *str, size_t size)
657{
658 return getcwd (str, size);
659}
660
661/*@null@*/ /*@observer@*/ char *
662osd_dirNext (char *str)
663{
664 char *p1 = strchr (str, '/');
665 char *p2 = strchr (str, '\\');
666
667 if (p1 == NULL)
668 {
669 if (p2 != NULL)
670 {
671 return p2 + 1;
672 }
673 else
674 {
675 return NULL;
676 }
677 }
678 else if (p2 == NULL)
679 {
680 return p1 + 1;
681 }
682 else /* both not null */
683 {
684 return (p1 < p2 ? p1 : p2) + 1;
685 }
686}
687
688static void
689osd_dirShift (char *str, size_t num) /*@modifies str@*/
690{
691 int i;
692
693 assert (num <= strlen (str));
694
695 for (i = 0; str[i] != '\0'; i++)
696 {
697 str[i] = str[i + num];
698 }
699}
700
701bool
702osd_dirDotdot (char *str)
703{
704 return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);
705}
706
707void
708osd_dirNormalize (char *str)
709{
710 char *pos1, *pos2;
711
712 for (; osd_isConnectChar (str[0]); str++)
713 {
714 }
715
716 for (; str != NULL && osd_dirDotdot (str); str = osd_dirNext (str))
717 {
718 }
719
720 for (pos1 = pos2 = str;
721 pos1 != NULL;
722 pos2 = pos1, pos1 = osd_dirNext (pos1))
723 {
724 /* remove redundant `./' entry */
725 while (pos1[0] == '.' && osd_isConnectChar (pos1[1]))
726 {
727 osd_dirShift (pos1, 2);
728 }
729
730 /* remove redundant `foo/../' entry */
731 if (osd_dirDotdot (pos1) && pos2 < pos1)
732 {
733 osd_dirShift (pos2, pos1 - pos2 + 1);
734 osd_dirNormalize (str);
735 }
736 }
737}
738
739/*@null@*/ char *
740osd_dirAbsolute (char *str)
741{
742 char *ret = NULL;
743 size_t size = PATH_MAX * sizeof (*ret);
744
745 if (osd_isConnectChar (str[0]))
746 {
747 ret = dmalloc ((strlen (str) + 1) * sizeof (*ret));
748 strcpy (ret, str);
749 }
750 else
751 {
752 ret = dmalloc (size);
753
754 ret = osd_getcwd (ret, size);
755 ret = realloc (ret, (strlen (str) + strlen (ret) + 2) * sizeof (*ret));
756
757 if (ret == NULL)
758 {
759 return NULL;
760 }
761
762 strcat (ret, CONNECTSTR);
763 strcat (ret, str);
764 }
765
766 osd_dirNormalize (ret);
767 return ret;
768}
769
770# endif
53a89507 771
772/*
773** absolute paths
774**
775** This code is adapted from:
776**
777** 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
778**
779**
780** Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
781** Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
782**
783** This file is part of GNU CC.
784**
785** GNU CC is free software; you can redistribute it and/or modify
786** it under the terms of the GNU General Public License as published by
787** the Free Software Foundation; either version 2, or (at your option)
788** any later version.
789**
790** GNU CC is distributed in the hope that it will be useful,
791** but WITHOUT ANY WARRANTY; without even the implied warranty of
792** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
793** GNU General Public License for more details.
794**
795** You should have received a copy of the GNU General Public License
796** along with GNU CC; see the file COPYING. If not, write to
797** the Free Software Foundation, 59 Temple Place - Suite 330,
798** Boston, MA 02111-1307, USA.
799*/
800
801/*
802** Return the absolutized filename for the given relative
803** filename. Note that if that filename is already absolute, it may
804** still be returned in a modified form because this routine also
805** eliminates redundant slashes and single dots and eliminates double
806** dots to get a shortest possible filename from the given input
807** filename. The absolutization of relative filenames is made by
808** assuming that the given filename is to be taken as relative to
809** the first argument (cwd) or to the current directory if cwd is
810** NULL.
811*/
812
813/* A pointer to the current directory filename (used by abspath). */
814static /*@only@*/ cstring osd_cwd = cstring_undefined;
815
816static void osd_setWorkingDirectory (void)
817{
818# ifdef UNIX
819 char *buf = dmalloc (sizeof (*buf) * MAXPATHLEN);
820 char *cwd = getcwd (buf, MAXPATHLEN);
821
822 llassert (cstring_isUndefined (osd_cwd));
823
824 if (cwd == NULL)
825 {
826 lldiagmsg (message ("Cannot get working directory: %s\n",
827 lldecodeerror (errno)));
828 }
829 else
830 {
831 osd_cwd = cstring_fromCharsNew (cwd);
832 }
833
834 sfree (buf);
835# else
836 ; /* Don't know how to do this for non-POSIX platforms */
837# endif
838}
839
840void osd_initMod (void)
841{
842 osd_setWorkingDirectory ();
843}
844
845cstring osd_absolutePath (cstring cwd, cstring filename)
846{
847# ifdef UNIX
848 /* Setup the current working directory as needed. */
849 cstring cwd2 = cstring_isDefined (cwd) ? cwd : osd_cwd;
850 char *abs_buffer;
851 char *endp, *outp, *inp;
852
853 /*@access cstring@*/
854 llassert (cstring_isDefined (cwd2));
855 llassert (cstring_isDefined (filename));
856
857 abs_buffer = (char *) dmalloc (size_fromInt (cstring_length (cwd2) + cstring_length (filename) + 2));
858 endp = abs_buffer;
859
860 /*
861 ** Copy the filename (possibly preceded by the current working
862 ** directory name) into the absolutization buffer.
863 */
864
865 {
866 const char *src_p;
867
868 if (filename[0] != '/')
869 {
870 src_p = cwd2;
871
872 while ((*endp++ = *src_p++) != '\0')
873 {
874 continue;
875 }
876
877 *(endp-1) = '/'; /* overwrite null */
878 }
879
880 src_p = filename;
881
882 while ((*endp++ = *src_p++) != '\0')
883 {
884 continue;
885 }
886 }
887
888 /* Now make a copy of abs_buffer into abs_buffer, shortening the
889 filename (by taking out slashes and dots) as we go. */
890
891 outp = inp = abs_buffer;
892 *outp++ = *inp++; /* copy first slash */
893#ifdef apollo
894 if (inp[0] == '/')
895 *outp++ = *inp++; /* copy second slash */
896#endif
897 for (;;)
898 {
899 if (inp[0] == '\0')
900 {
901 break;
902 }
903 else if (inp[0] == '/' && outp[-1] == '/')
904 {
905 inp++;
906 continue;
907 }
908 else if (inp[0] == '.' && outp[-1] == '/')
909 {
910 if (inp[1] == '\0')
911 {
912 break;
913 }
914 else if (inp[1] == '/')
915 {
916 inp += 2;
917 continue;
918 }
919 else if ((inp[1] == '.')
920 && (inp[2] == '\0' || inp[2] == '/'))
921 {
922 inp += (inp[2] == '/') ? 3 : 2;
923 outp -= 2;
924
925 while (outp >= abs_buffer && *outp != '/')
926 {
927 outp--;
928 }
929
930 if (outp < abs_buffer)
931 {
932 /* Catch cases like /.. where we try to backup to a
933 point above the absolute root of the logical file
934 system. */
935
936 llfatalbug (message ("Invalid file name: %s", filename));
937 }
938
939 *++outp = '\0';
940 continue;
941 }
942 else
943 {
944 ;
945 }
946 }
947 else
948 {
949 ;
950 }
951
952 *outp++ = *inp++;
953 }
954
955 /* On exit, make sure that there is a trailing null, and make sure that
956 the last character of the returned string is *not* a slash. */
957
958 *outp = '\0';
959 if (outp[-1] == '/')
960 *--outp = '\0';
961
962 /*@noaccess cstring@*/
963 return cstring_fromChars (abs_buffer);
964# else
965 return cstring_copy (filename);
966# endif
967}
968
969/*
970** Given a filename (and possibly a directory name from which the filename
971** is relative) return a string which is the shortest possible
972** equivalent for the corresponding full (absolutized) filename. The
973** shortest possible equivalent may be constructed by converting the
974** absolutized filename to be a relative filename (i.e. relative to
975** the actual current working directory). However if a relative filename
976** is longer, then the full absolute filename is returned.
977**
978** KNOWN BUG: subpart of the original filename is actually a symbolic link.
979*/
980
981cstring osd_outputPath (cstring filename)
982{
983# ifdef UNIX
984 char *rel_buffer;
985 char *rel_buf_p;
986 cstring cwd_p = osd_cwd;
987 char *path_p;
988 int unmatched_slash_count = 0;
989 size_t filename_len = size_fromInt (cstring_length (filename));
990
991 /*@access cstring@*/
992 path_p = filename;
993 rel_buf_p = rel_buffer = (char *) dmalloc (filename_len);
994
995 llassert (cwd_p != NULL);
996 llassert (path_p != NULL);
997
998 while ((*cwd_p != '\0') && (*cwd_p == *path_p))
999 {
1000 cwd_p++;
1001 path_p++;
1002 }
1003
1004 if ((*cwd_p == '\0') && (*path_p == '\0' || *path_p == '/')) /* whole pwd matched */
1005 {
1006 if (*path_p == '\0') /* input *is* the current path! */
1007 return cstring_makeLiteral (".");
1008 else
1009 {
1010 /*@i324 ! lclint didn't report an errors for: return ++path_p; */
1011 return cstring_fromCharsNew (++path_p);
1012 }
1013 }
1014 else
1015 {
1016 if (*path_p != '\0')
1017 {
1018 --cwd_p;
1019 --path_p;
1020 while (*cwd_p != '/') /* backup to last slash */
1021 {
1022 --cwd_p;
1023 --path_p;
1024 }
1025 cwd_p++;
1026 path_p++;
1027 unmatched_slash_count++;
1028 }
1029
1030 /* Find out how many directory levels in cwd were *not* matched. */
1031 while (*cwd_p != '\0')
1032 {
1033 if (*cwd_p++ == '/')
1034 unmatched_slash_count++;
1035 }
1036
1037 /* Now we know how long the "short name" will be.
1038 Reject it if longer than the input. */
1039 if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1040 {
1041 return cstring_copy (filename);
1042 }
1043
1044 /*
1045 ** evans 2001-10-15
1046 ** I'm trusting the code on this one...don't see how this is guaranteed though.
1047 */
1048
1049 assertSet (rel_buffer);
1050
1051 /* For each of them, put a `../' at the beginning of the short name. */
1052 while (unmatched_slash_count-- > 0)
1053 {
1054 /* Give up if the result gets to be longer
1055 than the absolute path name. */
1056 if (rel_buffer + filename_len <= rel_buf_p + 3)
1057 {
1058 sfree (rel_buffer);
1059 return cstring_copy (filename);
1060 }
1061
1062 *rel_buf_p++ = '.';
1063 *rel_buf_p++ = '.';
1064 *rel_buf_p++ = '/';
1065 }
1066
1067 /* Then tack on the unmatched part of the desired file's name. */
1068 do
1069 {
1070 if (rel_buffer + filename_len <= rel_buf_p)
1071 {
1072 cstring_free (rel_buffer);
1073 return cstring_copy (filename);
1074 }
1075 }
1076 while ((*rel_buf_p++ = *path_p++) != '\0') ;
1077
1078 --rel_buf_p;
1079 if (*(rel_buf_p-1) == '/')
1080 *--rel_buf_p = '\0';
1081
1082 return rel_buffer;
1083 }
1084 /*@noaccess cstring@*/
1085# else
1086 return cstring_copy (filename);
1087# endif
1088}
1089
1090
1091
This page took 0.20864 seconds and 5 git commands to generate.