]> andersk Git - splint.git/blame - src/osd.c
Added usleep to unix.h in library.
[splint.git] / src / osd.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
28bf4b0b 3** Copyright (C) 1994-2001 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**
20** For information on lclint: lclint-request@cs.virginia.edu
21** To report a bug: lclint-bug@cs.virginia.edu
22** For more information: http://lclint.cs.virginia.edu
23*/
24/*
25** osd.c
26**
27** Provide a system-independent interface to system-dependent
28** file operations.
29*/
30
31/*
32 * Modified by Herbert 04/19/97:
33 * - added conditional 'OS2' to conditional 'MSDOS'
34 * - added include of new header portab.h.
35 * - changed '/' to macro.
36 * - added DOS / OS/2 specific stuff in osd_getPath.
37 * Herbert 06/12/2000:
38 * - added OS/2 specific includes before osd_getPid()
39 * - handle files like in WIN32 for OS/2 in osd_fileExists()
40 */
41
42/*@-allmacros*/
43/*@ignore@*/
44# include <sys/types.h>
45# include <sys/stat.h>
46/* Fix suggested by Lars Rasmussen */
47# include <errno.h>
b7e84605 48
49/* POSIX platforms should defined getpid in unistd.h */
50# if defined (WIN32) || (defined(OS2) && defined(__IBMC__))
51# include <process.h>
52# else
53# include <unistd.h>
54# endif
55
616915dd 56/*@end@*/
57/*@=allmacros*/
58# include "lclintMacros.nf"
59# include "basic.h"
60# include "osd.h"
61# include "portab.h"
62
63/* from stat.h */
64/*@ignore@*/
65extern int stat (const char *, /*@out@*/ struct stat *);
66/*@end@*/
67
68static bool osd_executableFileExists (char *);
69
70static bool nextdir (char **p_current_dir, /*@out@*/ char **p_dir,
71 /*@out@*/ size_t *p_len);
72
28bf4b0b 73extern cstring LSLRootName (cstring filespec)
616915dd 74{
28bf4b0b 75 /*@access cstring@*/
616915dd 76 char *result, *startName, *tail;
77 size_t nameLength;
78
28bf4b0b 79 llassert (cstring_isDefined (filespec));
616915dd 80 tail = strrchr (filespec, CONNECTCHAR);
81 startName = (tail == NULL ? filespec : &tail[1]);
82 tail = strrchr (startName, '.');
83 nameLength = (tail == NULL ? strlen (startName)
84 : size_fromInt (tail - startName));
85 result = dmalloc (nameLength + 1);
86 strncpy (result, startName, nameLength);
87 result[(int) nameLength] = '\0';
88 return result;
28bf4b0b 89 /*@noaccess cstring@*/
616915dd 90}
91
28bf4b0b 92extern /*@observer@*/ cstring
93osd_getEnvironment (cstring env, /*@returned@*/ cstring def)
616915dd 94{
28bf4b0b 95 /*@access cstring@*/
616915dd 96 char *ret = osd_getEnvironmentVariable (env);
97
98 if (ret == NULL)
99 {
100 return def;
101 }
102 else
103 {
104 return ret;
105 }
28bf4b0b 106 /*@noaccess cstring@*/
616915dd 107}
108
109
110/*
111**++
112** FUNCTIONAL DESCRIPTION:
113**
114** This function attempts to locate a file in a search list. On VMS, it
115** just concatinates the path and file names, and then lets RMS do the
116** searching. On Ultrix, it searches for the file on the path.
117**
118** FORMAL PARAMETERS:
119**
120** path: search path where to look for the file.
121** file: name of file to search for.
122** returnPath: if a file is found, this is where the concatenated
123** directory and file name are returned.
124**
125** RETURN VALUE:
126**
127** OSD_FILEFOUND: the file was found on the search list.
128** OSD_FILENOTFOUND the file was not found.
129** OSD_PATHTOOLONG the concatenated directory and file name are too
130** long.
131**
132** SIDE EFFECTS:
133**
134** None
135**
136** PRECONDITIONS:
137**
138** Requires that parameters, path and file, are valid C strings.
139**
140**
141**--
142*/
143
28bf4b0b 144extern /*@observer@*/ cstring osd_getHomeDir ()
616915dd 145{
146 /* Would something different be better for windows? */
28bf4b0b 147 return (osd_getEnvironmentVariable (cstring_makeLiteralTemp ("HOME")));
616915dd 148}
149
28bf4b0b 150filestatus osd_findOnLarchPath (cstring file, cstring *returnPath)
616915dd 151{
28bf4b0b 152 return (osd_getPath (context_getLarchPath (), file, returnPath));
616915dd 153}
154
155extern filestatus
28bf4b0b 156osd_getPath (cstring path, cstring file, cstring *returnPath)
616915dd 157{
158 char *fullPath;
159 char *dirPtr;
160 size_t dirLen;
161 char aPath[MAXPATHLEN];
162 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
28bf4b0b 163
164 /*@access cstring@*/
165
616915dd 166 fullPath = path;
28bf4b0b 167 llassert (cstring_isDefined (file));
168
169 if (fullPath == NULL
170 ||
616915dd 171# if defined(OS2) || defined(MSDOS) || defined(WIN32)
28bf4b0b 172 /* under OS/2 and MSDOS the includePath may be empty, if so, search
173 * the current directory. */
174 *fullPath == '\0' ||
175 (*file == CONNECTCHAR || (file[0] != '\0' && file[1] == ':'))
616915dd 176# else
28bf4b0b 177 (*file == CONNECTCHAR)
616915dd 178# endif
28bf4b0b 179 )
616915dd 180 {
28bf4b0b 181 /* No path specified. Look for it in the current directory. */
182
616915dd 183 strcpy (&aPath[0], file);
28bf4b0b 184
616915dd 185 if (osd_fileExists (&aPath[0]))
186 {
187 rVal = OSD_FILEFOUND;
188 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
189 strcpy (*returnPath, &aPath[0]);
190 }
191 }
192 else
193 {
28bf4b0b 194 /* Path specified. Loop through directories in path looking for the */
195 /* first occurrence of the file. */
196
616915dd 197 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
198 rVal == OSD_FILENOTFOUND)
199 {
200 if ((dirLen + strlen (file) + 2) <= MAXPATHLEN)
201 {
28bf4b0b 202 /* Cat directory and filename, and see if file exists. */
616915dd 203 strncpy (&aPath[0], dirPtr, dirLen);
204 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
205 strcat (&aPath[0], CONNECTSTR);
206 strcat (&aPath[0], file);
28bf4b0b 207
616915dd 208 if (osd_fileExists (&aPath[0]))
209 {
210 rVal = OSD_FILEFOUND;
211 *returnPath = (char *) dmalloc (strlen (&aPath[0]) + 1);
212 strcpy (*returnPath, &aPath[0]);
213 }
214 }
215 else
216 {
217 rVal = OSD_PATHTOOLONG;
218 }
219 }
220 }
28bf4b0b 221
616915dd 222 return rVal;
28bf4b0b 223 /*@noaccess cstring@*/
616915dd 224}
225
226extern filestatus
28bf4b0b 227osd_getExePath (cstring path, cstring file, cstring *returnPath)
616915dd 228{
229 char *fullPath;
230 char *dirPtr;
231 size_t dirLen;
232 char aPath[MAXPATHLEN];
233 filestatus rVal = OSD_FILENOTFOUND; /* assume file not found. */
28bf4b0b 234 /*@access cstring@*/
616915dd 235
236 fullPath = osd_getEnvironmentVariable (path);
28bf4b0b 237
616915dd 238 if (fullPath == NULL)
239 {
28bf4b0b 240 /* No path specified. Look for it in the current directory. */
241 llassert (cstring_isDefined (file));
616915dd 242 strcpy (&aPath[0], file);
28bf4b0b 243
616915dd 244 if (osd_fileExists (&aPath[0]))
245 {
246 rVal = OSD_FILEFOUND;
247 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
248 strcpy (*returnPath, &aPath[0]);
249 }
250 }
251 else
252 {
253 /*
254 ** Path specified. Loop through directories in path looking
255 ** for the first occurrence of the file.
256 */
257
258 while (nextdir (&fullPath, &dirPtr, &dirLen) &&
259 rVal == OSD_FILENOTFOUND)
260 {
28bf4b0b 261 llassert (cstring_isDefined (file));
262
263 if ((dirLen + cstring_length (file) + 2) <= MAXPATHLEN)
616915dd 264 {
265 /* Cat directory and filename, and see if file exists. */
266 strncpy (&aPath[0], dirPtr, dirLen);
267 strcpy (&aPath[0] + dirLen, ""); /* Null terminate aPath. */
268 strcat (&aPath[0], CONNECTSTR);
269 strcat (&aPath[0], file);
270
271 if (osd_executableFileExists (&aPath[0]))
272 {
273 rVal = OSD_FILEFOUND;
274 *returnPath = dmalloc (strlen (&aPath[0]) + 1);
275 strcpy (*returnPath, &aPath[0]);
276 }
277 }
278 else
279 {
280 rVal = OSD_PATHTOOLONG;
281 }
282 }
283 }
284
285 return rVal;
28bf4b0b 286 /*@noaccess cstring@*/
616915dd 287}
288
289bool
28bf4b0b 290osd_fileExists (cstring filespec)
616915dd 291{
292# ifdef UNIX
293 struct stat buf;
28bf4b0b 294 return (stat (cstring_toCharsSafe (filespec), &buf) == 0);
616915dd 295# else
296# if defined (WIN32) || defined (OS2)
dfd82dce 297 FILE *test = fileTable_openFile (context_fileTable (), filespec, "r");
28bf4b0b 298
616915dd 299 if (test != NULL)
28bf4b0b 300 {
dfd82dce 301 (void) fileTable_closeFile (context_fileTable (),test);
28bf4b0b 302 return TRUE;
303 }
616915dd 304 else
28bf4b0b 305 {
306 return FALSE;
307 }
616915dd 308# else
309 return FALSE;
310# endif
311# endif
312}
313
314bool
315osd_executableFileExists (/*@unused@*/ char *filespec)
316{
317# ifdef UNIX
318 struct stat buf;
319# if defined(__IBMC__) && defined(OS2)
320# define S_IFMT (unsigned short)0xFFFF
321# endif
322 if (stat (filespec, &buf) == 0)
323 {
324 /* mask by file type */
325 /*@-unrecog@*/ /* S_IFMT is not defined */
326 if ((buf.st_mode & S_IFMT) != S_IFDIR /*@=unrecog@*/) /* not a directory */
327 {
328 /* as long as it is an executable file */
329# if defined(__IBMC__) && defined(OS2)
330 int com_or_exe_pos = strlen( filespec) - 4;
331 return stricmp( &filespec[com_or_exe_pos], ".exe") == 0
332 || stricmp( &filespec[com_or_exe_pos], ".com") == 0
333 || stricmp( &filespec[com_or_exe_pos], ".bat") == 0
334 || stricmp( &filespec[com_or_exe_pos], ".cmd") == 0;
335# else
336 return (((buf.st_mode & S_IXUSR)
337# if !defined(MSDOS) && !defined(OS2)
338 | (buf.st_mode & S_IXGRP) |
339 (buf.st_mode & S_IXOTH)
340# endif
341 ) != 0);
342# endif
343 }
344 }
345
346# endif
347 return (FALSE);
348
349}
350
351/*
352**++
353** FUNCTIONAL DESCRIPTION:
354**
355** Find the next directory from a directory path.
356**
357** FORMAL PARAMETERS:
358**
359** char ** current_dir :
360** Points to the current position in the path string. The first time
361** you call this routine, this should point to the first character of
362** the path. On return, this will be updated to point to the
363** terminating \0 or : of the first directory found. You can then pass
364** it unchanged for subsequent calls; this routine will correctly skip
365** over the :.
366**
367** char ** dir :
368** On exit, this will point to the first character of the directory
369** that was found. This will be a pointer directly into the client's
370** path string.
371**
372** unsigned int * len :
373** On exit, this will contain the length of the directory that was
374** found, not counting any terminating \0 or :. If no directory was
375** found, this will be 0.
376**
377** RETURN VALUE:
378** TRUE if we found another directory.
379** FALSE otherwise.
380**
381** DESIGN:
382**
383** We return a pointer and length, rather than a string, because of a)
384** historical reasons; and b) this avoids having to allocate storage.
385**
386**
387**
388**--
389*/
390
391static bool
392nextdir (d_char *current_dir, d_char *dir, size_t *len)
393{
394 char *tchar;
395
396 if (**current_dir == '\0')
397 {
398 *len = 0;
399 return FALSE;
400 }
401
7272a1c1 402 *dir = (**current_dir == PATH_SEPARATOR ? *current_dir + 1 : *current_dir);
616915dd 403
404 /* Find next ':' or end of string */
7272a1c1 405 for (tchar = *dir; *tchar != '\0' && *tchar != PATH_SEPARATOR; tchar++)
616915dd 406 {
407 ;
408 }
409
410 *current_dir = tchar;
411 *len = size_fromInt (tchar - *dir);
412 return TRUE;
413}
414
28bf4b0b 415/*@observer@*/ /*@null@*/ cstring osd_getEnvironmentVariable (cstring var)
616915dd 416{
1d239d69 417 /* evans - 2001-08-26 fixed OS instead of OS2 bug, reported by Alexander Mai */
418# if defined(UNIX) || defined(OS2) || defined(MSDOS) || defined(WIN32)
28bf4b0b 419 char *val = getenv (cstring_toCharsSafe (var));
420
421 if (val == NULL)
422 {
423 return cstring_undefined;
424 }
425 else
426 {
427 return cstring_makeLiteralTemp (val);
428 }
616915dd 429# else
28bf4b0b 430 return cstring_undefined;
616915dd 431# endif
432}
433
434# ifndef NOLCL
435
436# ifdef WIN32
437extern /*@external@*/ int _flushall (void) /*@modifies fileSystem@*/ ;
438# endif
439
440# ifndef system
441extern /*@external@*/ int system (const char *) /*@modifies fileSystem@*/ ;
442# endif
28bf4b0b 443int osd_system (cstring cmd)
616915dd 444{
445 int res;
446 /* system ("printenv"); */
447# ifdef WIN32
448 (void) _flushall ();
449# endif
450
28bf4b0b 451 res = system (cstring_toCharsSafe (cmd));
616915dd 452 return res;
453}
454# endif
455
456# ifndef unlink
b7e84605 457/* This should be defined by unistd.h */
616915dd 458/*@-redecl@*/
459extern /*@external@*/ int unlink (const char *) /*@modifies fileSystem@*/ ;
460/*@=redecl@*/
461# endif
462
28bf4b0b 463int osd_unlink (cstring fname)
616915dd 464{
465 int res;
466
28bf4b0b 467 res = unlink (cstring_toCharsSafe (fname));
616915dd 468
469 if (res != 0)
470 {
471 llcontbug (message ("Cannot remove temporary file: %s (%s)",
28bf4b0b 472 fname,
616915dd 473 cstring_fromChars (strerror (errno))));
474 }
475
476 return res;
477}
478
616915dd 479# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
480int
481# else
482int /* pid_t */
483# endif
484osd_getPid ()
485{
486# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
487 int pid = _getpid ();
488# else
28bf4b0b 489 pid_t pid = getpid ();
616915dd 490# endif
491
492 return (int) pid;
493}
494
28bf4b0b 495cstring osd_fixDefine (cstring x)
616915dd 496{
28bf4b0b 497 /*@access cstring@*/
498 llassert (cstring_isDefined (x));
616915dd 499# ifdef UNIX
500 if (strchr (x, '\'') != NULL) {
501 /*
502 ** If there is a single quote, check for <ident>='<string>' and
503 ** produce <ident>=<string>
504 */
505
506 char *eqs = strchr (x, '=');
507
508 if (eqs != NULL) {
509 if (eqs[1] == '\'') {
510 char *endqu = strrchr (x, '\'');
511
512 if (endqu != NULL) {
513 if (*(endqu - 1) != '\\') {
514 if (*(endqu + 1) == '\0') {
515 cstring res;
516 cstring def;
517
518 *endqu = '\0';
519 def = cstring_fromChars (eqs + 2);
520 eqs[1] = '\0';
521 res = cstring_concat (cstring_fromChars (x), def);
522 return res;
523 }
524 }
525 }
526 }
527 }
528 }
529
530# endif
531
28bf4b0b 532 return cstring_copy (x);
533 /*@noaccess cstring@*/
616915dd 534}
535
28bf4b0b 536bool osd_fileIsReadable (cstring f)
616915dd 537{
dfd82dce 538 FILE *fl = fileTable_openFile (context_fileTable (), f, "r");
616915dd 539
dfd82dce 540 if (fl != NULL)
616915dd 541 {
dfd82dce 542 check (fileTable_closeFile (context_fileTable (), fl));
616915dd 543 return (TRUE);
544 }
545 else
546 {
547 return (FALSE);
548 }
549}
550
551bool osd_isConnectChar (char c)
552{
553 if (c == CONNECTCHAR)
554 {
555 return TRUE;
556 }
557
558# ifdef HASALTCONNECTCHAR
559 if (c == ALTCONNECTCHAR)
560 {
561 return TRUE;
562 }
563# endif
564
565 return FALSE;
566}
567
68de3f33 568/*
569** Returns true if c2 starts with the same path as c1
570**
571** This is called by context_isSystemDir to determine if a
572** directory is on the system path.
573**
574** In unix, this is just a string comparison. For Win32 and OS2, we need a more
575** complex comparison.
576*/
577
578bool osd_equalCanonicalPrefix (cstring dirpath, cstring prefixpath)
579{
580 llassert (cstring_isDefined (prefixpath));
581
582 if (cstring_isEmpty (dirpath))
583 {
584 return (cstring_isEmpty (prefixpath));
585 }
586
587# if defined (WIN32) || defined (OS2)
588
589 /*@access cstring@*/ /* Moved this from cstring - should abstract it... */
590
591 /*
592 ** If one has a drive specification, but the other doesn't, skip it.
593 */
594
595 if (strchr (dirpath, ':') == NULL
596 && strchr (prefixpath, ':') != NULL)
597 {
598 prefixpath = strchr (prefixpath, ':') + 1;
599 }
600 else
601 {
602 if (strchr (prefixpath, ':') == NULL
603 && strchr (dirpath, ':') != NULL)
604 {
605 dirpath = strchr (dirpath, ':') + 1;
606 }
607 }
608
609 {
610 int len = size_toInt (strlen (prefixpath));
611 int i = 0;
612 int slen = 0;
613
614 for (i = 0, slen = 0; i < len; i++, slen++)
615 {
616 /* Allow any number of connect characters in any combination:
617 * c:/usr//src\/foo == c:\\usr/src\/foo
618 * After this we'll be at the last of such a sequence */
619
620 if (osd_isConnectChar (dirpath[slen]) && osd_isConnectChar (prefixpath[i]))
621 {
622 /* Skip one or more connect chars */
623
624 for (; osd_isConnectChar (dirpath[slen+1]); ++slen)
625 {
626 ;
627 }
628
629 for (; osd_isConnectChar (prefixpath[i+1]); ++i)
630 {
631 ;
632 }
633 }
634 /* Windows, MSDOS and OS/2 use case-insensitive path specs! */
635 else if (toupper (dirpath[slen]) != toupper (prefixpath[i]))
636 {
637 return FALSE;
638 }
639
640 }
641 }
642
643 /*@noaccess cstring@*/
644
645 return TRUE;
646# else
647 return (cstring_equalPrefix (dirpath, prefixpath));
648# endif
649}
650
This page took 4.821691 seconds and 5 git commands to generate.