]> andersk Git - splint.git/blame - src/fileTable.c
Updating to use the LEnsures and LRequires instead of the ensures requires so
[splint.git] / src / fileTable.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
3** Copyright (C) 1994-2000 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.
19**
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
23*/
24/*
25** fileTable.c
26**
27** replaces filenamemap.c
28** based (loosely) on typeTable.c
29**
30** entries in the fileTable are:
31**
32** name - name of the file
33** type - kind of file (a temp file to be deleted?)
34** link - derived from this file
35**
36*/
37/*
38 * Herbert 04/1997:
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.
45 */
46
47# include "lclintMacros.nf"
48# include "llbasic.h"
49# include "osd.h"
50# include "llmain.h"
51# include "portab.h"
52# if defined(__IBMC__) && defined(OS2)
53# include <process.h>
54# define getpid _getpid
55# endif
56
57/*@access fileId*/
58
59static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/
60{
61 return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
62}
63
64static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e)
65 /*@modifies p_ft@*/ ;
66static /*@only@*/ char *makeTempName (char *p_dir, char *p_pre, char *p_suf);
67
68static /*@only@*/ cstring
69fileType_unparse (fileType ft)
70{
71 switch (ft)
72 {
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_MACROS: return cstring_makeLiteral ("macros");
78 }
79
80 BADEXIT;
81}
82
83static int
84fileTable_getIndex (fileTable ft, cstring s)
85{
86 if (ft == NULL) return NOT_FOUND;
87 return (hashTable_lookup (ft->htable, s));
88}
89
90/*@only@*/ cstring
91fileTable_unparse (fileTable ft)
92{
93 cstring s = cstring_undefined;
94 int i;
95
96 if (fileTable_isUndefined (ft))
97 {
98 return (cstring_makeLiteral ("<fileTable undefined>"));
99 }
100
101 for (i = 0; i < ft->nentries; i++)
102 {
103 if (fileId_isValid (ft->elements[i]->fder))
104 {
105 s = message ("%s\n[%d] %s %q %d (%s)",
106 s, i,
107 ft->elements[i]->fname,
108 fileType_unparse (ft->elements[i]->ftype),
109 ft->elements[i]->fder,
110 ft->elements[ft->elements[i]->fder]->fname);
111 }
112 else
113 {
114 s = message ("%s\n[%d] %s %q", s, i, ft->elements[i]->fname,
115 fileType_unparse (ft->elements[i]->ftype));
116 }
117 }
118
119 return s;
120}
121
122void fileTable_printTemps (fileTable ft)
123{
124 if (fileTable_isDefined (ft))
125 {
126 int i;
127
128 for (i = 0; i < ft->nentries; i++)
129 {
130 if (ft->elements[i]->ftemp)
131 {
132 if (fileId_isValid (ft->elements[i]->fder))
133 {
134 fprintf (stderr, " %s:1\n\t%s:1\n",
135 cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
136 cstring_toCharsSafe (ft->elements[i]->fname));
137 }
138 else
139 {
140 fprintf (stderr, "[no file]\n\t%s:1\n",
141 cstring_toCharsSafe (ft->elements[i]->fname));
142 }
143 }
144 }
145 }
146}
147
148/*
149** loads in fileTable from fileTable_dump
150*/
151
152static /*@notnull@*/ ftentry
153ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
154{
155 ftentry t = (ftentry) dmalloc (sizeof (*t));
156
157 if (cstring_isUndefined (tn))
158 {
159 llbug (cstring_makeLiteral ("Undefined filename!"));
160 }
161
162 t->fname = tn;
163
164 t->basename = cstring_undefined;
165 t->ftemp = temp;
166 t->ftype = typ;
167 t->fder = der;
168
169 /* Don't set these until the basename is needed. */
170 t->fsystem = FALSE;
171 t->fspecial = FALSE;
172
173 return t;
174}
175
176static void
177ftentry_free (/*@only@*/ ftentry t)
178{
179 cstring_free (t->fname);
180 cstring_free (t->basename);
181 sfree (t);
182}
183
184/*@only@*/ /*@notnull@*/ fileTable
185fileTable_create ()
186{
187 fileTable ft = (fileTable) dmalloc (sizeof (*ft));
188
189 ft->nentries = 0;
190 ft->nspace = FTBASESIZE;
191 ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
192 ft->htable = hashTable_create (FTHASHSIZE);
193
194 return (ft);
195}
196
197static void
198fileTable_grow (fileTable ft)
199{
200 int i;
201 ftentry *newent;
202
203 llassert (fileTable_isDefined (ft));
204
205 ft->nspace = FTBASESIZE;
206
207 newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
208
209 for (i = 0; i < ft->nentries; i++)
210 {
211 newent[i] = ft->elements[i];
212 }
213
214 sfree (ft->elements);
215 ft->elements = newent;
216}
217
218static fileId
219fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
220{
221 llassert (fileTable_isDefined (ft));
222
223 if (ft->nspace <= 0)
224 fileTable_grow (ft);
225
226 ft->nspace--;
227
228 hashTable_insert (ft->htable, e->fname, ft->nentries);
229 ft->elements[ft->nentries] = e;
230
231 ft->nentries++;
232 return (ft->nentries - 1);
233}
234
235void fileTable_noDelete (fileTable ft, cstring name)
236{
237 fileId fid = fileTable_lookup (ft, name);
238
239 if (fileId_isValid (fid)) {
240 llassert (fileTable_isDefined (ft));
241
242 ft->elements[fid]->ftype = FILE_NODELETE;
243 }
244}
245
246static fileId
247fileTable_addFilePrim (fileTable ft, /*@only@*/ cstring name,
248 bool temp, fileType typ, fileId der)
249 /*@modifies ft@*/
250{
251 int tindex = fileTable_getIndex (ft, name);
252
253 llassert (ft != fileTable_undefined);
254
255 if (tindex != NOT_FOUND)
256 {
257 llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", name));
258
259 return tindex;
260 }
261 else
262 {
263 ftentry e = ftentry_create (name, temp, typ, der);
264
265 if (der == fileId_invalid)
266 {
267 llassert (cstring_isUndefined (e->basename));
268
269 e->basename = cstring_fromChars
270 (removePathFree (removeAnyExtension
271 (cstring_toCharsSafe (name))));
272 e->fsystem = context_isSystemDir (name);
273 e->fspecial = context_isSpecialFile (name);
274
275 if (e->fspecial)
276 {
277 cstring srcname = cstring_concatFree (cstring_fromChars (removeAnyExtension (cstring_toCharsSafe (name))), cstring_makeLiteral (".c"));
278 fileId fid = fileTable_lookup (ft, srcname);
279
280 cstring_free (srcname);
281
282 if (fileId_isValid (fid))
283 {
284 fileId derid = ft->elements[fid]->fder;
285
286 ft->elements[fid]->fspecial = TRUE;
287
288 if (fileId_isValid (derid))
289 {
290 ft->elements[derid]->fspecial = TRUE;
291 }
292 }
293 }
294 }
295 else
296 {
297 ftentry de = ft->elements[der];
298
299 llassert (cstring_isUndefined (e->basename));
300 e->basename = cstring_copy (de->basename);
301 e->fsystem = de->fsystem;
302 e->fspecial = de->fspecial;
303 }
304
305 return (fileTable_internAddEntry (ft, e));
306 }
307}
308
309fileId
310fileTable_addFile (fileTable ft, cstring name)
311{
312 /* while (*name == '.' && *(name + 1) == '/') name += 2; */
313 return (fileTable_addFilePrim (ft, cstring_copy (name),
314 FALSE, FILE_NORMAL, fileId_invalid));
315}
316
317fileId
318fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
319{
320 return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
321}
322
323fileId
324fileTable_addHeaderFile (fileTable ft, cstring name)
325{
326 return (fileTable_addFilePrim (ft, cstring_copy (name), FALSE,
327 FILE_HEADER, fileId_invalid));
328}
329
330bool
331fileTable_isHeader (fileTable ft, fileId fid)
332{
333 if (fileId_isInvalid (fid))
334 {
335 return FALSE;
336 }
337
338 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
339 return (ft->elements[fid]->ftype == FILE_HEADER);
340}
341
342bool
343fileTable_isSystemFile (fileTable ft, fileId fid)
344{
345 if (fileId_isInvalid (fid))
346 {
347 return FALSE;
348 }
349
350 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
351 return (ft->elements[fid]->fsystem);
352}
353
354bool
355fileTable_isSpecialFile (fileTable ft, fileId fid)
356{
357 if (fileId_isInvalid (fid))
358 {
359 return FALSE;
360 }
361
362 llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
363 return (ft->elements[fid]->fspecial);
364}
365
366fileId
367fileTable_addLibraryFile (fileTable ft, cstring name)
368{
369 return (fileTable_addFilePrim (ft, cstring_copy (name),
370 FALSE, FILE_HEADER, fileId_invalid));
371}
372
373# ifndef NOLCL
374fileId
375fileTable_addImportFile (fileTable ft, cstring name)
376{
377 return (fileTable_addFilePrim (ft, cstring_copy (name),
378 FALSE, FILE_HEADER, fileId_invalid));
379}
380
381fileId
382fileTable_addLCLFile (fileTable ft, cstring name)
383{
384 return (fileTable_addFilePrim (ft, cstring_copy (name),
385 FALSE, FILE_HEADER, fileId_invalid));
386}
387# endif
388
389# ifndef NOLCL
390static int tmpcounter = 0;
391# endif
392
393fileId
394fileTable_addMacrosFile (fileTable ft)
395{
396 cstring newname = cstring_fromChars
397 (makeTempName (cstring_toCharsSafe (context_tmpdir ()), "lmx", ".llm"));
398
399 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid));
400}
401
402fileId
403fileTable_addCTempFile (fileTable ft, fileId fid)
404{
405# if FALSE
406 /* Can't control output file name for cl preprocessor */
407 cstring newname = cstring_concatChars (removeAnyExtension (fileName (fid)), ".i");
408# else
409 cstring newname = cstring_fromChars
410 (makeTempName (cstring_toCharsSafe (context_tmpdir ()), "cl", ".c"));
411# endif
412
413 llassert (fileTable_isDefined (ft));
414
415 if (!fileId_isValid (ft->elements[fid]->fder))
416 {
417 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid));
418 }
419 else
420 {
421 return (fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
422 ft->elements[fid]->fder));
423 }
424}
425
426# ifndef NOLCL
427fileId
428fileTable_addltemp (fileTable ft)
429{
430 char *newname = makeTempName (cstring_toCharsSafe (context_tmpdir ()),
431 "ls", ".lsl");
432 char *onewname;
433 fileId ret;
434
435 if (cstring_hasNonAlphaNumBar (cstring_fromChars (newname)))
436 {
437 char *lastpath = (char *)NULL;
438
439 if (tmpcounter == 0)
440 {
441 lldiagmsg
442 (message
443 ("Operating system generates tmp filename containing invalid charater: %s",
444 cstring_fromChars (newname)));
445 lldiagmsg (cstring_makeLiteral
446 ("Try cleaning up the tmp directory. Attempting to continue."));
447 }
448
449 lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
450 llassert (lastpath != NULL);
451 *lastpath = '\0';
452
453 onewname = newname;
454 newname = cstring_toCharsSafe (message ("%s%hlsl%d.lsl",
455 cstring_fromChars (newname),
456 CONNECTCHAR,
457 tmpcounter));
458 sfree (onewname);
459 tmpcounter++;
460 }
461
462 /*
463 ** this is kind of yucky...need to make the result of cstring_fromChars
464 ** refer to the same storage as its argument. Of course, this loses,
465 ** since cstring is abstract. Should make it an only?
466 */
467
468 ret = fileTable_addFilePrim (ft, cstring_copy (cstring_fromChars (newname)),
469 TRUE, FILE_LSLTEMP, fileId_invalid);
470 sfree (newname);
471 return (ret);
472}
473# endif
474
475bool
476fileTable_exists (fileTable ft, cstring s)
477{
478 int tindex = fileTable_getIndex (ft, s);
479
480 if (tindex == NOT_FOUND)
481 return FALSE;
482 else
483 return TRUE;
484}
485
486fileId
487fileTable_lookup (fileTable ft, cstring s)
488{
489 int tindex = fileTable_getIndex (ft, s);
490
491 if (tindex == NOT_FOUND)
492 {
493 return fileId_invalid;
494 }
495 else
496 {
497 return tindex;
498 }
499}
500
501fileId
502fileTable_lookupBase (fileTable ft, cstring base)
503{
504 int tindex = fileTable_getIndex (ft, base);
505
506 if (tindex == NOT_FOUND)
507 {
508
509 return fileId_invalid;
510 }
511 else
512 {
513 fileId der;
514
515 llassert (fileTable_isDefined (ft));
516
517 der = ft->elements[tindex]->fder;
518
519 if (!fileId_isValid (der))
520 {
521 der = tindex;
522 }
523
524 return der;
525 }
526}
527
528cstring
529fileTable_getName (fileTable ft, fileId fid)
530{
531 if (!fileId_isValid (fid))
532 {
533 llcontbug
534 (message ("fileTable_getName: called with invalid type id: %d", fid));
535 return cstring_makeLiteralTemp ("<invalid>");
536 }
537
538 llassert (fileTable_isDefined (ft));
539 return (ft->elements[fid]->fname);
540}
541
542cstring
543fileTable_getRootName (fileTable ft, fileId fid)
544{
545 fileId fder;
546
547 if (!fileId_isValid (fid))
548 {
549 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
550 return cstring_makeLiteralTemp ("<invalid>");
551 }
552
553 if (!fileTable_isDefined (ft))
554 {
555 return cstring_makeLiteralTemp ("<no file table>");
556 }
557
558 if (fid >= ft->nentries)
559 {
560 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
561 // fprintf(stderr, "\nbad\n");
562 return cstring_makeLiteralTemp ("<invalid>");
563 }
564
565 fder = ft->elements[fid]->fder;
566
567 if (fileId_isValid (fder))
568 {
569 return (ft->elements[fder]->fname);
570 }
571 else
572 {
573 return (ft->elements[fid]->fname);
574 }
575}
576
577cstring
578fileTable_getNameBase (fileTable ft, fileId fid)
579{
580 if (!fileId_isValid (fid))
581 {
582 llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
583 return cstring_makeLiteralTemp ("<invalid>");
584 }
585
586 if (!fileTable_isDefined (ft))
587 {
588 return cstring_makeLiteralTemp ("<no file table>");
589 }
590
591 return (ft->elements[fid]->basename);
592}
593
594bool
595fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
596{
597 fileId fd1, fd2;
598
599 if (!fileId_isValid (f1))
600 {
601 return FALSE;
602 }
603
604 if (!fileId_isValid (f2))
605 {
606 return FALSE;
607 }
608
609 llassert (fileTable_isDefined (ft));
610
611 if (f1 == f2)
612 {
613 return TRUE;
614 }
615
616 fd1 = ft->elements[f1]->fder;
617
618 if (!fileId_isValid (fd1))
619 {
620 fd1 = f1;
621 }
622
623 fd2 = ft->elements[f2]->fder;
624
625
626 if (!fileId_isValid (fd2))
627 {
628 fd2 = f2;
629 }
630
631 return (fd1 == fd2);
632}
633
634void
635fileTable_cleanup (fileTable ft)
636{
637 int i;
638 bool msg;
639 int skip;
640
641 llassert (fileTable_isDefined (ft));
642
643 msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
644 skip = ft->nentries / 10;
645
646 if (msg)
647 {
648 (void) fflush (g_msgstream);
649 fprintf (stderr, "< cleaning");
650 }
651
652 for (i = 0; i < ft->nentries; i++)
653 {
654 ftentry fe = ft->elements[i];
655
656 if (fe->ftemp)
657 {
658 /* let's be real careful now, hon! */
659
660 /*
661 ** Make sure it is really a derived file
662 */
663
664 if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
665 {
666 ; /* already removed */
667 }
668 else if (fileId_isValid (fe->fder))
669 {
670 (void) osd_unlink (cstring_toCharsSafe (fe->fname));
671 }
672 else if (fe->ftype == FILE_MACROS)
673 {
674 (void) osd_unlink (cstring_toCharsSafe (fe->fname));
675 }
676 else
677 {
678 llbug (message ("Temporary file is not derivative: %s "
679 "(not deleted)", fe->fname));
680 }
681 }
682 else
683 {
684 ;
685 }
686
687 if (msg && ((i % skip) == 0))
688 {
689 (void) fflush (g_msgstream);
690
691 if (i == 0) {
692 fprintf (stderr, " ");
693 } else {
694 fprintf (stderr, ".");
695 }
696
697 (void) fflush (stderr);
698 }
699 }
700
701 if (msg)
702 {
703 fprintf (stderr, " >\n");
704 }
705}
706
707void
708fileTable_free (/*@only@*/ fileTable f)
709{
710 int i = 0;
711
712 if (f == (fileTable)NULL)
713 {
714 return;
715 }
716
717 while ( i < f->nentries )
718 {
719 ftentry_free (f->elements[i]);
720 i++;
721 }
722
723 hashTable_free (f->htable);
724 sfree (f->elements);
725 sfree (f);
726}
727
728/*
729** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
730** requires: <dir> must end in '/'
731*/
732
733static void nextMsg (char *msg)
734{
735 /*@+charint@*/
736 if (msg[0] < 'Z')
737 {
738 msg[0]++;
739 }
740 else
741 {
742 msg[0] = 'A';
743 if (msg[1] < 'Z')
744 {
745 msg[1]++;
746 }
747 else
748 {
749 msg[1] = 'A';
750 if (msg[2] < 'Z')
751 {
752 msg[2]++;
753 }
754 else
755 {
756 msg[2] = 'A';
757 if (msg[3] < 'Z')
758 {
759 msg[3]++;
760 }
761 else
762 {
763 llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
764 }
765 }
766 }
767 }
768 /*@-charint@*/
769}
770
771static /*@only@*/ char *makeTempName (char *dir, char *pre, char *suf)
772{
773 static int pid = 0;
774 static /*@owned@*/ char *msg = NULL;
775 static /*@only@*/ char *pidname = NULL;
776 size_t maxlen;
777 char *buf;
778
779 llassert (strlen (pre) <= 3);
780
781 /*
782 ** We limit the temp name to 8 characters:
783 ** pre: 3 or less
784 ** msg: 3
785 ** pid: 2 (% 100)
786 */
787
788 if (msg == NULL)
789 {
790 msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
791 }
792
793 if (pid == 0)
794 {
795 /*@+matchanyintegral@*/
796 pid = osd_getPid ();
797 /*@=matchanyintegral@*/
798 }
799
800 if (pidname == NULL)
801 {
802 pidname = cstring_toCharsSafe (message ("%d", pid % 100));
803 }
804 else
805 {
806 pidname = mstring_createEmpty ();
807 }
808
809 maxlen = (strlen (dir) + strlen (pre) + strlen (msg)
810 + strlen (pidname) + strlen (suf) + 2);
811
812 buf = mstring_create (size_toInt (maxlen));
813
814 sprintf (buf, "%s%s%s%s%s", dir, pre, pidname, msg, suf);
815 nextMsg (msg);
816
817 while (osd_fileExists (buf))
818 {
819 sprintf (buf, "%s%s%s%s%s", dir, pre, pidname, msg, suf);
820 nextMsg (msg);
821 }
822
823 return buf;
824}
825
826
827
This page took 0.170525 seconds and 5 git commands to generate.