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