]> andersk Git - splint.git/blob - src/fileTable.c
Merged with Dave Evans's changes.
[splint.git] / src / fileTable.c
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
59 static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/ 
60 {
61   return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
62 }
63
64 static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e) 
65    /*@modifies p_ft@*/ ;
66 static /*@only@*/ char *makeTempName (char *p_dir, char *p_pre, char *p_suf);
67
68 static /*@only@*/ cstring
69 fileType_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
83 static int
84 fileTable_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
91 fileTable_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
122 void 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
152 static /*@notnull@*/ ftentry
153 ftentry_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
176 static void
177 ftentry_free (/*@only@*/ ftentry t)
178 {
179   cstring_free (t->fname);
180   cstring_free (t->basename);
181   sfree (t);
182 }
183
184 /*@only@*/ /*@notnull@*/ fileTable
185 fileTable_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
197 static void
198 fileTable_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
218 static fileId
219 fileTable_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
235 void 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
246 static fileId
247 fileTable_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
309 fileId
310 fileTable_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
317 fileId
318 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
319 {
320   return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
321 }
322
323 fileId
324 fileTable_addHeaderFile (fileTable ft, cstring name)
325 {
326   return (fileTable_addFilePrim (ft, cstring_copy (name), FALSE, 
327                                  FILE_HEADER, fileId_invalid));
328 }
329
330 bool
331 fileTable_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
342 bool
343 fileTable_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
354 bool
355 fileTable_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
366 fileId
367 fileTable_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
374 fileId
375 fileTable_addImportFile (fileTable ft, cstring name)
376 {
377   return (fileTable_addFilePrim (ft, cstring_copy (name), 
378                                  FALSE, FILE_HEADER, fileId_invalid));
379 }
380
381 fileId
382 fileTable_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
390 static int tmpcounter = 0;
391 # endif
392
393 fileId
394 fileTable_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
402 fileId
403 fileTable_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
427 fileId
428 fileTable_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
475 bool
476 fileTable_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
486 fileId
487 fileTable_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
501 fileId
502 fileTable_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
528 cstring
529 fileTable_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
542 cstring
543 fileTable_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
577 cstring
578 fileTable_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
594 bool
595 fileTable_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
634 void
635 fileTable_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
707 void
708 fileTable_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
733 static 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
771 static /*@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.751344 seconds and 5 git commands to generate.