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