2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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@*/ cstring makeTempName (cstring p_dir, cstring p_pre, cstring 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_XH: return cstring_makeLiteral ("xh");
78 case FILE_MACROS: return cstring_makeLiteral ("macros");
79 case FILE_METASTATE: return cstring_makeLiteral ("metastate");
86 fileTable_getIndex (fileTable ft, cstring s)
90 if (ft == NULL) return NOT_FOUND;
91 abspath = osd_absolutePath (cstring_undefined, s);
92 res = cstringTable_lookup (ft->htable, abspath);
93 cstring_free (abspath);
98 fileTable_unparse (fileTable ft)
100 cstring s = cstring_undefined;
103 if (fileTable_isUndefined (ft))
105 return (cstring_makeLiteral ("<fileTable undefined>"));
108 for (i = 0; i < ft->nentries; i++)
110 if (fileId_isValid (ft->elements[i]->fder))
112 s = message ("%s\n[%d] %s %q %d (%s)",
114 ft->elements[i]->fname,
115 fileType_unparse (ft->elements[i]->ftype),
116 ft->elements[i]->fder,
117 ft->elements[ft->elements[i]->fder]->fname);
121 s = message ("%s\n[%d] %s %q", s, i, ft->elements[i]->fname,
122 fileType_unparse (ft->elements[i]->ftype));
129 void fileTable_printTemps (fileTable ft)
131 if (fileTable_isDefined (ft))
135 for (i = 0; i < ft->nentries; i++)
137 if (ft->elements[i]->ftemp)
139 if (fileId_isValid (ft->elements[i]->fder))
141 fprintf (stderr, " %s:1\n\t%s:1\n",
142 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
143 cstring_toCharsSafe (ft->elements[i]->fname));
147 fprintf (stderr, "[no file]\n\t%s:1\n",
148 cstring_toCharsSafe (ft->elements[i]->fname));
156 ** loads in fileTable from fileTable_dump
159 static /*@notnull@*/ ftentry
160 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
162 ftentry t = (ftentry) dmalloc (sizeof (*t));
164 if (cstring_isUndefined (tn))
166 llbug (cstring_makeLiteral ("Undefined filename!"));
171 t->basename = cstring_undefined;
176 /* Don't set these until the basename is needed. */
184 ftentry_free (/*@only@*/ ftentry t)
186 cstring_free (t->fname);
187 cstring_free (t->basename);
191 /*@only@*/ /*@notnull@*/ fileTable
194 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
197 ft->nspace = FTBASESIZE;
198 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
199 ft->htable = cstringTable_create (FTHASHSIZE);
202 ft->nopenspace = FTBASESIZE;
203 ft->openelements = (foentry *) dmalloc (FTBASESIZE * sizeof (*ft->openelements));
209 fileTable_grow (fileTable ft)
214 llassert (fileTable_isDefined (ft));
216 ft->nspace = FTBASESIZE;
218 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
220 for (i = 0; i < ft->nentries; i++)
222 newent[i] = ft->elements[i];
225 sfree (ft->elements);
226 ft->elements = newent;
230 fileTable_growOpen (fileTable ft)
235 llassert (fileTable_isDefined (ft));
237 ft->nopenspace = FTBASESIZE;
239 newent = (foentry *) dmalloc ((ft->nopen + ft->nopenspace) * sizeof (*newent));
241 for (i = 0; i < ft->nopen; i++)
243 newent[i] = ft->openelements[i];
246 sfree (ft->openelements);
247 ft->openelements = newent;
251 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
253 llassert (fileTable_isDefined (ft));
260 cstringTable_insert (ft->htable, e->fname, ft->nentries);
261 ft->elements[ft->nentries] = e;
264 return (ft->nentries - 1);
267 void fileTable_noDelete (fileTable ft, cstring name)
269 fileId fid = fileTable_lookup (ft, name);
271 if (fileId_isValid (fid)) {
272 llassert (fileTable_isDefined (ft));
274 ft->elements[fid]->ftype = FILE_NODELETE;
279 fileTable_addFilePrim (fileTable ft, /*@temp@*/ cstring name,
280 bool temp, fileType typ, fileId der)
283 cstring absname = osd_absolutePath (NULL, name);
284 int tindex = fileTable_getIndex (ft, absname);
286 llassert (ft != fileTable_undefined);
288 if (tindex != NOT_FOUND)
290 llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", absname));
295 ftentry e = ftentry_create (absname, temp, typ, der);
297 if (der == fileId_invalid)
299 llassert (cstring_isUndefined (e->basename));
301 e->basename = fileLib_removePathFree (fileLib_removeAnyExtension (absname));
302 e->fsystem = context_isSystemDir (absname);
303 e->fspecial = context_isSpecialFile (absname);
307 cstring srcname = cstring_concatFree1 (fileLib_removeAnyExtension (absname),
309 fileId fid = fileTable_lookup (ft, srcname);
310 cstring_free (srcname);
312 if (fileId_isValid (fid))
314 fileId derid = ft->elements[fid]->fder;
316 ft->elements[fid]->fspecial = TRUE;
318 if (fileId_isValid (derid))
320 ft->elements[derid]->fspecial = TRUE;
327 ftentry de = ft->elements[der];
329 llassert (cstring_isUndefined (e->basename));
330 e->basename = cstring_copy (de->basename);
331 e->fsystem = de->fsystem;
332 e->fspecial = de->fspecial;
335 return (fileTable_internAddEntry (ft, e));
340 fileTable_addFile (fileTable ft, cstring name)
342 return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
346 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
348 fileId res = fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid);
354 fileTable_addHeaderFile (fileTable ft, cstring name)
357 res = fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid);
363 fileTable_isHeader (fileTable ft, fileId fid)
365 if (fileId_isInvalid (fid))
370 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
371 return (ft->elements[fid]->ftype == FILE_HEADER);
375 fileTable_isSystemFile (fileTable ft, fileId fid)
377 if (fileId_isInvalid (fid))
382 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
383 return (ft->elements[fid]->fsystem);
387 fileTable_isXHFile (fileTable ft, fileId fid)
389 if (fileId_isInvalid (fid))
394 if (!(fileTable_isDefined (ft) && fileTable_inRange (ft, fid)))
396 llcontbug (message ("Bad file table or id: %s %d", bool_unparse (fileTable_isDefined (ft)), fid));
401 return (ft->elements[fid]->ftype == FILE_XH);
406 fileTable_isSpecialFile (fileTable ft, fileId fid)
408 if (fileId_isInvalid (fid))
413 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
414 return (ft->elements[fid]->fspecial);
418 fileTable_addLibraryFile (fileTable ft, cstring name)
420 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
424 fileTable_addXHFile (fileTable ft, cstring name)
426 return (fileTable_addFilePrim (ft, name, FALSE, FILE_XH, fileId_invalid));
431 fileTable_addImportFile (fileTable ft, cstring name)
433 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
437 fileTable_addLCLFile (fileTable ft, cstring name)
439 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
444 static int tmpcounter = 0;
448 fileTable_addMacrosFile (fileTable ft)
451 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("lmx"),
452 cstring_makeLiteralTemp (".llm"));
453 fileId res = fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid);
454 cstring_free (newname);
459 fileTable_addMetastateFile (fileTable ft, cstring name)
461 return (fileTable_addFilePrim (ft, name, FALSE, FILE_METASTATE, fileId_invalid));
465 fileTable_addCTempFile (fileTable ft, fileId fid)
468 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("cl"),
472 llassert (fileTable_isDefined (ft));
474 if (!fileId_isValid (ft->elements[fid]->fder))
476 if (fileTable_isXHFile (ft, fid))
478 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH, fid);
482 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid);
487 if (fileTable_isXHFile (ft, fid))
489 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH,
490 ft->elements[fid]->fder);
494 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
495 ft->elements[fid]->fder);
499 cstring_free (newname);
505 fileTable_addltemp (fileTable ft)
507 cstring newname = makeTempName (context_tmpdir (),
508 cstring_makeLiteralTemp ("ls"),
509 cstring_makeLiteralTemp (".lsl"));
512 if (cstring_hasNonAlphaNumBar (newname))
514 char *lastpath = (char *)NULL;
520 ("Operating system generates tmp filename containing invalid charater: %s",
522 lldiagmsg (cstring_makeLiteral
523 ("Try cleaning up the tmp directory. Attempting to continue."));
527 llassert (cstring_isDefined (newname));
528 lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
529 llassert (lastpath != NULL);
532 newname = message ("%q%hlsl%d.lsl",
536 /*@noaccess cstring@*/
541 ** this is kind of yucky...need to make the result of cstring_fromChars
542 ** refer to the same storage as its argument. Of course, this loses,
543 ** since cstring is abstract. Should make it an only?
546 ret = fileTable_addFilePrim (ft, newname, TRUE, FILE_LSLTEMP, fileId_invalid);
547 cstring_free (newname);
553 fileTable_exists (fileTable ft, cstring s)
555 int tindex = fileTable_getIndex (ft, s);
557 if (tindex == NOT_FOUND)
564 fileTable_lookup (fileTable ft, cstring s)
566 int tindex = fileTable_getIndex (ft, s);
568 if (tindex == NOT_FOUND)
570 return fileId_invalid;
579 ** This is pretty awkward --- when we find the real path of
580 ** a .xh file, we may need to change the recorded name. [Sigh]
584 fileTable_setFilePath (fileTable ft, fileId fid, cstring path)
586 llassert (fileId_isValid (fid));
587 llassert (fileTable_isDefined (ft));
588 /* Need to put new string in hash table */
589 cstringTable_insert (ft->htable, cstring_copy (path), fid);
590 ft->elements[fid]->fname = cstring_copy (path);
594 fileTable_lookupBase (fileTable ft, cstring base)
596 int tindex = fileTable_getIndex (ft, base);
598 if (tindex == NOT_FOUND)
600 return fileId_invalid;
606 llassert (fileTable_isDefined (ft));
608 der = ft->elements[tindex]->fder;
610 if (!fileId_isValid (der))
620 fileTable_getName (fileTable ft, fileId fid)
622 if (!fileId_isValid (fid))
625 (message ("fileTable_getName: called with invalid type id: %d", fid));
626 return cstring_makeLiteralTemp ("<invalid>");
629 llassert (fileTable_isDefined (ft));
630 return (ft->elements[fid]->fname);
634 fileTable_getRootName (fileTable ft, fileId fid)
638 if (!fileId_isValid (fid))
640 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
641 return cstring_makeLiteralTemp ("<invalid>");
644 if (!fileTable_isDefined (ft))
646 return cstring_makeLiteralTemp ("<no file table>");
649 fder = ft->elements[fid]->fder;
651 if (fileId_isValid (fder))
653 return (ft->elements[fder]->fname);
657 return (ft->elements[fid]->fname);
662 fileTable_getNameBase (fileTable ft, fileId fid)
664 if (!fileId_isValid (fid))
666 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
667 return cstring_makeLiteralTemp ("<invalid>");
670 if (!fileTable_isDefined (ft))
672 return cstring_makeLiteralTemp ("<no file table>");
675 return (ft->elements[fid]->basename);
679 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
683 if (!fileId_isValid (f1))
688 if (!fileId_isValid (f2))
693 llassert (fileTable_isDefined (ft));
700 fd1 = ft->elements[f1]->fder;
702 if (!fileId_isValid (fd1))
707 fd2 = ft->elements[f2]->fder;
710 if (!fileId_isValid (fd2))
719 fileTable_cleanup (fileTable ft)
725 llassert (fileTable_isDefined (ft));
727 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
728 skip = ft->nentries / 10;
732 (void) fflush (g_msgstream);
733 fprintf (stderr, "< cleaning");
736 for (i = 0; i < ft->nentries; i++)
738 ftentry fe = ft->elements[i];
742 /* let's be real careful now, hon! */
745 ** Make sure it is really a derived file
748 if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
750 ; /* already removed */
752 else if (fileId_isValid (fe->fder))
754 /*@i423 this should use close (fd) also... */
755 (void) osd_unlink (fe->fname);
757 else if (fe->ftype == FILE_MACROS)
759 (void) osd_unlink (fe->fname);
763 llbug (message ("Temporary file is not derivative: %s "
764 "(not deleted)", fe->fname));
772 if (msg && ((i % skip) == 0))
774 (void) fflush (g_msgstream);
777 fprintf (stderr, " ");
779 fprintf (stderr, ".");
782 (void) fflush (stderr);
788 fprintf (stderr, " >\n");
793 fileTable_free (/*@only@*/ fileTable f)
797 if (f == (fileTable)NULL)
802 while ( i < f->nentries )
804 ftentry_free (f->elements[i]);
808 cstringTable_free (f->htable);
814 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
815 ** requires: <dir> must end in '/'
818 static void nextMsg (char *msg)
848 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
856 static /*@only@*/ cstring makeTempName (cstring dir, cstring pre, cstring suf)
859 static /*@owned@*/ char *msg = NULL;
860 static /*@only@*/ cstring pidname = NULL;
864 llassert (cstring_length (pre) <= 3);
867 ** We limit the temp name to 8 characters:
875 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
880 /*@+matchanyintegral@*/
882 /*@=matchanyintegral@*/
885 if (cstring_isUndefined (pidname))
887 pidname = message ("%d", pid % 100);
890 maxlen = (cstring_length (dir) + cstring_length (pre) + mstring_length (msg)
891 + cstring_length (pidname) + cstring_length (suf) + 2);
893 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
896 while (osd_fileExists (smsg))
899 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
908 foentry_create (/*@exposed@*/ FILE *f, /*@only@*/ cstring fname)
910 foentry t = (foentry) dmalloc (sizeof (*t));
917 foentry_free (/*@only@*/ foentry foe)
919 cstring_free (foe->fname);
924 fileTable_addOpen (fileTable ft, /*@observer@*/ FILE *f, /*@only@*/ cstring fname)
926 llassert (fileTable_isDefined (ft));
928 if (ft->nopenspace <= 0)
930 fileTable_growOpen (ft);
934 ft->openelements[ft->nopen] = foentry_create (f, fname);
938 FILE *fileTable_openFile (fileTable ft, cstring fname, char *mode)
940 FILE *res = fopen (cstring_toCharsSafe (fname), mode);
943 fileTable_addOpen (ft, res, cstring_copy (fname));
944 DPRINTF (("Opening file: %s / %p", fname, res));
950 bool fileTable_closeFile (fileTable ft, FILE *f)
952 bool foundit = FALSE;
955 llassert (fileTable_isDefined (ft));
957 DPRINTF (("Closing file: %p", f));
959 for (i = 0; i < ft->nopen; i++)
961 if (ft->openelements[i]->f == f)
963 DPRINTF (("Closing file: %p = %s", f, ft->openelements[i]->fname));
965 if (i == ft->nopen - 1)
967 foentry_free (ft->openelements[i]);
968 ft->openelements[i] = NULL;
972 foentry_free (ft->openelements[i]);
973 ft->openelements[i] = ft->openelements[ft->nopen - 1];
974 ft->openelements[ft->nopen - 1] = NULL;
985 return (fclose (f) == 0);
988 void fileTable_closeAll (fileTable ft)
992 for (i = 0; i < ft->nopen; i++)
995 lldiagmsg (message ("Unclosed file at exit: %s", ft->openelements[i]->fname));
998 (void) fclose (ft->openelements[i]->f); /* No check - cleaning up after errors */
999 ft->openelements[i]->f = NULL;
1000 foentry_free (ft->openelements[i]);
1001 ft->openelements[i] = NULL;
1004 ft->nopenspace += ft->nopen;