Various minor fixes for compiler/linter (other then splint itself) warnings.
[splint-patched.git] / src / fileTable.c
blob5af1fbd70a71d3de992def48f35db63984f25e4a
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
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.
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
25 ** fileTable.c
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
38 # include "splintMacros.nf"
39 # include "basic.h"
40 # include "osd.h"
42 /*@access fileId*/
44 static void
45 fileTable_addOpen (fileTable p_ft, /*@observer@*/ FILE *p_f, /*@only@*/ cstring p_fname)
46 /*@modifies p_ft@*/ ;
48 static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/
50 return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
53 static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e)
54 /*@modifies p_ft@*/ ;
55 static /*@only@*/ cstring makeTempName (cstring p_pre, cstring p_suf);
57 # ifdef DEADCODE
58 static /*@only@*/ cstring
59 fileType_unparse (fileType ft)
61 switch (ft)
63 case FILE_NORMAL: return cstring_makeLiteral ("normal");
64 case FILE_HEADER: return cstring_makeLiteral ("header");
65 case FILE_XH: return cstring_makeLiteral ("xh");
66 case FILE_METASTATE: return cstring_makeLiteral ("metastate");
67 case FILE_RC: return cstring_makeLiteral ("rc");
68 case FILE_LCL: return cstring_makeLiteral ("lcl");
69 case FILE_LCD: return cstring_makeLiteral ("lcd");
70 case FILE_IMPORT: return cstring_makeLiteral ("import");
71 case FILE_PP: return cstring_makeLiteral ("pp");
73 case FILE_LSLTEMP: return cstring_makeLiteral ("lsltemp");
74 case FILE_MACROS: return cstring_makeLiteral ("macros");
75 case FILE_NODELETE: return cstring_makeLiteral ("nodelete");
78 BADEXIT;
80 # endif /* DEADCODE */
82 static int
83 fileTable_getIndex (fileTable ft, cstring s)
85 int res;
86 cstring abspath;
87 if (ft == NULL) return NOT_FOUND;
88 abspath = osd_absolutePath (s);
90 if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
92 abspath = cstring_downcase (abspath);
95 DPRINTF (("Absolute path: %s: %s", s, abspath));
96 res = cstringTable_lookup (ft->htable, abspath);
97 cstring_free (abspath);
98 return res;
101 # ifdef DEADCODE
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)",
109 fte->fname,
110 fileType_unparse (fte->ftype),
111 fte->fder,
112 ft->elements[fte->fder]->fname);
114 else
116 return message ("%s %q", fte->fname,
117 fileType_unparse (fte->ftype));
121 /*@only@*/ cstring
122 fileTable_unparse (fileTable ft)
124 cstring s = cstring_undefined;
125 int i;
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]));
137 return s;
139 # endif /* DEADCODE */
141 void fileTable_printTemps (fileTable ft)
143 if (fileTable_isDefined (ft))
145 int i;
147 for (i = 0; i < ft->nentries; i++)
149 if (ft->elements[i]->ftemp)
151 if (fileId_isValid (ft->elements[i]->fder))
153 fprintf (stderr, " %s:1\n\t%s:1\n",
154 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
155 cstring_toCharsSafe (ft->elements[i]->fname));
157 else
159 fprintf (stderr, "[no file]\n\t%s:1\n",
160 cstring_toCharsSafe (ft->elements[i]->fname));
168 ** loads in fileTable from fileTable_dump
171 static /*@notnull@*/ ftentry
172 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
174 ftentry t = (ftentry) dmalloc (sizeof (*t));
176 if (cstring_isUndefined (tn))
178 llbug (cstring_makeLiteral ("Undefined filename!"));
181 t->fname = tn;
182 t->ftemp = temp;
183 t->ftype = typ;
184 t->fder = der;
186 /* Don't set these until needed. */
187 t->basename = cstring_undefined;
188 t->fsystem = FALSE;
189 t->fspecial = FALSE;
191 return t;
194 static void
195 ftentry_free (/*@only@*/ ftentry t)
197 cstring_free (t->fname);
198 cstring_free (t->basename);
199 sfree (t);
202 /*@only@*/ /*@notnull@*/ fileTable
203 fileTable_create (void)
205 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
207 ft->nentries = 0;
208 ft->nspace = FTBASESIZE;
209 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
210 ft->htable = cstringTable_create (FTHASHSIZE);
212 ft->nopen = 0;
213 ft->nopenspace = FTBASESIZE;
214 ft->openelements = (foentry *) dmalloc (FTBASESIZE * sizeof (*ft->openelements));
216 return (ft);
219 /*@-bounds@*/
220 static void
221 fileTable_grow (fileTable ft)
223 int i;
224 ftentry *newent;
226 llassert (fileTable_isDefined (ft));
228 ft->nspace = FTBASESIZE;
230 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
232 for (i = 0; i < ft->nentries; i++)
234 newent[i] = ft->elements[i];
237 sfree (ft->elements);
238 ft->elements = newent;
240 /*@=bounds@*/
241 static void
242 fileTable_growOpen (fileTable ft)
244 int i;
245 foentry *newent;
247 llassert (fileTable_isDefined (ft));
249 ft->nopenspace = FTBASESIZE;
251 newent = (foentry *) dmalloc ((ft->nopen + ft->nopenspace) * sizeof (*newent));
253 for (i = 0; i < ft->nopen; i++)
255 newent[i] = ft->openelements[i];
258 sfree (ft->openelements);
259 ft->openelements = newent;
262 static fileId
263 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
265 cstring sd;
266 llassert (fileTable_isDefined (ft));
268 if (ft->nspace <= 0)
269 fileTable_grow (ft);
271 ft->nspace--;
273 DPRINTF (("Adding: %s", e->fname));
275 if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
277 sd = cstring_downcase (e->fname);
279 else
281 sd = cstring_copy (e->fname);
283 /* evans 2002-07-12:
284 Before, there was no cstring_copy above, and e->fname was free'd in the if branch.
285 Splint should have caught this, and produced a warning for this assignment.
286 Why not?
288 cstringTable_insert (ft->htable, sd, ft->nentries);
290 ft->elements[ft->nentries] = e;
291 ft->nentries++;
292 return (ft->nentries - 1);
295 void fileTable_noDelete (fileTable ft, cstring name)
297 fileId fid = fileTable_lookup (ft, name);
299 if (fileId_isValid (fid))
301 llassert (fileTable_isDefined (ft));
302 ft->elements[fid]->ftype = FILE_NODELETE;
304 else
306 DPRINTF (("Invalid no delete: %s", name));
310 static fileId
311 fileTable_addFilePrim (fileTable ft, /*@temp@*/ cstring name,
312 bool temp, fileType typ, fileId der)
313 /*@modifies ft@*/
315 ftentry e;
316 cstring absname = osd_absolutePath (name);
317 int tindex = fileTable_getIndex (ft, absname);
319 llassert (ft != fileTable_undefined);
321 if (tindex != NOT_FOUND)
323 llcontbug (message ("%s: duplicate entry: %q", __func__, absname));
324 return tindex;
327 e = ftentry_create (absname, temp, typ, der);
328 llassert (cstring_isUndefined (e->basename));
329 if (der == fileId_invalid)
331 e->basename = fileLib_removePathFree (fileLib_removeAnyExtension (absname));
332 e->fsystem = !temp &&
333 (typ == FILE_NORMAL || typ == FILE_HEADER) &&
334 (context_isSystemDir (absname)
336 ** evans 2002-03-15: change suggested by Jim Zelenka
337 ** support relative paths for system directories
339 || context_isSystemDir (name));
340 e->fspecial = context_isSpecialFile (absname);
342 if (e->fspecial)
344 cstring srcname = cstring_concatFree1 (fileLib_removeAnyExtension (absname),
345 C_EXTENSION);
346 fileId fid = fileTable_lookup (ft, srcname);
347 cstring_free (srcname);
349 if (fileId_isValid (fid))
351 fileId derid = ft->elements[fid]->fder;
353 ft->elements[fid]->fspecial = TRUE;
355 if (fileId_isValid (derid))
357 ft->elements[derid]->fspecial = TRUE;
362 else
364 ftentry de = ft->elements[der];
366 e->basename = cstring_copy (de->basename);
367 e->fsystem = de->fsystem;
368 e->fspecial = de->fspecial;
371 return (fileTable_internAddEntry (ft, e));
374 fileId
375 fileTable_addFile (fileTable ft, fileType typ, cstring name)
377 switch (typ)
379 case FILE_RC:
380 case FILE_PP:
381 case FILE_NORMAL:
382 case FILE_HEADER:
383 case FILE_METASTATE:
384 case FILE_XH:
385 case FILE_LCL:
386 case FILE_IMPORT:
387 case FILE_LCD:
388 return fileTable_addFilePrim (ft, name, FALSE, typ, fileId_invalid);
390 default:
391 BADBRANCH;
392 return fileId_invalid;
396 fileId
397 fileTable_addTempFile (fileTable ft, fileType ftype, fileId fid)
399 fileId res;
400 cstring newname, pre, suf;
402 llassert (fileTable_isDefined (ft));
404 switch (ftype) {
405 case FILE_MACROS:
406 llassert (fid == fileId_invalid);
407 pre = cstring_makeLiteralTemp ("lmx");
408 suf = cstring_makeLiteralTemp (".llm");
409 break;
411 case FILE_LSLTEMP:
412 llassert (fid == fileId_invalid);
413 pre = cstring_makeLiteralTemp ("ls");
414 suf = cstring_makeLiteralTemp (".lsl");
415 break;
417 case FILE_NORMAL:
418 case FILE_HEADER:
419 case FILE_XH:
420 /* temporary files for C preprocessing */
421 llassert (fileId_isValid (fid));
423 pre = cstring_makeLiteralTemp ("cl");
424 suf = C_EXTENSION;
426 if (fileId_isValid (ft->elements[fid]->fder))
428 fid = ft->elements[fid]->fder;
430 break;
432 default:
433 BADBRANCH;
434 return fileId_invalid;
437 newname = makeTempName (pre, suf);
438 res = fileTable_addFilePrim (ft, newname, TRUE, ftype, fid);
439 DPRINTF (("Added file: %s", fileTable_getName (ft, res)));
440 cstring_free (newname);
441 return res;
444 void
445 fileTable_addStreamFile (fileTable ft, FILE *fstream, cstring name)
447 fileTable_addOpen (ft, fstream, cstring_copy (name));
450 bool
451 fileTable_isHeader (fileTable ft, fileId fid)
453 if (fileId_isInvalid (fid))
455 return FALSE;
458 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
459 return (ft->elements[fid]->ftype == FILE_HEADER);
462 bool
463 fileTable_isSystemFile (fileTable ft, fileId fid)
465 if (fileId_isInvalid (fid))
467 return FALSE;
470 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
471 return (ft->elements[fid]->fsystem);
474 bool
475 fileTable_isXHFile (fileTable ft, fileId fid)
477 if (fileId_isInvalid (fid))
479 return FALSE;
482 if (!(fileTable_isDefined (ft) && fileTable_inRange (ft, fid)))
484 llcontbug (message ("Bad file table or id: %s %d", bool_unparse (fileTable_isDefined (ft)), fid));
485 return FALSE;
487 else
489 return (ft->elements[fid]->ftype == FILE_XH);
493 bool
494 fileTable_isSpecialFile (fileTable ft, fileId fid)
496 if (fileId_isInvalid (fid))
498 return FALSE;
501 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
502 return (ft->elements[fid]->fspecial);
505 bool
506 fileTable_exists (fileTable ft, cstring s)
508 int tindex = fileTable_getIndex (ft, s);
510 if (tindex == NOT_FOUND)
512 DPRINTF (("Not found: %s", s));
513 return FALSE;
515 else
517 return TRUE;
521 fileId
522 fileTable_lookup (fileTable ft, cstring s)
524 int tindex = fileTable_getIndex (ft, s);
526 if (tindex == NOT_FOUND)
528 return fileId_invalid;
530 else
532 return tindex;
536 fileId
537 fileTable_lookupBase (fileTable ft, cstring base)
539 int tindex;
541 if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
543 cstring dbase = cstring_downcase (base);
544 tindex = fileTable_getIndex (ft, dbase);
545 cstring_free (dbase);
547 else
549 tindex = fileTable_getIndex (ft, base);
552 if (tindex == NOT_FOUND)
554 return fileId_invalid;
556 else
558 fileId der;
560 llassert (fileTable_isDefined (ft));
562 der = ft->elements[tindex]->fder;
564 if (!fileId_isValid (der))
566 der = tindex;
569 return der;
573 cstring
574 fileTable_getName (fileTable ft, fileId fid)
576 if (!fileId_isValid (fid))
578 llcontbug
579 (message ("%s: called with invalid type id: %d", __func__, fid));
580 return cstring_makeLiteralTemp ("<invalid>");
583 llassert (fileTable_isDefined (ft));
584 return (ft->elements[fid]->fname);
587 cstring
588 fileTable_getRootName (fileTable ft, fileId fid)
590 fileId fder;
592 if (!fileId_isValid (fid))
594 llcontbug (message ("%s: called with invalid id: %d", __func__, fid));
595 return cstring_makeLiteralTemp ("<invalid>");
598 if (!fileTable_isDefined (ft))
600 return cstring_makeLiteralTemp ("<no file table>");
603 fder = ft->elements[fid]->fder;
605 if (fileId_isValid (fder))
607 return (ft->elements[fder]->fname);
609 else
611 return (ft->elements[fid]->fname);
615 cstring
616 fileTable_getNameBase (fileTable ft, fileId fid)
618 if (!fileId_isValid (fid))
620 llcontbug (message ("%s: called with invalid id: %d", __func__, fid));
621 return cstring_makeLiteralTemp ("<invalid>");
624 if (!fileTable_isDefined (ft))
626 return cstring_makeLiteralTemp ("<no file table>");
629 return (ft->elements[fid]->basename);
632 bool
633 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
635 fileId fd1, fd2;
637 if (!fileId_isValid (f1))
639 return FALSE;
642 if (!fileId_isValid (f2))
644 return FALSE;
647 llassert (fileTable_isDefined (ft));
649 if (f1 == f2)
651 return TRUE;
654 fd1 = ft->elements[f1]->fder;
656 if (!fileId_isValid (fd1))
658 fd1 = f1;
661 fd2 = ft->elements[f2]->fder;
664 if (!fileId_isValid (fd2))
666 fd2 = f2;
669 return (fd1 == fd2);
672 void
673 fileTable_cleanup (fileTable ft)
675 int i;
676 bool msg;
677 int skip;
679 llassert (fileTable_isDefined (ft));
681 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
682 skip = ft->nentries / 10;
684 if (msg)
686 (void) fflush (g_warningstream);
687 displayScanOpen (cstring_makeLiteral ("cleaning"));
690 for (i = 0; i < ft->nentries; i++)
692 ftentry fe = ft->elements[i];
694 if (fe->ftemp)
696 /* let's be real careful now, hon! */
698 switch (fe->ftype) {
699 case FILE_NODELETE:
700 break; /* nothing to do */
702 case FILE_LSLTEMP:
703 break; /* already removed */
705 case FILE_MACROS:
706 goto delete;
708 default:
710 ** Make sure it is really a derived file
712 if (fileId_isValid (fe->fder))
714 delete:
715 /* this should use close (fd) also... */
716 (void) osd_unlink (fe->fname);
718 else
720 llbug (message ("Temporary file is not derivative: %s "
721 "(not deleted)", fe->fname));
725 else
730 if (msg && ((i % skip) == 0))
732 displayScanContinue (cstring_makeLiteral (i == 0 ? " " : "."));
736 if (msg)
738 displayScanClose ();
742 void
743 fileTable_free (/*@only@*/ fileTable f)
745 int i = 0;
747 if (f == (fileTable)NULL)
749 return;
752 while ( i < f->nentries )
754 ftentry_free (f->elements[i]);
755 i++;
758 cstringTable_free (f->htable);
759 sfree (f->elements);
760 sfree (f->openelements); /*!! why didn't splint report this? */
761 sfree (f);
765 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
766 ** requires: <dir> must end in '/'
769 static void nextMsg (char *msg)
771 /*@+charint@*/
772 if (msg[0] < 'Z')
774 msg[0]++;
776 else
778 msg[0] = 'A';
779 if (msg[1] < 'Z')
781 msg[1]++;
783 else
785 msg[1] = 'A';
786 if (msg[2] < 'Z')
788 msg[2]++;
790 else
792 msg[2] = 'A';
793 if (msg[3] < 'Z')
795 msg[3]++;
797 else
799 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
804 /*@-charint@*/
807 static /*@only@*/ cstring makeTempName (cstring pre, cstring suf)
809 static /*@owned@*/ char *msg = NULL;
810 static /*@only@*/ cstring pidname = cstring_undefined;
811 static cstring dir = cstring_undefined;
812 cstring smsg;
814 llassert (cstring_length (pre) <= 3);
817 ** We limit the temp name to 8 characters:
818 ** pre: 3 or less
819 ** msg: 3
820 ** pid: 2 (% 100)
823 if (msg == NULL)
825 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
828 if (cstring_isUndefined (pidname))
830 pidname = message ("%d", osd_getPid () % 100);
833 if (cstring_isUndefined (dir))
835 dir = context_tmpdir ();
838 DPRINTF (("Dir: %s / %s / %s / %s / %s", dir, pre, pidname, msg, suf));
840 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
841 nextMsg (msg);
843 DPRINTF (("Trying: %s", smsg));
845 while (osd_fileExists (smsg))
847 cstring_free (smsg);
848 smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
849 nextMsg (msg);
852 return smsg;
855 static foentry
856 foentry_create (/*@exposed@*/ FILE *f, /*@only@*/ cstring fname)
858 foentry t = (foentry) dmalloc (sizeof (*t));
859 t->f = f;
860 t->fname = fname;
861 return t;
864 static void
865 foentry_free (/*@only@*/ foentry foe)
867 cstring_free (foe->fname);
868 sfree (foe);
871 static void
872 fileTable_addOpen (fileTable ft, /*@observer@*/ FILE *f, /*@only@*/ cstring fname)
874 llassert (fileTable_isDefined (ft));
876 if (ft->nopenspace <= 0)
878 fileTable_growOpen (ft);
881 ft->nopenspace--;
882 ft->openelements[ft->nopen] = foentry_create (f, fname);
883 ft->nopen++;
886 FILE *fileTable_createTempFile (fileTable ft, cstring fname, bool read)
888 FILE *res = osd_createTmpFile(fname, read);
890 if (res != NULL)
892 fileTable_addOpen (ft, res, cstring_copy (fname));
893 DPRINTF (("Opening file: %s / %p", fname, res));
895 else
897 DPRINTF (("Error opening: %s", fname));
900 return res;
903 FILE *fileTable_openReadFile (fileTable ft, cstring fname)
905 FILE *res = fopen (cstring_toCharsSafe (fname), "r");
907 if (res != NULL)
909 fileTable_addOpen (ft, res, cstring_copy (fname));
910 DPRINTF (("Opening read file: %s / %p", fname, res));
912 else
914 DPRINTF (("Cannot open read file: %s", fname));
917 return res;
921 ** Allows overwriting
924 FILE *fileTable_openWriteFile (fileTable ft, cstring fname)
926 FILE *res = fopen (cstring_toCharsSafe (fname), "w");
928 if (res != NULL) {
929 fileTable_addOpen (ft, res, cstring_copy (fname));
930 DPRINTF (("Opening file: %s / %p", fname, res));
933 return res;
936 FILE *fileTable_openWriteUpdateFile (fileTable ft, cstring fname)
938 FILE *res = fopen (cstring_toCharsSafe (fname), "w+");
940 if (res != NULL) {
941 fileTable_addOpen (ft, res, cstring_copy (fname));
942 DPRINTF (("Opening file: %s / %p", fname, res));
945 return res;
948 bool fileTable_closeFile (fileTable ft, FILE *f)
950 bool foundit = FALSE;
951 int i = 0;
953 llassert (fileTable_isDefined (ft));
955 DPRINTF (("Closing file: %p", f));
957 for (i = 0; i < ft->nopen; i++)
959 if (ft->openelements[i]->f == f)
961 DPRINTF (("Closing file: %p = %s", f, ft->openelements[i]->fname));
963 if (i == ft->nopen - 1)
965 foentry_free (ft->openelements[i]);
966 ft->openelements[i] = NULL;
968 else
970 foentry_free (ft->openelements[i]);
971 ft->openelements[i] = ft->openelements[ft->nopen - 1];
972 ft->openelements[ft->nopen - 1] = NULL;
975 ft->nopen--;
976 ft->nopenspace++;
977 foundit = TRUE;
978 break;
982 llassert (foundit);
983 return (fclose (f) == 0);
986 void fileTable_closeAll (fileTable ft)
988 int i = 0;
990 llassert (fileTable_isDefined (ft));
992 for (i = 0; i < ft->nopen; i++)
995 lldiagmsg (message ("Unclosed file at exit: %s", ft->openelements[i]->fname));
998 if (ft->openelements[i]->f != NULL)
1000 (void) fclose (ft->openelements[i]->f); /* No check - cleaning up after errors */
1003 ft->openelements[i]->f = NULL;
1004 foentry_free (ft->openelements[i]);
1005 ft->openelements[i] = NULL;
1008 ft->nopenspace += ft->nopen;
1009 ft->nopen = 0;