]> andersk Git - splint.git/blob - src/osd.c
Fixed the OS/2 specific files for the latest release.
[splint.git] / src / osd.c
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
68 extern int stat (const char *, /*@out@*/ struct stat *);\r
69 /*@end@*/\r
70 \r
71 static bool osd_executableFileExists (char *);\r
72 \r
73 static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir, \r
74                      /*@out@*/ size_t *p_len);\r
75 \r
76 extern 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
95 extern /*@observer@*/ cstring\r
96 osd_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
147 extern /*@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
153 filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)\r
154 {\r
155   return (osd_getPath (context_getLarchPath (), file, returnPath));\r
156 }\r
157 \r
158 extern filestatus\r
159 osd_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
235 extern filestatus\r
236 osd_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
299 bool\r
300 osd_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
338 bool\r
339 osd_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
413 static bool\r
414 nextdir (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
458 extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;\r
459 # endif\r
460 \r
461 # ifndef system\r
462 extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;\r
463 # endif\r
464 int 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
479 extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;\r
480 /*@=redecl@*/\r
481 # endif\r
482 \r
483 static bool s_tempError = FALSE;\r
484 \r
485 void osd_setTempError (void)\r
486 {\r
487   s_tempError = TRUE;\r
488 }\r
489 \r
490 int 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
510 int\r
511 # else\r
512 int /* pid_t */\r
513 # endif\r
514 osd_getPid ()\r
515 {\r
516 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
517   int pid = _getpid ();\r
518 # else\r
519   __pid_t pid = getpid ();\r
520 # endif\r
521 \r
522   return (int) pid;\r
523 }\r
524   \r
525 cstring 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
566 bool 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
581 bool 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
608 bool 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
686 char *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
692 osd_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
718 static void \r
719 osd_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
731 bool\r
732 osd_dirDotdot (char *str)\r
733 {\r
734   return str[0] == '.' && str[1] == '.' && osd_isConnectChar (str[2]);\r
735 }\r
736 \r
737 void\r
738 osd_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
770 osd_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
858 static /*@only@*/ cstring osd_cwd = cstring_undefined;\r
859 \r
860 static 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
865 #else if defined (OS2)\r
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
894 void osd_initMod (void)\r
895 {\r
896   osd_setWorkingDirectory ();\r
897 }\r
898 \r
899 void osd_destroyMod (void)\r
900 {\r
901   cstring_free (osd_cwd);\r
902   osd_cwd = cstring_undefined;\r
903 }\r
904 \r
905 cstring 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
1048 cstring 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
1192 cstring 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.170449 seconds and 5 git commands to generate.