2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
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 "splintMacros.nf"
52 # if defined(__IBMC__) && defined(OS2)
54 # define getpid _getpid
60 fileTable_addOpen (fileTable p_ft, /*@observer@*/ FILE *p_f, /*@only@*/ cstring p_fname)
63 static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/
65 return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
68 static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e)
70 static /*@only@*/ cstring makeTempName (cstring p_dir, cstring p_pre, cstring p_suf);
72 static /*@only@*/ cstring
73 fileType_unparse (fileType ft)
77 case FILE_NORMAL: return cstring_makeLiteral ("normal");
78 case FILE_NODELETE: return cstring_makeLiteral ("normal");
79 case FILE_LSLTEMP: return cstring_makeLiteral ("ltemp");
80 case FILE_HEADER: return cstring_makeLiteral ("header");
81 case FILE_XH: return cstring_makeLiteral ("xh");
82 case FILE_MACROS: return cstring_makeLiteral ("macros");
83 case FILE_METASTATE: return cstring_makeLiteral ("metastate");
90 fileTable_getIndex (fileTable ft, cstring s)
94 if (ft == NULL) return NOT_FOUND;
95 abspath = osd_absolutePath (cstring_undefined, s);
96 DPRINTF (("Absolute path: %s: %s", s, abspath));
97 res = cstringTable_lookup (ft->htable, abspath);
98 cstring_free (abspath);
102 static cstring ftentry_unparse (fileTable ft, ftentry fte)
104 if (fileId_isValid (fte->fder))
106 llassert (fileTable_isDefined (ft));
108 return message ("%s %q %d (%s)",
110 fileType_unparse (fte->ftype),
112 ft->elements[fte->fder]->fname);
116 return message ("%s %q", fte->fname,
117 fileType_unparse (fte->ftype));
122 fileTable_unparse (fileTable ft)
124 cstring s = cstring_undefined;
127 if (fileTable_isUndefined (ft))
129 return (cstring_makeLiteral ("<fileTable undefined>"));
132 for (i = 0; i < ft->nentries; i++)
134 s = message ("%s\n[%d] %q", s, i, ftentry_unparse (ft, ft->elements[i]));
140 void fileTable_printTemps (fileTable ft)
142 if (fileTable_isDefined (ft))
146 for (i = 0; i < ft->nentries; i++)
148 if (ft->elements[i]->ftemp)
150 if (fileId_isValid (ft->elements[i]->fder))
152 fprintf (stderr, " %s:1\n\t%s:1\n",
153 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
154 cstring_toCharsSafe (ft->elements[i]->fname));
158 fprintf (stderr, "[no file]\n\t%s:1\n",
159 cstring_toCharsSafe (ft->elements[i]->fname));
167 ** loads in fileTable from fileTable_dump
170 static /*@notnull@*/ ftentry
171 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
173 ftentry t = (ftentry) dmalloc (sizeof (*t));
175 if (cstring_isUndefined (tn))
177 llbug (cstring_makeLiteral ("Undefined filename!"));
182 t->basename = cstring_undefined;
187 /* Don't set these until the basename is needed. */
195 ftentry_free (/*@only@*/ ftentry t)
197 cstring_free (t->fname);
198 cstring_free (t->basename);
202 /*@only@*/ /*@notnull@*/ fileTable
205 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
208 ft->nspace = FTBASESIZE;
209 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
210 ft->htable = cstringTable_create (FTHASHSIZE);
213 ft->nopenspace = FTBASESIZE;
214 ft->openelements = (foentry *) dmalloc (FTBASESIZE * sizeof (*ft->openelements));
220 fileTable_grow (fileTable ft)
225 llassert (fileTable_isDefined (ft));
227 ft->nspace = FTBASESIZE;
229 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
231 for (i = 0; i < ft->nentries; i++)
233 newent[i] = ft->elements[i];
236 sfree (ft->elements);
237 ft->elements = newent;
241 fileTable_growOpen (fileTable ft)
246 llassert (fileTable_isDefined (ft));
248 ft->nopenspace = FTBASESIZE;
250 newent = (foentry *) dmalloc ((ft->nopen + ft->nopenspace) * sizeof (*newent));
252 for (i = 0; i < ft->nopen; i++)
254 newent[i] = ft->openelements[i];
257 sfree (ft->openelements);
258 ft->openelements = newent;
262 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
264 llassert (fileTable_isDefined (ft));
271 DPRINTF (("Adding: %s", e->fname));
272 cstringTable_insert (ft->htable, e->fname, ft->nentries);
273 ft->elements[ft->nentries] = e;
276 return (ft->nentries - 1);
279 void fileTable_noDelete (fileTable ft, cstring name)
281 fileId fid = fileTable_lookup (ft, name);
283 if (fileId_isValid (fid))
285 llassert (fileTable_isDefined (ft));
286 ft->elements[fid]->ftype = FILE_NODELETE;
290 DPRINTF (("Invalid no delete: %s", name));
295 fileTable_addFilePrim (fileTable ft, /*@temp@*/ cstring name,
296 bool temp, fileType typ, fileId der)
299 cstring absname = osd_absolutePath (NULL, name);
300 int tindex = fileTable_getIndex (ft, absname);
302 DPRINTF (("Got abs path: %s", absname));
303 llassert (ft != fileTable_undefined);
305 if (tindex != NOT_FOUND)
307 llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", absname));
312 ftentry e = ftentry_create (absname, temp, typ, der);
314 if (der == fileId_invalid)
316 llassert (cstring_isUndefined (e->basename));
318 e->basename = fileLib_removePathFree (fileLib_removeAnyExtension (absname));
319 e->fsystem = context_isSystemDir (absname);
322 ** evans 2002-03-15: change suggested by Jim Zelenka
323 ** support relative paths for system directories
328 e->fsystem = context_isSystemDir (name);
331 e->fspecial = context_isSpecialFile (absname);
335 cstring srcname = cstring_concatFree1 (fileLib_removeAnyExtension (absname),
337 fileId fid = fileTable_lookup (ft, srcname);
338 cstring_free (srcname);
340 if (fileId_isValid (fid))
342 fileId derid = ft->elements[fid]->fder;
344 ft->elements[fid]->fspecial = TRUE;
346 if (fileId_isValid (derid))
348 ft->elements[derid]->fspecial = TRUE;
355 ftentry de = ft->elements[der];
357 llassert (cstring_isUndefined (e->basename));
358 e->basename = cstring_copy (de->basename);
359 e->fsystem = de->fsystem;
360 e->fspecial = de->fspecial;
363 return (fileTable_internAddEntry (ft, e));
368 fileTable_addFile (fileTable ft, cstring name)
370 return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
374 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
376 fileId res = fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid);
382 fileTable_addHeaderFile (fileTable ft, cstring name)
385 res = fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid);
391 fileTable_addStreamFile (fileTable ft, FILE *fstream, cstring name)
393 fileTable_addOpen (ft, fstream, cstring_copy (name));
397 fileTable_isHeader (fileTable ft, fileId fid)
399 if (fileId_isInvalid (fid))
404 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
405 return (ft->elements[fid]->ftype == FILE_HEADER);
409 fileTable_isSystemFile (fileTable ft, fileId fid)
411 if (fileId_isInvalid (fid))
416 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
417 return (ft->elements[fid]->fsystem);
421 fileTable_isXHFile (fileTable ft, fileId fid)
423 if (fileId_isInvalid (fid))
428 if (!(fileTable_isDefined (ft) && fileTable_inRange (ft, fid)))
430 llcontbug (message ("Bad file table or id: %s %d", bool_unparse (fileTable_isDefined (ft)), fid));
435 return (ft->elements[fid]->ftype == FILE_XH);
440 fileTable_isSpecialFile (fileTable ft, fileId fid)
442 if (fileId_isInvalid (fid))
447 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
448 return (ft->elements[fid]->fspecial);
452 fileTable_addLibraryFile (fileTable ft, cstring name)
454 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
458 fileTable_addXHFile (fileTable ft, cstring name)
460 return (fileTable_addFilePrim (ft, name, FALSE, FILE_XH, fileId_invalid));
465 fileTable_addImportFile (fileTable ft, cstring name)
467 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
471 fileTable_addLCLFile (fileTable ft, cstring name)
473 return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
478 static int tmpcounter = 0;
482 fileTable_addMacrosFile (fileTable ft)
485 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("lmx"),
486 cstring_makeLiteralTemp (".llm"));
487 fileId res = fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid);
488 cstring_free (newname);
493 fileTable_addMetastateFile (fileTable ft, cstring name)
495 return (fileTable_addFilePrim (ft, name, FALSE, FILE_METASTATE, fileId_invalid));
499 fileTable_addCTempFile (fileTable ft, fileId fid)
502 makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("cl"),
506 DPRINTF (("tmp dir: %s", context_tmpdir ()));
507 DPRINTF (("new name: %s", newname));
509 llassert (fileTable_isDefined (ft));
511 if (!fileId_isValid (ft->elements[fid]->fder))
513 if (fileTable_isXHFile (ft, fid))
515 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH, fid);
519 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid);
524 if (fileTable_isXHFile (ft, fid))
526 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH,
527 ft->elements[fid]->fder);
531 res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
532 ft->elements[fid]->fder);
536 DPRINTF (("Added file: %s", fileTable_fileName (res)));
537 cstring_free (newname);
543 fileTable_addltemp (fileTable ft)
545 cstring newname = makeTempName (context_tmpdir (),
546 cstring_makeLiteralTemp ("ls"),
547 cstring_makeLiteralTemp (".lsl"));
550 if (cstring_hasNonAlphaNumBar (newname))
552 char *lastpath = (char *)NULL;
558 ("Operating system generates tmp filename containing invalid charater: %s",
560 lldiagmsg (cstring_makeLiteral
561 ("Try cleaning up the tmp directory. Attempting to continue."));
565 llassert (cstring_isDefined (newname));
566 lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
567 llassert (lastpath != NULL);
570 newname = message ("%q%hlsl%d.lsl",
574 /*@noaccess cstring@*/
579 ** this is kind of yucky...need to make the result of cstring_fromChars
580 ** refer to the same storage as its argument. Of course, this loses,
581 ** since cstring is abstract. Should make it an only?
584 ret = fileTable_addFilePrim (ft, newname, TRUE, FILE_LSLTEMP, fileId_invalid);
585 cstring_free (newname);
591 fileTable_exists (fileTable ft, cstring s)
593 int tindex = fileTable_getIndex (ft, s);
595 if (tindex == NOT_FOUND)
597 DPRINTF (("Not found: %s", s));
607 fileTable_lookup (fileTable ft, cstring s)
609 int tindex = fileTable_getIndex (ft, s);
611 if (tindex == NOT_FOUND)
613 return fileId_invalid;
622 ** This is pretty awkward --- when we find the real path of
623 ** a .xh file, we may need to change the recorded name. [Sigh]
627 fileTable_setFilePath (fileTable ft, fileId fid, cstring path)
629 llassert (fileId_isValid (fid));
630 llassert (fileTable_isDefined (ft));
631 /* Need to put new string in hash table */
632 cstringTable_insert (ft->htable, cstring_copy (path), fid);
633 ft->elements[fid]->fname = cstring_copy (path);
637 fileTable_lookupBase (fileTable ft, cstring base)
639 int tindex = fileTable_getIndex (ft, base);
641 if (tindex == NOT_FOUND)
643 return fileId_invalid;
649 llassert (fileTable_isDefined (ft));
651 der = ft->elements[tindex]->fder;
653 if (!fileId_isValid (der))
663 fileTable_getName (fileTable ft, fileId fid)
665 if (!fileId_isValid (fid))
668 (message ("fileTable_getName: called with invalid type id: %d", fid));
669 return cstring_makeLiteralTemp ("<invalid>");
672 llassert (fileTable_isDefined (ft));
673 return (ft->elements[fid]->fname);
677 fileTable_getRootName (fileTable ft, fileId fid)
681 if (!fileId_isValid (fid))
683 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
684 return cstring_makeLiteralTemp ("<invalid>");
687 if (!fileTable_isDefined (ft))
689 return cstring_makeLiteralTemp ("<no file table>");
692 fder = ft->elements[fid]->fder;
694 if (fileId_isValid (fder))
696 return (ft->elements[fder]->fname);
700 return (ft->elements[fid]->fname);
705 fileTable_getNameBase (fileTable ft, fileId fid)
707 if (!fileId_isValid (fid))
709 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
710 return cstring_makeLiteralTemp ("<invalid>");
713 if (!fileTable_isDefined (ft))
715 return cstring_makeLiteralTemp ("<no file table>");
718 return (ft->elements[fid]->basename);
722 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
726 if (!fileId_isValid (f1))
731 if (!fileId_isValid (f2))
736 llassert (fileTable_isDefined (ft));
743 fd1 = ft->elements[f1]->fder;
745 if (!fileId_isValid (fd1))
750 fd2 = ft->elements[f2]->fder;
753 if (!fileId_isValid (fd2))
762 fileTable_cleanup (fileTable ft)
768 llassert (fileTable_isDefined (ft));
770 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
771 skip = ft->nentries / 10;
775 (void) fflush (g_warningstream);
776 fprintf (stderr, "< cleaning");
779 for (i = 0; i < ft->nentries; i++)
781 ftentry fe = ft->elements[i];
785 /* let's be real careful now, hon! */
788 ** Make sure it is really a derived file
792 if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
794 ; /* already removed */
796 else if (fileId_isValid (fe->fder))
798 /*@i423 this should use close (fd) also... */
799 (void) osd_unlink (fe->fname);
801 else if (fe->ftype == FILE_MACROS)
803 (void) osd_unlink (fe->fname);
807 llbug (message ("Temporary file is not derivative: %s "
808 "(not deleted)", fe->fname));
816 if (msg && ((i % skip) == 0))
818 (void) fflush (g_warningstream);
821 fprintf (stderr, " ");
823 fprintf (stderr, ".");
826 (void) fflush (stderr);
832 fprintf (stderr, " >\n");
837 fileTable_free (/*@only@*/ fileTable f)
841 if (f == (fileTable)NULL)
846 while ( i < f->nentries )
848 ftentry_free (f->elements[i]);
852 cstringTable_free (f->htable);
858 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
859 ** requires: <dir> must end in '/'
862 static void nextMsg (char *msg)
892 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
900 static /*@only@*/ cstring makeTempName (cstring dir, cstring pre, cstring suf)
903 static /*@owned@*/ char *msg = NULL;
904 static /*@only@*/ cstring pidname = NULL;
908 llassert (cstring_length (pre) <= 3);
911 ** We limit the temp name to 8 characters:
919 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
924 /*@+matchanyintegral@*/
926 /*@=matchanyintegral@*/
929 if (cstring_isUndefined (pidname))
931 pidname = message ("%d", pid % 100);
934 maxlen = (cstring_length (dir) + cstring_length (pre) + mstring_length (msg)
935 + cstring_length (pidname) + cstring_length (suf) + 2);
937 DPRINTF (("Dir: %s / %s / %s / %s / %s",
938 dir, pre, pidname, msg, suf));
940 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
943 DPRINTF (("Trying: %s", smsg));
945 while (osd_fileExists (smsg))
948 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
957 foentry_create (/*@exposed@*/ FILE *f, /*@only@*/ cstring fname)
959 foentry t = (foentry) dmalloc (sizeof (*t));
966 foentry_free (/*@only@*/ foentry foe)
968 cstring_free (foe->fname);
973 fileTable_addOpen (fileTable ft, /*@observer@*/ FILE *f, /*@only@*/ cstring fname)
975 llassert (fileTable_isDefined (ft));
977 if (ft->nopenspace <= 0)
979 fileTable_growOpen (ft);
983 ft->openelements[ft->nopen] = foentry_create (f, fname);
987 FILE *fileTable_openFile (fileTable ft, cstring fname, char *mode)
989 FILE *res = fopen (cstring_toCharsSafe (fname), mode);
992 fileTable_addOpen (ft, res, cstring_copy (fname));
993 DPRINTF (("Opening file: %s / %p", fname, res));
999 bool fileTable_closeFile (fileTable ft, FILE *f)
1001 bool foundit = FALSE;
1004 llassert (fileTable_isDefined (ft));
1006 DPRINTF (("Closing file: %p", f));
1008 for (i = 0; i < ft->nopen; i++)
1010 if (ft->openelements[i]->f == f)
1012 DPRINTF (("Closing file: %p = %s", f, ft->openelements[i]->fname));
1014 if (i == ft->nopen - 1)
1016 foentry_free (ft->openelements[i]);
1017 ft->openelements[i] = NULL;
1021 foentry_free (ft->openelements[i]);
1022 ft->openelements[i] = ft->openelements[ft->nopen - 1];
1023 ft->openelements[ft->nopen - 1] = NULL;
1034 return (fclose (f) == 0);
1037 void fileTable_closeAll (fileTable ft)
1041 llassert (fileTable_isDefined (ft));
1043 for (i = 0; i < ft->nopen; i++)
1046 lldiagmsg (message ("Unclosed file at exit: %s", ft->openelements[i]->fname));
1049 if (ft->openelements[i]->f != NULL)
1051 (void) fclose (ft->openelements[i]->f); /* No check - cleaning up after errors */
1054 ft->openelements[i]->f = NULL;
1055 foentry_free (ft->openelements[i]);
1056 ft->openelements[i] = NULL;
1059 ft->nopenspace += ft->nopen;