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)
88 if (ft == NULL) return NOT_FOUND;
89 return (cstringTable_lookup (ft->htable, s));
93 fileTable_unparse (fileTable ft)
95 cstring s = cstring_undefined;
98 if (fileTable_isUndefined (ft))
100 return (cstring_makeLiteral ("<fileTable undefined>"));
103 for (i = 0; i < ft->nentries; i++)
105 if (fileId_isValid (ft->elements[i]->fder))
107 s = message ("%s\n[%d] %s %q %d (%s)",
109 ft->elements[i]->fname,
110 fileType_unparse (ft->elements[i]->ftype),
111 ft->elements[i]->fder,
112 ft->elements[ft->elements[i]->fder]->fname);
116 s = message ("%s\n[%d] %s %q", s, i, ft->elements[i]->fname,
117 fileType_unparse (ft->elements[i]->ftype));
124 void fileTable_printTemps (fileTable ft)
126 if (fileTable_isDefined (ft))
130 for (i = 0; i < ft->nentries; i++)
132 if (ft->elements[i]->ftemp)
134 if (fileId_isValid (ft->elements[i]->fder))
136 fprintf (stderr, " %s:1\n\t%s:1\n",
137 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
138 cstring_toCharsSafe (ft->elements[i]->fname));
142 fprintf (stderr, "[no file]\n\t%s:1\n",
143 cstring_toCharsSafe (ft->elements[i]->fname));
151 ** loads in fileTable from fileTable_dump
154 static /*@notnull@*/ ftentry
155 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
157 ftentry t = (ftentry) dmalloc (sizeof (*t));
159 if (cstring_isUndefined (tn))
161 llbug (cstring_makeLiteral ("Undefined filename!"));
166 t->basename = cstring_undefined;
171 /* Don't set these until the basename is needed. */
179 ftentry_free (/*@only@*/ ftentry t)
181 cstring_free (t->fname);
182 cstring_free (t->basename);
186 /*@only@*/ /*@notnull@*/ fileTable
189 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
192 ft->nspace = FTBASESIZE;
193 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
194 ft->htable = cstringTable_create (FTHASHSIZE);
200 fileTable_grow (fileTable ft)
205 llassert (fileTable_isDefined (ft));
207 ft->nspace = FTBASESIZE;
209 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
211 for (i = 0; i < ft->nentries; i++)
213 newent[i] = ft->elements[i];
216 sfree (ft->elements);
217 ft->elements = newent;
221 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
223 llassert (fileTable_isDefined (ft));
230 cstringTable_insert (ft->htable, e->fname, ft->nentries);
231 ft->elements[ft->nentries] = e;
234 return (ft->nentries - 1);
237 void fileTable_noDelete (fileTable ft, cstring name)
239 fileId fid = fileTable_lookup (ft, name);
241 if (fileId_isValid (fid)) {
242 llassert (fileTable_isDefined (ft));
244 ft->elements[fid]->ftype = FILE_NODELETE;
249 fileTable_addFilePrim (fileTable ft, /*@only@*/ cstring name,
250 bool temp, fileType typ, fileId der)
253 int tindex = fileTable_getIndex (ft, name);
255 llassert (ft != fileTable_undefined);
257 if (tindex != NOT_FOUND)
259 llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", name));
265 ftentry e = ftentry_create (name, temp, typ, der);
267 if (der == fileId_invalid)
269 llassert (cstring_isUndefined (e->basename));
271 e->basename = fileLib_removePathFree (fileLib_removeAnyExtension (name));
272 e->fsystem = context_isSystemDir (name);
273 e->fspecial = context_isSpecialFile (name);
277 cstring srcname = cstring_concatFree1 (fileLib_removeAnyExtension (name),
279 fileId fid = fileTable_lookup (ft, srcname);
281 cstring_free (srcname);
283 if (fileId_isValid (fid))
285 fileId derid = ft->elements[fid]->fder;
287 ft->elements[fid]->fspecial = TRUE;
289 if (fileId_isValid (derid))
291 ft->elements[derid]->fspecial = TRUE;
298 ftentry de = ft->elements[der];
300 llassert (cstring_isUndefined (e->basename));
301 e->basename = cstring_copy (de->basename);
302 e->fsystem = de->fsystem;
303 e->fspecial = de->fspecial;
306 return (fileTable_internAddEntry (ft, e));
311 fileTable_addFile (fileTable ft, cstring name)
313 /* while (*name == '.' && *(name + 1) == '/') name += 2; */
315 return (fileTable_addFilePrim (ft, cstring_copy (name),
316 FALSE, FILE_NORMAL, fileId_invalid));
320 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
322 return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
326 fileTable_addHeaderFile (fileTable ft, cstring name)
330 res = fileTable_addFilePrim (ft, cstring_copy (name), FALSE,
331 FILE_HEADER, fileId_invalid);
337 fileTable_isHeader (fileTable ft, fileId fid)
339 if (fileId_isInvalid (fid))
344 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
345 return (ft->elements[fid]->ftype == FILE_HEADER);
349 fileTable_isSystemFile (fileTable ft, fileId fid)
351 if (fileId_isInvalid (fid))
356 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
357 return (ft->elements[fid]->fsystem);
361 fileTable_isXHFile (fileTable ft, fileId fid)
363 if (fileId_isInvalid (fid))
368 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
369 return (ft->elements[fid]->ftype == FILE_XH);
373 fileTable_isSpecialFile (fileTable ft, fileId fid)
375 if (fileId_isInvalid (fid))
380 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
381 return (ft->elements[fid]->fspecial);
385 fileTable_addLibraryFile (fileTable ft, cstring name)
387 return (fileTable_addFilePrim (ft, cstring_copy (name),
388 FALSE, FILE_HEADER, fileId_invalid));
392 fileTable_addXHFile (fileTable ft, cstring name)
394 return (fileTable_addFilePrim (ft, cstring_copy (name),
395 FALSE, FILE_XH, fileId_invalid));
400 fileTable_addImportFile (fileTable ft, cstring name)
402 return (fileTable_addFilePrim (ft, cstring_copy (name),
403 FALSE, FILE_HEADER, fileId_invalid));
407 fileTable_addLCLFile (fileTable ft, cstring name)
409 return (fileTable_addFilePrim (ft, cstring_copy (name),
410 FALSE, FILE_HEADER, fileId_invalid));
415 static int tmpcounter = 0;
419 fileTable_addMacrosFile (fileTable ft)
422 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("lmx"),
423 cstring_makeLiteralTemp (".llm"));
425 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid));
429 fileTable_addMetastateFile (fileTable ft, cstring name)
431 return (fileTable_addFilePrim (ft, cstring_copy (name),
432 FALSE, FILE_METASTATE, fileId_invalid));
436 fileTable_addCTempFile (fileTable ft, fileId fid)
439 /* Can't control output file name for cl preprocessor */
440 cstring newname = cstring_concatChars (fileLib_removeAnyExtension (fileName (fid)), ".i");
443 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("cl"),
447 llassert (fileTable_isDefined (ft));
449 if (!fileId_isValid (ft->elements[fid]->fder))
451 if (fileTable_isXHFile (ft, fid))
453 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_XH, fid));
457 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid));
462 if (fileTable_isXHFile (ft, fid))
464 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_XH,
465 ft->elements[fid]->fder));
469 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
470 ft->elements[fid]->fder));
477 fileTable_addltemp (fileTable ft)
479 cstring newname = makeTempName (context_tmpdir (),
480 cstring_makeLiteralTemp ("ls"),
481 cstring_makeLiteralTemp (".lsl"));
484 if (cstring_hasNonAlphaNumBar (newname))
486 char *lastpath = (char *)NULL;
492 ("Operating system generates tmp filename containing invalid charater: %s",
494 lldiagmsg (cstring_makeLiteral
495 ("Try cleaning up the tmp directory. Attempting to continue."));
499 llassert (cstring_isDefined (newname));
500 lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
501 llassert (lastpath != NULL);
504 newname = message ("%q%hlsl%d.lsl",
508 /*@noaccess cstring@*/
513 ** this is kind of yucky...need to make the result of cstring_fromChars
514 ** refer to the same storage as its argument. Of course, this loses,
515 ** since cstring is abstract. Should make it an only?
518 ret = fileTable_addFilePrim (ft, cstring_copy (newname),
519 TRUE, FILE_LSLTEMP, fileId_invalid);
520 cstring_free (newname);
526 fileTable_exists (fileTable ft, cstring s)
528 int tindex = fileTable_getIndex (ft, s);
530 if (tindex == NOT_FOUND)
537 fileTable_lookup (fileTable ft, cstring s)
539 int tindex = fileTable_getIndex (ft, s);
541 if (tindex == NOT_FOUND)
543 return fileId_invalid;
552 ** This is pretty awkward --- when we find the real path of
553 ** a .xh file, we may need to change the recorded name. [Sigh]
557 fileTable_setFilePath (fileTable ft, fileId fid, cstring path)
559 llassert (fileId_isValid (fid));
560 llassert (fileTable_isDefined (ft));
561 /* Need to put new string in hash table */
562 cstringTable_insert (ft->htable, cstring_copy (path), fid);
563 ft->elements[fid]->fname = cstring_copy (path);
567 fileTable_lookupBase (fileTable ft, cstring base)
569 int tindex = fileTable_getIndex (ft, base);
571 if (tindex == NOT_FOUND)
573 return fileId_invalid;
579 llassert (fileTable_isDefined (ft));
581 der = ft->elements[tindex]->fder;
583 if (!fileId_isValid (der))
593 fileTable_getName (fileTable ft, fileId fid)
595 if (!fileId_isValid (fid))
598 (message ("fileTable_getName: called with invalid type id: %d", fid));
599 return cstring_makeLiteralTemp ("<invalid>");
602 llassert (fileTable_isDefined (ft));
603 return (ft->elements[fid]->fname);
607 fileTable_getRootName (fileTable ft, fileId fid)
611 if (!fileId_isValid (fid))
613 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
614 return cstring_makeLiteralTemp ("<invalid>");
617 if (!fileTable_isDefined (ft))
619 return cstring_makeLiteralTemp ("<no file table>");
622 fder = ft->elements[fid]->fder;
624 if (fileId_isValid (fder))
626 return (ft->elements[fder]->fname);
630 return (ft->elements[fid]->fname);
635 fileTable_getNameBase (fileTable ft, fileId fid)
637 if (!fileId_isValid (fid))
639 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
640 return cstring_makeLiteralTemp ("<invalid>");
643 if (!fileTable_isDefined (ft))
645 return cstring_makeLiteralTemp ("<no file table>");
648 return (ft->elements[fid]->basename);
652 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
656 if (!fileId_isValid (f1))
661 if (!fileId_isValid (f2))
666 llassert (fileTable_isDefined (ft));
673 fd1 = ft->elements[f1]->fder;
675 if (!fileId_isValid (fd1))
680 fd2 = ft->elements[f2]->fder;
683 if (!fileId_isValid (fd2))
692 fileTable_cleanup (fileTable ft)
698 llassert (fileTable_isDefined (ft));
700 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
701 skip = ft->nentries / 10;
705 (void) fflush (g_msgstream);
706 fprintf (stderr, "< cleaning");
709 for (i = 0; i < ft->nentries; i++)
711 ftentry fe = ft->elements[i];
715 /* let's be real careful now, hon! */
718 ** Make sure it is really a derived file
721 if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
723 ; /* already removed */
725 else if (fileId_isValid (fe->fder))
727 /*@i423 this should use close (fd) also... */
728 (void) osd_unlink (fe->fname);
730 else if (fe->ftype == FILE_MACROS)
732 (void) osd_unlink (fe->fname);
736 llbug (message ("Temporary file is not derivative: %s "
737 "(not deleted)", fe->fname));
745 if (msg && ((i % skip) == 0))
747 (void) fflush (g_msgstream);
750 fprintf (stderr, " ");
752 fprintf (stderr, ".");
755 (void) fflush (stderr);
761 fprintf (stderr, " >\n");
766 fileTable_free (/*@only@*/ fileTable f)
770 if (f == (fileTable)NULL)
775 while ( i < f->nentries )
777 ftentry_free (f->elements[i]);
781 cstringTable_free (f->htable);
787 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
788 ** requires: <dir> must end in '/'
791 static void nextMsg (char *msg)
821 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
829 static /*@only@*/ cstring makeTempName (cstring dir, cstring pre, cstring suf)
832 static /*@owned@*/ char *msg = NULL;
833 static /*@only@*/ cstring pidname = NULL;
837 llassert (cstring_length (pre) <= 3);
840 ** We limit the temp name to 8 characters:
848 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
853 /*@+matchanyintegral@*/
855 /*@=matchanyintegral@*/
858 if (cstring_isUndefined (pidname))
860 pidname = message ("%d", pid % 100);
863 maxlen = (cstring_length (dir) + cstring_length (pre) + mstring_length (msg)
864 + cstring_length (pidname) + cstring_length (suf) + 2);
866 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
869 while (osd_fileExists (smsg))
872 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);