2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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.
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
27 ** replaces filenamemap.c
28 ** based (loosely) on typeTable.c
30 ** entries in the fileTable are:
32 ** name - name of the file
33 ** type - kind of file (a temp file to be deleted?)
34 ** link - derived from this file
39 * - Added conditional stuff (macros OS2 and MSDOS) to make names of temporary
40 * files under Windows or OS/2 not larger than 8+3 characters to avoid
41 * trouble with FAT file systems or Novell Netware volumes.
42 * - Added include of new header file portab.h containing OS dependent stuff.
43 * - Changed occurance of '/' as path delimiter to a macro.
44 * - Added conditional stuff (#define and #include) for IBM's compiler.
47 # include "lclintMacros.nf"
52 # if defined(__IBMC__) && defined(OS2)
54 # define getpid _getpid
59 static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/
61 return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
64 static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e)
66 static /*@only@*/ char *makeTempName (char *p_dir, char *p_pre, char *p_suf);
68 static /*@only@*/ cstring
69 fileType_unparse (fileType ft)
73 case FILE_NORMAL: return cstring_makeLiteral ("normal");
74 case FILE_NODELETE: return cstring_makeLiteral ("normal");
75 case FILE_LSLTEMP: return cstring_makeLiteral ("ltemp");
76 case FILE_HEADER: return cstring_makeLiteral ("header");
77 case FILE_MACROS: return cstring_makeLiteral ("macros");
84 fileTable_getIndex (fileTable ft, cstring s)
86 if (ft == NULL) return NOT_FOUND;
87 return (hashTable_lookup (ft->htable, s));
91 fileTable_unparse (fileTable ft)
93 cstring s = cstring_undefined;
96 if (fileTable_isUndefined (ft))
98 return (cstring_makeLiteral ("<fileTable undefined>"));
101 for (i = 0; i < ft->nentries; i++)
103 if (fileId_isValid (ft->elements[i]->fder))
105 s = message ("%s\n[%d] %s %q %d (%s)",
107 ft->elements[i]->fname,
108 fileType_unparse (ft->elements[i]->ftype),
109 ft->elements[i]->fder,
110 ft->elements[ft->elements[i]->fder]->fname);
114 s = message ("%s\n[%d] %s %q", s, i, ft->elements[i]->fname,
115 fileType_unparse (ft->elements[i]->ftype));
122 void fileTable_printTemps (fileTable ft)
124 if (fileTable_isDefined (ft))
128 for (i = 0; i < ft->nentries; i++)
130 if (ft->elements[i]->ftemp)
132 if (fileId_isValid (ft->elements[i]->fder))
134 fprintf (stderr, " %s:1\n\t%s:1\n",
135 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
136 cstring_toCharsSafe (ft->elements[i]->fname));
140 fprintf (stderr, "[no file]\n\t%s:1\n",
141 cstring_toCharsSafe (ft->elements[i]->fname));
149 ** loads in fileTable from fileTable_dump
152 static /*@notnull@*/ ftentry
153 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
155 ftentry t = (ftentry) dmalloc (sizeof (*t));
157 if (cstring_isUndefined (tn))
159 llbug (cstring_makeLiteral ("Undefined filename!"));
164 t->basename = cstring_undefined;
169 /* Don't set these until the basename is needed. */
177 ftentry_free (/*@only@*/ ftentry t)
179 cstring_free (t->fname);
180 cstring_free (t->basename);
184 /*@only@*/ /*@notnull@*/ fileTable
187 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
190 ft->nspace = FTBASESIZE;
191 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
192 ft->htable = hashTable_create (FTHASHSIZE);
198 fileTable_grow (fileTable ft)
203 llassert (fileTable_isDefined (ft));
205 ft->nspace = FTBASESIZE;
207 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
209 for (i = 0; i < ft->nentries; i++)
211 newent[i] = ft->elements[i];
214 sfree (ft->elements);
215 ft->elements = newent;
219 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
221 llassert (fileTable_isDefined (ft));
228 hashTable_insert (ft->htable, e->fname, ft->nentries);
229 ft->elements[ft->nentries] = e;
232 return (ft->nentries - 1);
235 void fileTable_noDelete (fileTable ft, cstring name)
237 fileId fid = fileTable_lookup (ft, name);
239 if (fileId_isValid (fid)) {
240 llassert (fileTable_isDefined (ft));
242 ft->elements[fid]->ftype = FILE_NODELETE;
247 fileTable_addFilePrim (fileTable ft, /*@only@*/ cstring name,
248 bool temp, fileType typ, fileId der)
251 int tindex = fileTable_getIndex (ft, name);
253 llassert (ft != fileTable_undefined);
255 if (tindex != NOT_FOUND)
257 llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", name));
263 ftentry e = ftentry_create (name, temp, typ, der);
265 if (der == fileId_invalid)
267 llassert (cstring_isUndefined (e->basename));
269 e->basename = cstring_fromChars
270 (removePathFree (removeAnyExtension
271 (cstring_toCharsSafe (name))));
272 e->fsystem = context_isSystemDir (name);
273 e->fspecial = context_isSpecialFile (name);
277 cstring srcname = cstring_concatFree (cstring_fromChars (removeAnyExtension (cstring_toCharsSafe (name))), cstring_makeLiteral (".c"));
278 fileId fid = fileTable_lookup (ft, srcname);
280 cstring_free (srcname);
282 if (fileId_isValid (fid))
284 fileId derid = ft->elements[fid]->fder;
286 ft->elements[fid]->fspecial = TRUE;
288 if (fileId_isValid (derid))
290 ft->elements[derid]->fspecial = TRUE;
297 ftentry de = ft->elements[der];
299 llassert (cstring_isUndefined (e->basename));
300 e->basename = cstring_copy (de->basename);
301 e->fsystem = de->fsystem;
302 e->fspecial = de->fspecial;
305 return (fileTable_internAddEntry (ft, e));
310 fileTable_addFile (fileTable ft, cstring name)
312 /* while (*name == '.' && *(name + 1) == '/') name += 2; */
313 return (fileTable_addFilePrim (ft, cstring_copy (name),
314 FALSE, FILE_NORMAL, fileId_invalid));
318 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
320 return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
324 fileTable_addHeaderFile (fileTable ft, cstring name)
326 return (fileTable_addFilePrim (ft, cstring_copy (name), FALSE,
327 FILE_HEADER, fileId_invalid));
331 fileTable_isHeader (fileTable ft, fileId fid)
333 if (fileId_isInvalid (fid))
338 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
339 return (ft->elements[fid]->ftype == FILE_HEADER);
343 fileTable_isSystemFile (fileTable ft, fileId fid)
345 if (fileId_isInvalid (fid))
350 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
351 return (ft->elements[fid]->fsystem);
355 fileTable_isSpecialFile (fileTable ft, fileId fid)
357 if (fileId_isInvalid (fid))
362 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
363 return (ft->elements[fid]->fspecial);
367 fileTable_addLibraryFile (fileTable ft, cstring name)
369 return (fileTable_addFilePrim (ft, cstring_copy (name),
370 FALSE, FILE_HEADER, fileId_invalid));
375 fileTable_addImportFile (fileTable ft, cstring name)
377 return (fileTable_addFilePrim (ft, cstring_copy (name),
378 FALSE, FILE_HEADER, fileId_invalid));
382 fileTable_addLCLFile (fileTable ft, cstring name)
384 return (fileTable_addFilePrim (ft, cstring_copy (name),
385 FALSE, FILE_HEADER, fileId_invalid));
390 static int tmpcounter = 0;
394 fileTable_addMacrosFile (fileTable ft)
396 cstring newname = cstring_fromChars
397 (makeTempName (cstring_toCharsSafe (context_tmpdir ()), "lmx", ".llm"));
399 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid));
403 fileTable_addCTempFile (fileTable ft, fileId fid)
406 /* Can't control output file name for cl preprocessor */
407 cstring newname = cstring_concatChars (removeAnyExtension (fileName (fid)), ".i");
409 cstring newname = cstring_fromChars
410 (makeTempName (cstring_toCharsSafe (context_tmpdir ()), "cl", ".c"));
413 llassert (fileTable_isDefined (ft));
415 if (!fileId_isValid (ft->elements[fid]->fder))
417 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid));
421 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
422 ft->elements[fid]->fder));
428 fileTable_addltemp (fileTable ft)
430 char *newname = makeTempName (cstring_toCharsSafe (context_tmpdir ()),
435 if (cstring_hasNonAlphaNumBar (cstring_fromChars (newname)))
437 char *lastpath = (char *)NULL;
443 ("Operating system generates tmp filename containing invalid charater: %s",
444 cstring_fromChars (newname)));
445 lldiagmsg (cstring_makeLiteral
446 ("Try cleaning up the tmp directory. Attempting to continue."));
449 lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
450 llassert (lastpath != NULL);
454 newname = cstring_toCharsSafe (message ("%s%hlsl%d.lsl",
455 cstring_fromChars (newname),
463 ** this is kind of yucky...need to make the result of cstring_fromChars
464 ** refer to the same storage as its argument. Of course, this loses,
465 ** since cstring is abstract. Should make it an only?
468 ret = fileTable_addFilePrim (ft, cstring_copy (cstring_fromChars (newname)),
469 TRUE, FILE_LSLTEMP, fileId_invalid);
476 fileTable_exists (fileTable ft, cstring s)
478 int tindex = fileTable_getIndex (ft, s);
480 if (tindex == NOT_FOUND)
487 fileTable_lookup (fileTable ft, cstring s)
489 int tindex = fileTable_getIndex (ft, s);
491 if (tindex == NOT_FOUND)
493 return fileId_invalid;
502 fileTable_lookupBase (fileTable ft, cstring base)
504 int tindex = fileTable_getIndex (ft, base);
506 if (tindex == NOT_FOUND)
509 return fileId_invalid;
515 llassert (fileTable_isDefined (ft));
517 der = ft->elements[tindex]->fder;
519 if (!fileId_isValid (der))
529 fileTable_getName (fileTable ft, fileId fid)
531 if (!fileId_isValid (fid))
534 (message ("fileTable_getName: called with invalid type id: %d", fid));
535 return cstring_makeLiteralTemp ("<invalid>");
538 llassert (fileTable_isDefined (ft));
539 return (ft->elements[fid]->fname);
543 fileTable_getRootName (fileTable ft, fileId fid)
547 if (!fileId_isValid (fid))
549 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
550 return cstring_makeLiteralTemp ("<invalid>");
553 if (!fileTable_isDefined (ft))
555 return cstring_makeLiteralTemp ("<no file table>");
558 if (fid >= ft->nentries)
560 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
561 // fprintf(stderr, "\nbad\n");
562 return cstring_makeLiteralTemp ("<invalid>");
565 fder = ft->elements[fid]->fder;
567 if (fileId_isValid (fder))
569 return (ft->elements[fder]->fname);
573 return (ft->elements[fid]->fname);
578 fileTable_getNameBase (fileTable ft, fileId fid)
580 if (!fileId_isValid (fid))
582 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
583 return cstring_makeLiteralTemp ("<invalid>");
586 if (!fileTable_isDefined (ft))
588 return cstring_makeLiteralTemp ("<no file table>");
591 return (ft->elements[fid]->basename);
595 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
599 if (!fileId_isValid (f1))
604 if (!fileId_isValid (f2))
609 llassert (fileTable_isDefined (ft));
616 fd1 = ft->elements[f1]->fder;
618 if (!fileId_isValid (fd1))
623 fd2 = ft->elements[f2]->fder;
626 if (!fileId_isValid (fd2))
635 fileTable_cleanup (fileTable ft)
641 llassert (fileTable_isDefined (ft));
643 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
644 skip = ft->nentries / 10;
648 (void) fflush (g_msgstream);
649 fprintf (stderr, "< cleaning");
652 for (i = 0; i < ft->nentries; i++)
654 ftentry fe = ft->elements[i];
658 /* let's be real careful now, hon! */
661 ** Make sure it is really a derived file
664 if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
666 ; /* already removed */
668 else if (fileId_isValid (fe->fder))
670 (void) osd_unlink (cstring_toCharsSafe (fe->fname));
672 else if (fe->ftype == FILE_MACROS)
674 (void) osd_unlink (cstring_toCharsSafe (fe->fname));
678 llbug (message ("Temporary file is not derivative: %s "
679 "(not deleted)", fe->fname));
687 if (msg && ((i % skip) == 0))
689 (void) fflush (g_msgstream);
692 fprintf (stderr, " ");
694 fprintf (stderr, ".");
697 (void) fflush (stderr);
703 fprintf (stderr, " >\n");
708 fileTable_free (/*@only@*/ fileTable f)
712 if (f == (fileTable)NULL)
717 while ( i < f->nentries )
719 ftentry_free (f->elements[i]);
723 hashTable_free (f->htable);
729 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
730 ** requires: <dir> must end in '/'
733 static void nextMsg (char *msg)
763 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
771 static /*@only@*/ char *makeTempName (char *dir, char *pre, char *suf)
774 static /*@owned@*/ char *msg = NULL;
775 static /*@only@*/ char *pidname = NULL;
779 llassert (strlen (pre) <= 3);
782 ** We limit the temp name to 8 characters:
790 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
795 /*@+matchanyintegral@*/
797 /*@=matchanyintegral@*/
802 pidname = cstring_toCharsSafe (message ("%d", pid % 100));
806 pidname = mstring_createEmpty ();
809 maxlen = (strlen (dir) + strlen (pre) + strlen (msg)
810 + strlen (pidname) + strlen (suf) + 2);
812 buf = mstring_create (size_toInt (maxlen));
814 sprintf (buf, "%s%s%s%s%s", dir, pre, pidname, msg, suf);
817 while (osd_fileExists (buf))
819 sprintf (buf, "%s%s%s%s%s", dir, pre, pidname, msg, suf);