2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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
38 # include "splintMacros.nf"
45 fileTable_addOpen (fileTable p_ft
, /*@observer@*/ FILE *p_f
, /*@only@*/ cstring p_fname
)
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
)
55 static /*@only@*/ cstring
makeTempName (cstring p_pre
, cstring p_suf
);
58 static /*@only@*/ cstring
59 fileType_unparse (fileType 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");
80 # endif /* DEADCODE */
83 fileTable_getIndex (fileTable ft
, cstring s
)
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
);
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
]));
139 # endif /* DEADCODE */
141 void fileTable_printTemps (fileTable ft
)
143 if (fileTable_isDefined (ft
))
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
));
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!"));
186 /* Don't set these until needed. */
187 t
->basename
= cstring_undefined
;
195 ftentry_free (/*@only@*/ ftentry t
)
197 cstring_free (t
->fname
);
198 cstring_free (t
->basename
);
202 /*@only@*/ /*@notnull@*/ fileTable
203 fileTable_create (void)
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
));
221 fileTable_grow (fileTable ft
)
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
;
242 fileTable_growOpen (fileTable ft
)
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
;
263 fileTable_internAddEntry (fileTable ft
, /*@only@*/ ftentry e
)
266 llassert (fileTable_isDefined (ft
));
273 DPRINTF (("Adding: %s", e
->fname
));
275 if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES
))
277 sd
= cstring_downcase (e
->fname
);
281 sd
= cstring_copy (e
->fname
);
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.
288 cstringTable_insert (ft
->htable
, sd
, ft
->nentries
);
290 ft
->elements
[ft
->nentries
] = e
;
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
;
306 DPRINTF (("Invalid no delete: %s", name
));
311 fileTable_addFilePrim (fileTable ft
, /*@temp@*/ cstring name
,
312 bool temp
, fileType typ
, fileId der
)
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
));
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
= fileLib_isSpecialFile (absname
);
344 cstring srcname
= cstring_concatFree1 (fileLib_removeAnyExtension (absname
),
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
;
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
));
375 fileTable_addFile (fileTable ft
, fileType typ
, cstring name
)
388 return fileTable_addFilePrim (ft
, name
, FALSE
, typ
, fileId_invalid
);
392 return fileId_invalid
;
397 fileTable_addTempFile (fileTable ft
, fileType ftype
, fileId fid
)
400 cstring newname
, pre
, suf
;
402 llassert (fileTable_isDefined (ft
));
406 llassert (fid
== fileId_invalid
);
407 pre
= cstring_makeLiteralTemp ("lmx");
408 suf
= cstring_makeLiteralTemp (".llm");
412 llassert (fid
== fileId_invalid
);
413 pre
= cstring_makeLiteralTemp ("ls");
414 suf
= cstring_makeLiteralTemp (".lsl");
420 /* temporary files for C preprocessing */
421 llassert (fileId_isValid (fid
));
423 pre
= cstring_makeLiteralTemp ("cl");
426 if (fileId_isValid (ft
->elements
[fid
]->fder
))
428 fid
= ft
->elements
[fid
]->fder
;
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
);
445 fileTable_addStreamFile (fileTable ft
, FILE *fstream
, cstring name
)
447 fileTable_addOpen (ft
, fstream
, cstring_copy (name
));
451 fileTable_isHeader (fileTable ft
, fileId fid
)
453 if (fileId_isInvalid (fid
))
458 llassert (fileTable_isDefined (ft
) && fileTable_inRange (ft
, fid
));
459 return (ft
->elements
[fid
]->ftype
== FILE_HEADER
);
463 fileTable_isSystemFile (fileTable ft
, fileId fid
)
465 if (fileId_isInvalid (fid
))
470 llassert (fileTable_isDefined (ft
) && fileTable_inRange (ft
, fid
));
471 return (ft
->elements
[fid
]->fsystem
);
475 fileTable_isXHFile (fileTable ft
, fileId fid
)
477 if (fileId_isInvalid (fid
))
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
));
489 return (ft
->elements
[fid
]->ftype
== FILE_XH
);
494 fileTable_isSpecialFile (fileTable ft
, fileId fid
)
496 if (fileId_isInvalid (fid
))
501 llassert (fileTable_isDefined (ft
) && fileTable_inRange (ft
, fid
));
502 return (ft
->elements
[fid
]->fspecial
);
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
));
522 fileTable_lookup (fileTable ft
, cstring s
)
524 int tindex
= fileTable_getIndex (ft
, s
);
526 if (tindex
== NOT_FOUND
)
528 return fileId_invalid
;
537 fileTable_lookupBase (fileTable ft
, cstring base
)
541 if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES
))
543 cstring dbase
= cstring_downcase (base
);
544 tindex
= fileTable_getIndex (ft
, dbase
);
545 cstring_free (dbase
);
549 tindex
= fileTable_getIndex (ft
, base
);
552 if (tindex
== NOT_FOUND
)
554 return fileId_invalid
;
560 llassert (fileTable_isDefined (ft
));
562 der
= ft
->elements
[tindex
]->fder
;
564 if (!fileId_isValid (der
))
574 fileTable_getName (fileTable ft
, fileId fid
)
576 if (!fileId_isValid (fid
))
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
);
588 fileTable_getRootName (fileTable ft
, fileId fid
)
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
);
611 return (ft
->elements
[fid
]->fname
);
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
);
633 fileTable_sameBase (fileTable ft
, fileId f1
, fileId f2
)
637 if (!fileId_isValid (f1
))
642 if (!fileId_isValid (f2
))
647 llassert (fileTable_isDefined (ft
));
654 fd1
= ft
->elements
[f1
]->fder
;
656 if (!fileId_isValid (fd1
))
661 fd2
= ft
->elements
[f2
]->fder
;
664 if (!fileId_isValid (fd2
))
673 fileTable_cleanup (fileTable ft
)
679 llassert (fileTable_isDefined (ft
));
681 msg
= ((ft
->nentries
> 40) && context_getFlag (FLG_SHOWSCAN
));
682 skip
= ft
->nentries
/ 10;
686 (void) fflush (g_warningstream
);
687 displayScanOpen (cstring_makeLiteral ("cleaning"));
690 for (i
= 0; i
< ft
->nentries
; i
++)
692 ftentry fe
= ft
->elements
[i
];
696 /* let's be real careful now, hon! */
700 break; /* nothing to do */
703 break; /* already removed */
710 ** Make sure it is really a derived file
712 if (fileId_isValid (fe
->fder
))
715 /* this should use close (fd) also... */
716 (void) osd_unlink (fe
->fname
);
720 llbug (message ("Temporary file is not derivative: %s "
721 "(not deleted)", fe
->fname
));
730 if (msg
&& ((i
% skip
) == 0))
732 displayScanContinue (cstring_makeLiteral (i
== 0 ? " " : "."));
743 fileTable_free (/*@only@*/ fileTable f
)
747 if (f
== (fileTable
)NULL
)
752 while ( i
< f
->nentries
)
754 ftentry_free (f
->elements
[i
]);
758 cstringTable_free (f
->htable
);
760 sfree (f
->openelements
); /*!! why didn't splint report this? */
765 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
766 ** requires: <dir> must end in '/'
769 static void nextMsg (char *msg
)
799 llassertprint (FALSE
, ("nextMsg: out of unique names!!!"));
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
;
814 llassert (cstring_length (pre
) <= 3);
817 ** We limit the temp name to 8 characters:
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
);
843 DPRINTF (("Trying: %s", smsg
));
845 while (osd_fileExists (smsg
))
848 smsg
= message ("%s%s%s%s%s", dir
, pre
, pidname
, cstring_fromChars (msg
), suf
);
856 foentry_create (/*@exposed@*/ FILE *f
, /*@only@*/ cstring fname
)
858 foentry t
= (foentry
) dmalloc (sizeof (*t
));
865 foentry_free (/*@only@*/ foentry foe
)
867 cstring_free (foe
->fname
);
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
);
882 ft
->openelements
[ft
->nopen
] = foentry_create (f
, fname
);
886 FILE *fileTable_createTempFile (fileTable ft
, cstring fname
, bool read
)
888 FILE *res
= osd_createTmpFile(fname
, read
);
892 fileTable_addOpen (ft
, res
, cstring_copy (fname
));
893 DPRINTF (("Opening file: %s / %p", fname
, res
));
897 DPRINTF (("Error opening: %s", fname
));
903 FILE *fileTable_openReadFile (fileTable ft
, cstring fname
)
905 FILE *res
= fopen (cstring_toCharsSafe (fname
), "r");
909 fileTable_addOpen (ft
, res
, cstring_copy (fname
));
910 DPRINTF (("Opening read file: %s / %p", fname
, res
));
914 DPRINTF (("Cannot open read file: %s", fname
));
921 ** Allows overwriting
924 FILE *fileTable_openWriteFile (fileTable ft
, cstring fname
)
926 FILE *res
= fopen (cstring_toCharsSafe (fname
), "w");
929 fileTable_addOpen (ft
, res
, cstring_copy (fname
));
930 DPRINTF (("Opening file: %s / %p", fname
, res
));
936 FILE *fileTable_openWriteUpdateFile (fileTable ft
, cstring fname
)
938 FILE *res
= fopen (cstring_toCharsSafe (fname
), "w+");
941 fileTable_addOpen (ft
, res
, cstring_copy (fname
));
942 DPRINTF (("Opening file: %s / %p", fname
, res
));
948 bool fileTable_closeFile (fileTable ft
, FILE *f
)
950 bool foundit
= FALSE
;
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
;
970 foentry_free (ft
->openelements
[i
]);
971 ft
->openelements
[i
] = ft
->openelements
[ft
->nopen
- 1];
972 ft
->openelements
[ft
->nopen
- 1] = NULL
;
983 return (fclose (f
) == 0);
986 void fileTable_closeAll (fileTable ft
)
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
;