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