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