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.
19 **
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
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 <sys/types.h>
48 # include <sys/stat.h>
49 # include <fcntl.h>
50 # include "splintMacros.nf"
51 # include "basic.h"
52 # include "osd.h"
53 # include "llmain.h"
54 
55 # ifdef WIN32
56 # include <io.h>
57 # else
58 # if defined(__IBMC__) && defined(OS2)
59 # include <process.h>
60 # include <io.h>
61 # define getpid _getpid
62 # define S_IRUSR S_IREAD
63 # define S_IWUSR S_IWRITE
64 # define S_IXUSR S_IEXEC
65 # endif
66 # endif
67 
68 /*@access fileId*/
69 
70 static void
71 fileTable_addOpen (fileTable p_ft, /*@observer@*/ FILE *p_f, /*@only@*/ cstring p_fname)
72   /*@modifies p_ft@*/ ;
73 
fileTable_inRange(fileTable ft,fileId fid)74 static bool fileTable_inRange (fileTable ft, fileId fid) /*@*/
75 {
76   return (fileTable_isDefined (ft) && (fid >= 0) && (fid < ft->nentries));
77 }
78 
79 static fileId fileTable_internAddEntry (fileTable p_ft, /*@only@*/ ftentry p_e)
80    /*@modifies p_ft@*/ ;
81 static /*@only@*/ cstring makeTempName (cstring p_dir, cstring p_pre, cstring p_suf);
82 
83 static /*@only@*/ cstring
fileType_unparse(fileType ft)84 fileType_unparse (fileType ft)
85 {
86   switch (ft)
87     {
88     case FILE_NORMAL:  return cstring_makeLiteral ("normal");
89     case FILE_NODELETE:  return cstring_makeLiteral ("normal");
90     case FILE_LSLTEMP: return cstring_makeLiteral ("ltemp");
91     case FILE_HEADER:  return cstring_makeLiteral ("header");
92     case FILE_XH:  return cstring_makeLiteral ("xh");
93     case FILE_MACROS:  return cstring_makeLiteral ("macros");
94     case FILE_METASTATE:  return cstring_makeLiteral ("metastate");
95     }
96 
97   BADEXIT;
98 }
99 
100 static int
fileTable_getIndex(fileTable ft,cstring s)101 fileTable_getIndex (fileTable ft, cstring s)
102 {
103   int res;
104   cstring abspath;
105   if (ft == NULL) return NOT_FOUND;
106   abspath = osd_absolutePath (cstring_undefined, s);
107 
108   if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
109     {
110       abspath = cstring_downcase (abspath);
111     }
112 
113   DPRINTF (("Absolute path: %s: %s", s, abspath));
114   res = cstringTable_lookup (ft->htable, abspath);
115   cstring_free (abspath);
116   return res;
117 }
118 
ftentry_unparse(fileTable ft,ftentry fte)119 static cstring ftentry_unparse (fileTable ft, ftentry fte)
120 {
121   if (fileId_isValid (fte->fder))
122     {
123       llassert (fileTable_isDefined (ft));
124 
125       return message ("%s %q %d (%s)",
126 		      fte->fname,
127 		      fileType_unparse (fte->ftype),
128 		      fte->fder,
129 		      ft->elements[fte->fder]->fname);
130     }
131   else
132     {
133       return message ("%s %q", fte->fname,
134 		      fileType_unparse (fte->ftype));
135     }
136 }
137 
138 /*@only@*/ cstring
fileTable_unparse(fileTable ft)139 fileTable_unparse (fileTable ft)
140 {
141   cstring s = cstring_undefined;
142   int i;
143 
144   if (fileTable_isUndefined (ft))
145     {
146       return (cstring_makeLiteral ("<fileTable undefined>"));
147     }
148 
149   for (i = 0; i < ft->nentries; i++)
150     {
151       s = message ("%s\n[%d] %q", s, i, ftentry_unparse (ft, ft->elements[i]));
152     }
153 
154   return s;
155 }
156 
fileTable_printTemps(fileTable ft)157 void fileTable_printTemps (fileTable ft)
158 {
159   if (fileTable_isDefined (ft))
160     {
161       int i;
162 
163       for (i = 0; i < ft->nentries; i++)
164 	{
165 	  if (ft->elements[i]->ftemp)
166 	    {
167 	      if (fileId_isValid (ft->elements[i]->fder))
168 		{
169 		  fprintf (stderr, "  %s:1\n\t%s:1\n",
170 			   cstring_toCharsSafe (ft->elements[ft->elements[i]->fder]->fname),
171 			   cstring_toCharsSafe (ft->elements[i]->fname));
172 		}
173 	      else
174 		{
175 		  fprintf (stderr, "[no file]\n\t%s:1\n",
176 			   cstring_toCharsSafe (ft->elements[i]->fname));
177 		}
178 	    }
179 	}
180     }
181 }
182 
183 /*
184 ** loads in fileTable from fileTable_dump
185 */
186 
187 static /*@notnull@*/ ftentry
ftentry_create(cstring tn,bool temp,fileType typ,fileId der)188 ftentry_create (/*@keep@*/ cstring tn, bool temp, fileType typ, fileId der)
189 {
190   ftentry t = (ftentry) dmalloc (sizeof (*t));
191 
192   if (cstring_isUndefined (tn))
193     {
194       llbug (cstring_makeLiteral ("Undefined filename!"));
195     }
196 
197   t->fname = tn;
198   t->basename = cstring_undefined;
199   t->ftemp = temp;
200   t->ftype = typ;
201   t->fder  = der;
202 
203   /* Don't set these until the basename is needed. */
204   t->fsystem = FALSE;
205   t->fspecial = FALSE;
206 
207   return t;
208 }
209 
210 static void
ftentry_free(ftentry t)211 ftentry_free (/*@only@*/ ftentry t)
212 {
213   cstring_free (t->fname);
214   cstring_free (t->basename);
215   sfree (t);
216 }
217 
218 /*@only@*/ /*@notnull@*/ fileTable
fileTable_create()219 fileTable_create ()
220 {
221   fileTable ft = (fileTable) dmalloc (sizeof (*ft));
222 
223   ft->nentries = 0;
224   ft->nspace = FTBASESIZE;
225   ft->elements = (ftentry *) dmalloc (FTBASESIZE * sizeof (*ft->elements));
226   ft->htable = cstringTable_create (FTHASHSIZE);
227 
228   ft->nopen = 0;
229   ft->nopenspace = FTBASESIZE;
230   ft->openelements = (foentry *) dmalloc (FTBASESIZE * sizeof (*ft->openelements));
231 
232   return (ft);
233 }
234 
235 /*@-bounds@*/
236 static void
fileTable_grow(fileTable ft)237 fileTable_grow (fileTable ft)
238 {
239   int i;
240   ftentry *newent;
241 
242   llassert (fileTable_isDefined (ft));
243 
244   ft->nspace = FTBASESIZE;
245 
246   newent = (ftentry *) dmalloc ((ft->nentries + ft->nspace) * sizeof (*newent));
247 
248   for (i = 0; i < ft->nentries; i++)
249     {
250       newent[i] = ft->elements[i];
251     }
252 
253   sfree (ft->elements);
254   ft->elements = newent;
255 }
256 /*@=bounds@*/
257 static void
fileTable_growOpen(fileTable ft)258 fileTable_growOpen (fileTable ft)
259 {
260   int i;
261   foentry *newent;
262 
263   llassert (fileTable_isDefined (ft));
264 
265   ft->nopenspace = FTBASESIZE;
266 
267   newent = (foentry *) dmalloc ((ft->nopen + ft->nopenspace) * sizeof (*newent));
268 
269   for (i = 0; i < ft->nopen; i++)
270     {
271       newent[i] = ft->openelements[i];
272     }
273 
274   sfree (ft->openelements);
275   ft->openelements = newent;
276 }
277 
278 static fileId
fileTable_internAddEntry(fileTable ft,ftentry e)279 fileTable_internAddEntry (fileTable ft, /*@only@*/ ftentry e)
280 {
281   llassert (fileTable_isDefined (ft));
282 
283   if (ft->nspace <= 0)
284     fileTable_grow (ft);
285 
286   ft->nspace--;
287 
288   DPRINTF (("Adding: %s", e->fname));
289 
290   if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
291     {
292       cstring sd = cstring_downcase (e->fname);
293       cstringTable_insert (ft->htable, sd, ft->nentries);
294     }
295   else
296     {
297       cstringTable_insert (ft->htable, cstring_copy (e->fname), ft->nentries);
298     }
299 
300   /* evans 2002-07-12:
301      Before, there was no cstring_copy above, and e->fname was free'd in the if branch.
302      Splint should have caught this, and produced a warning for this assignment.
303      Why not?
304   */
305   ft->elements[ft->nentries] = e;
306 
307   ft->nentries++;
308   return (ft->nentries - 1);
309 }
310 
fileTable_noDelete(fileTable ft,cstring name)311 void fileTable_noDelete (fileTable ft, cstring name)
312 {
313   fileId fid = fileTable_lookup (ft, name);
314 
315   if (fileId_isValid (fid))
316     {
317       llassert (fileTable_isDefined (ft));
318       ft->elements[fid]->ftype = FILE_NODELETE;
319     }
320   else
321     {
322       DPRINTF (("Invalid no delete: %s", name));
323     }
324 }
325 
326 static fileId
fileTable_addFilePrim(fileTable ft,cstring name,bool temp,fileType typ,fileId der)327 fileTable_addFilePrim (fileTable ft, /*@temp@*/ cstring name,
328 		       bool temp, fileType typ, fileId der)
329    /*@modifies ft@*/
330 {
331   cstring absname = osd_absolutePath (NULL, name);
332   int tindex = fileTable_getIndex (ft, absname);
333 
334   llassert (ft != fileTable_undefined);
335 
336   if (tindex != NOT_FOUND)
337     {
338       llcontbug (message ("fileTable_addFilePrim: duplicate entry: %q", absname));
339       return tindex;
340     }
341   else
342     {
343       ftentry e = ftentry_create (absname, temp, typ, der);
344 
345       if (der == fileId_invalid)
346 	{
347 	  llassert (cstring_isUndefined (e->basename));
348 
349 	  e->basename = fileLib_removePathFree (fileLib_removeAnyExtension (absname));
350 	  e->fsystem = context_isSystemDir (absname);
351 
352 	  /*
353 	  ** evans 2002-03-15: change suggested by Jim Zelenka
354 	  **                   support relative paths for system directories
355 	  */
356 
357 	  if (!e->fsystem)
358 	    {
359 	      e->fsystem = context_isSystemDir (name);
360 	    }
361 
362 	  e->fspecial = context_isSpecialFile (absname);
363 
364 	  if (e->fspecial)
365 	    {
366 	      cstring srcname = cstring_concatFree1 (fileLib_removeAnyExtension (absname),
367 						     C_EXTENSION);
368 	      fileId fid = fileTable_lookup (ft, srcname);
369 	      cstring_free (srcname);
370 
371 	      if (fileId_isValid (fid))
372 		{
373 		  fileId derid = ft->elements[fid]->fder;
374 
375 		  ft->elements[fid]->fspecial = TRUE;
376 
377 		  if (fileId_isValid (derid))
378 		    {
379 		      ft->elements[derid]->fspecial = TRUE;
380 		    }
381 		}
382 	    }
383 	}
384       else
385 	{
386 	  ftentry de = ft->elements[der];
387 
388 	  llassert (cstring_isUndefined (e->basename));
389 	  e->basename = cstring_copy (de->basename);
390 	  e->fsystem = de->fsystem;
391 	  e->fspecial = de->fspecial;
392 	}
393 
394       return (fileTable_internAddEntry (ft, e));
395     }
396 }
397 
398 fileId
fileTable_addFile(fileTable ft,cstring name)399 fileTable_addFile (fileTable ft, cstring name)
400 {
401   return (fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid));
402 }
403 
404 fileId
fileTable_addFileOnly(fileTable ft,cstring name)405 fileTable_addFileOnly (fileTable ft, /*@only@*/ cstring name)
406 {
407   fileId res = fileTable_addFilePrim (ft, name, FALSE, FILE_NORMAL, fileId_invalid);
408   cstring_free (name);
409   return res;
410 }
411 
412 fileId
fileTable_addHeaderFile(fileTable ft,cstring name)413 fileTable_addHeaderFile (fileTable ft, cstring name)
414 {
415   fileId res;
416   res = fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid);
417   return res;
418 
419 }
420 
421 void
fileTable_addStreamFile(fileTable ft,FILE * fstream,cstring name)422 fileTable_addStreamFile (fileTable ft, FILE *fstream, cstring name)
423 {
424   fileTable_addOpen (ft, fstream, cstring_copy (name));
425 }
426 
427 bool
fileTable_isHeader(fileTable ft,fileId fid)428 fileTable_isHeader (fileTable ft, fileId fid)
429 {
430   if (fileId_isInvalid (fid))
431     {
432       return FALSE;
433     }
434 
435   llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
436   return (ft->elements[fid]->ftype == FILE_HEADER);
437 }
438 
439 bool
fileTable_isSystemFile(fileTable ft,fileId fid)440 fileTable_isSystemFile (fileTable ft, fileId fid)
441 {
442   if (fileId_isInvalid (fid))
443     {
444       return FALSE;
445     }
446 
447   llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
448   return (ft->elements[fid]->fsystem);
449 }
450 
451 bool
fileTable_isXHFile(fileTable ft,fileId fid)452 fileTable_isXHFile (fileTable ft, fileId fid)
453 {
454   if (fileId_isInvalid (fid))
455     {
456       return FALSE;
457     }
458 
459   if (!(fileTable_isDefined (ft) && fileTable_inRange (ft, fid)))
460     {
461       llcontbug (message ("Bad file table or id: %s %d", bool_unparse (fileTable_isDefined (ft)), fid));
462       return FALSE;
463     }
464   else
465     {
466       return (ft->elements[fid]->ftype == FILE_XH);
467     }
468 }
469 
470 bool
fileTable_isSpecialFile(fileTable ft,fileId fid)471 fileTable_isSpecialFile (fileTable ft, fileId fid)
472 {
473   if (fileId_isInvalid (fid))
474     {
475       return FALSE;
476     }
477 
478   llassert (fileTable_isDefined (ft) && fileTable_inRange (ft, fid));
479   return (ft->elements[fid]->fspecial);
480 }
481 
482 fileId
fileTable_addLibraryFile(fileTable ft,cstring name)483 fileTable_addLibraryFile (fileTable ft, cstring name)
484 {
485   return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
486 }
487 
488 fileId
fileTable_addXHFile(fileTable ft,cstring name)489 fileTable_addXHFile (fileTable ft, cstring name)
490 {
491   return (fileTable_addFilePrim (ft, name, FALSE, FILE_XH, fileId_invalid));
492 }
493 
494 fileId
fileTable_addImportFile(fileTable ft,cstring name)495 fileTable_addImportFile (fileTable ft, cstring name)
496 {
497   return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
498 }
499 
500 fileId
fileTable_addLCLFile(fileTable ft,cstring name)501 fileTable_addLCLFile (fileTable ft, cstring name)
502 {
503   return (fileTable_addFilePrim (ft, name, FALSE, FILE_HEADER, fileId_invalid));
504 }
505 
506 static int tmpcounter = 0;
507 
508 fileId
fileTable_addMacrosFile(fileTable ft)509 fileTable_addMacrosFile (fileTable ft)
510 {
511   cstring newname =
512     makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("lmx"),
513 		  cstring_makeLiteralTemp (".llm"));
514   fileId res = fileTable_addFilePrim (ft, newname, TRUE, FILE_MACROS, fileId_invalid);
515   cstring_free (newname);
516   return res;
517 }
518 
519 fileId
fileTable_addMetastateFile(fileTable ft,cstring name)520 fileTable_addMetastateFile (fileTable ft, cstring name)
521 {
522   return (fileTable_addFilePrim (ft, name, FALSE, FILE_METASTATE, fileId_invalid));
523 }
524 
525 fileId
fileTable_addCTempFile(fileTable ft,fileId fid)526 fileTable_addCTempFile (fileTable ft, fileId fid)
527 {
528   cstring newname =
529     makeTempName (context_tmpdir (), cstring_makeLiteralTemp ("cl"),
530 		  C_EXTENSION);
531   fileId res;
532 
533   DPRINTF (("tmp dir: %s", context_tmpdir ()));
534   DPRINTF (("new name: %s", newname));
535 
536   llassert (fileTable_isDefined (ft));
537 
538   if (!fileId_isValid (ft->elements[fid]->fder))
539     {
540       if (fileTable_isXHFile (ft, fid))
541 	{
542 	  res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH, fid);
543 	}
544       else
545 	{
546 	  res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL, fid);
547 	}
548     }
549   else
550     {
551       if (fileTable_isXHFile (ft, fid))
552 	{
553 	  res = fileTable_addFilePrim (ft, newname, TRUE, FILE_XH,
554 				       ft->elements[fid]->fder);
555 	}
556       else
557 	{
558 	  res = fileTable_addFilePrim (ft, newname, TRUE, FILE_NORMAL,
559 				       ft->elements[fid]->fder);
560 	}
561     }
562 
563   DPRINTF (("Added file: %s", fileTable_fileName (res)));
564   cstring_free (newname);
565   return res;
566 }
567 
568 fileId
fileTable_addltemp(fileTable ft)569 fileTable_addltemp (fileTable ft)
570 {
571   cstring newname = makeTempName (context_tmpdir (),
572 				  cstring_makeLiteralTemp ("ls"),
573 				  cstring_makeLiteralTemp (".lsl"));
574   fileId ret;
575 
576   if (cstring_hasNonAlphaNumBar (newname))
577     {
578       char *lastpath = (char *)NULL;
579 
580       if (tmpcounter == 0)
581 	{
582 	  lldiagmsg
583 	    (message
584 	     ("Operating system generates tmp filename containing invalid charater: %s",
585 	      newname));
586 	  lldiagmsg (cstring_makeLiteral
587 		     ("Try cleaning up the tmp directory.  Attempting to continue."));
588 	}
589 
590       /*@access cstring@*/
591       llassert (cstring_isDefined (newname));
592       lastpath = strrchr (newname, CONNECTCHAR); /* get the directory */
593       llassert (lastpath != NULL);
594       *lastpath = '\0';
595 
596       newname = message ("%q%hlsl%d.lsl",
597 			 newname,
598 			 CONNECTCHAR,
599 			 tmpcounter);
600       /*@noaccess cstring@*/
601       tmpcounter++;
602     }
603 
604   /*
605   ** this is kind of yucky...need to make the result of cstring_fromChars
606   ** refer to the same storage as its argument.  Of course, this loses,
607   ** since cstring is abstract.  Should make it an only?
608   */
609 
610   ret = fileTable_addFilePrim (ft, newname, TRUE, FILE_LSLTEMP, fileId_invalid);
611   cstring_free (newname);
612   return (ret);
613 }
614 
615 bool
fileTable_exists(fileTable ft,cstring s)616 fileTable_exists (fileTable ft, cstring s)
617 {
618   int tindex = fileTable_getIndex (ft, s);
619 
620   if (tindex == NOT_FOUND)
621     {
622       DPRINTF (("Not found: %s", s));
623       return FALSE;
624     }
625   else
626     {
627       return TRUE;
628     }
629 }
630 
631 fileId
fileTable_lookup(fileTable ft,cstring s)632 fileTable_lookup (fileTable ft, cstring s)
633 {
634   int tindex = fileTable_getIndex (ft, s);
635 
636   if (tindex == NOT_FOUND)
637     {
638       return fileId_invalid;
639     }
640   else
641     {
642       return tindex;
643     }
644 }
645 
646 /*
647 ** This is pretty awkward --- when we find the real path of
648 ** a .xh file, we may need to change the recorded name.  [Sigh]
649 */
650 
651 void
fileTable_setFilePath(fileTable ft,fileId fid,cstring path)652 fileTable_setFilePath (fileTable ft, fileId fid, cstring path)
653 {
654   llassert (fileId_isValid (fid));
655   llassert (fileTable_isDefined (ft));
656   /* Need to put new string in hash table */
657   cstringTable_insert (ft->htable, cstring_copy (path), fid);
658   ft->elements[fid]->fname = cstring_copy (path);
659 }
660 
661 fileId
fileTable_lookupBase(fileTable ft,cstring base)662 fileTable_lookupBase (fileTable ft, cstring base)
663 {
664   int tindex;
665 
666   if (context_getFlag (FLG_CASEINSENSITIVEFILENAMES))
667     {
668       cstring dbase = cstring_downcase (base);
669       tindex = fileTable_getIndex (ft, dbase);
670       cstring_free (dbase);
671     }
672   else
673     {
674       tindex = fileTable_getIndex (ft, base);
675     }
676 
677   if (tindex == NOT_FOUND)
678     {
679       return fileId_invalid;
680     }
681   else
682     {
683       fileId der;
684 
685       llassert (fileTable_isDefined (ft));
686 
687       der = ft->elements[tindex]->fder;
688 
689       if (!fileId_isValid (der))
690 	{
691 	  der = tindex;
692 	}
693 
694       return der;
695     }
696 }
697 
698 cstring
fileTable_getName(fileTable ft,fileId fid)699 fileTable_getName (fileTable ft, fileId fid)
700 {
701   if (!fileId_isValid (fid))
702     {
703       llcontbug
704 	(message ("fileTable_getName: called with invalid type id: %d", fid));
705       return cstring_makeLiteralTemp ("<invalid>");
706     }
707 
708   llassert (fileTable_isDefined (ft));
709   return (ft->elements[fid]->fname);
710 }
711 
712 cstring
fileTable_getRootName(fileTable ft,fileId fid)713 fileTable_getRootName (fileTable ft, fileId fid)
714 {
715   fileId fder;
716 
717   if (!fileId_isValid (fid))
718     {
719       llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
720       return cstring_makeLiteralTemp ("<invalid>");
721     }
722 
723   if (!fileTable_isDefined (ft))
724     {
725       return cstring_makeLiteralTemp ("<no file table>");
726     }
727 
728   fder = ft->elements[fid]->fder;
729 
730   if (fileId_isValid (fder))
731     {
732       return (ft->elements[fder]->fname);
733     }
734   else
735     {
736       return (ft->elements[fid]->fname);
737     }
738 }
739 
740 cstring
fileTable_getNameBase(fileTable ft,fileId fid)741 fileTable_getNameBase (fileTable ft, fileId fid)
742 {
743   if (!fileId_isValid (fid))
744     {
745       llcontbug (message ("fileTable_getName: called with invalid id: %d", fid));
746       return cstring_makeLiteralTemp ("<invalid>");
747     }
748 
749   if (!fileTable_isDefined (ft))
750     {
751       return cstring_makeLiteralTemp ("<no file table>");
752     }
753 
754   return (ft->elements[fid]->basename);
755 }
756 
757 bool
fileTable_sameBase(fileTable ft,fileId f1,fileId f2)758 fileTable_sameBase (fileTable ft, fileId f1, fileId f2)
759 {
760   fileId fd1, fd2;
761 
762   if (!fileId_isValid (f1))
763     {
764       return FALSE;
765     }
766 
767   if (!fileId_isValid (f2))
768     {
769       return FALSE;
770     }
771 
772   llassert (fileTable_isDefined (ft));
773 
774   if (f1 == f2)
775     {
776       return TRUE;
777     }
778 
779   fd1 = ft->elements[f1]->fder;
780 
781   if (!fileId_isValid (fd1))
782     {
783       fd1 = f1;
784     }
785 
786   fd2 = ft->elements[f2]->fder;
787 
788 
789   if (!fileId_isValid (fd2))
790     {
791       fd2 = f2;
792     }
793 
794   return (fd1 == fd2);
795 }
796 
797 void
fileTable_cleanup(fileTable ft)798 fileTable_cleanup (fileTable ft)
799 {
800   int i;
801   bool msg;
802   int skip;
803 
804   llassert (fileTable_isDefined (ft));
805 
806   msg = ((ft->nentries > 40) && context_getFlag (FLG_SHOWSCAN));
807   skip = ft->nentries / 10;
808 
809   if (msg)
810     {
811       (void) fflush (g_warningstream);
812       displayScanOpen (cstring_makeLiteral ("cleaning"));
813     }
814 
815   for (i = 0; i < ft->nentries; i++)
816     {
817       ftentry fe = ft->elements[i];
818 
819       if (fe->ftemp)
820 	{
821 	  /* let's be real careful now, hon! */
822 
823 	  /*
824           ** Make sure it is really a derived file
825 	  */
826 
827 
828 	  if (fe->ftype == FILE_LSLTEMP || fe->ftype == FILE_NODELETE)
829 	    {
830 	      ; /* already removed */
831 	    }
832 	  else if (fileId_isValid (fe->fder))
833 	    {
834 	      /* this should use close (fd) also... */
835 	      (void) osd_unlink (fe->fname);
836 	    }
837 	  else if (fe->ftype == FILE_MACROS)
838 	    {
839 	      (void) osd_unlink (fe->fname);
840 	    }
841 	  else
842 	    {
843 	      llbug (message ("Temporary file is not derivative: %s "
844 			      "(not deleted)", fe->fname));
845 	    }
846 	}
847       else
848 	{
849 	  ;
850 	}
851 
852       if (msg && ((i % skip) == 0))
853 	{
854 	  displayScanContinue (cstring_makeLiteral (i == 0 ? " " : "."));
855 	}
856     }
857 
858   if (msg)
859     {
860       displayScanClose ();
861     }
862 }
863 
864 void
fileTable_free(fileTable f)865 fileTable_free (/*@only@*/ fileTable f)
866 {
867   int i = 0;
868 
869   if (f == (fileTable)NULL)
870     {
871       return;
872     }
873 
874   while ( i < f->nentries )
875     {
876       ftentry_free (f->elements[i]);
877       i++;
878     }
879 
880   cstringTable_free (f->htable);
881   sfree (f->elements);
882   sfree (f->openelements); /*!! why didn't splint report this? */
883   sfree (f);
884 }
885 
886 /*
887 ** unique temp filename are constructed from <dir><pre><pid><msg>.<suf>
888 ** requires: <dir> must end in '/'
889 */
890 
nextMsg(char * msg)891 static void nextMsg (char *msg)
892 {
893   /*@+charint@*/
894   if (msg[0] < 'Z')
895     {
896       msg[0]++;
897     }
898   else
899     {
900       msg[0] = 'A';
901       if (msg[1] < 'Z')
902 	{
903 	  msg[1]++;
904 	}
905       else
906 	{
907 	  msg[1] = 'A';
908 	  if (msg[2] < 'Z')
909 	    {
910 	      msg[2]++;
911 	    }
912 	  else
913 	    {
914 	      msg[2] = 'A';
915 	      if (msg[3] < 'Z')
916 		{
917 		  msg[3]++;
918 		}
919 	      else
920 		{
921 		  llassertprint (FALSE, ("nextMsg: out of unique names!!!"));
922 		}
923 	    }
924 	}
925     }
926   /*@-charint@*/
927 }
928 
makeTempName(cstring dir,cstring pre,cstring suf)929 static /*@only@*/ cstring makeTempName (cstring dir, cstring pre, cstring suf)
930 {
931   static int pid = 0;
932   static /*@owned@*/ char *msg = NULL;
933   static /*@only@*/ cstring pidname = NULL;
934   size_t maxlen;
935   cstring smsg;
936 
937   llassert (cstring_length (pre) <= 3);
938 
939   /*
940   ** We limit the temp name to 8 characters:
941   **   pre: 3 or less
942   **   msg: 3
943   **   pid: 2  (% 100)
944   */
945 
946   if (msg == NULL)
947     {
948       msg = mstring_copy ("AAA"); /* there are 26^3 temp names */
949     }
950 
951   if (pid == 0)
952     {
953       /*@+matchanyintegral@*/
954       pid = osd_getPid ();
955       /*@=matchanyintegral@*/
956     }
957 
958   if (cstring_isUndefined (pidname))
959     {
960       pidname = message ("%d", pid % 100);
961     }
962 
963   maxlen = (cstring_length (dir) + cstring_length (pre) + mstring_length (msg)
964 	    + cstring_length (pidname) + cstring_length (suf) + 2);
965 
966   DPRINTF (("Dir: %s / %s / %s / %s / %s",
967 	    dir, pre, pidname, msg, suf));
968 
969   smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
970   nextMsg (msg);
971 
972   DPRINTF (("Trying: %s", smsg));
973 
974   while (osd_fileExists (smsg))
975     {
976       cstring_free (smsg);
977       smsg = message ("%s%s%s%s%s", dir, pre, pidname, cstring_fromChars (msg), suf);
978       nextMsg (msg);
979     }
980 
981   return smsg;
982 }
983 
984 static foentry
foentry_create(FILE * f,cstring fname)985 foentry_create (/*@exposed@*/ FILE *f, /*@only@*/ cstring fname)
986 {
987   foentry t = (foentry) dmalloc (sizeof (*t));
988   t->f = f;
989   t->fname = fname;
990   return t;
991 }
992 
993 static void
foentry_free(foentry foe)994 foentry_free (/*@only@*/ foentry foe)
995 {
996   cstring_free (foe->fname);
997   sfree (foe);
998 }
999 
1000 static void
fileTable_addOpen(fileTable ft,FILE * f,cstring fname)1001 fileTable_addOpen (fileTable ft, /*@observer@*/ FILE *f, /*@only@*/ cstring fname)
1002 {
1003   llassert (fileTable_isDefined (ft));
1004 
1005   if (ft->nopenspace <= 0)
1006     {
1007       fileTable_growOpen (ft);
1008     }
1009 
1010   ft->nopenspace--;
1011   ft->openelements[ft->nopen] = foentry_create (f, fname);
1012   ft->nopen++;
1013 }
1014 
fileTable_createFile(fileTable ft,cstring fname)1015 FILE *fileTable_createFile (fileTable ft, cstring fname)
1016 {
1017 # if defined (WIN32) && !defined (BCC32)
1018   int fdesc = _open (cstring_toCharsSafe (fname),
1019 		     O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
1020 		     _S_IWRITE | S_IREAD);
1021 # else
1022    int fdesc = open (cstring_toCharsSafe (fname),
1023 		     O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
1024 		     S_IRUSR | S_IWUSR);
1025 # endif
1026 
1027   if (fdesc == -1)
1028     {
1029       osd_setTempError ();
1030       llfatalerror (message ("Temporary file for "
1031 			     "pre-processor output already exists.  Trying to "
1032 			     "open: %s.",
1033 			     fname));
1034 
1035       /*@notreached@*/ return NULL;
1036     }
1037   else
1038     {
1039       FILE *res = fdopen (fdesc, "w");
1040 
1041       if (res != NULL)
1042 	{
1043 	  fileTable_addOpen (ft, res, cstring_copy (fname));
1044 	  DPRINTF (("Opening file: %s / %p", fname, res));
1045 	}
1046       else
1047 	{
1048 	  DPRINTF (("Error opening: %s", fname));
1049 	}
1050 
1051       return res;
1052     }
1053 }
1054 
fileTable_createMacrosFile(fileTable ft,cstring fname)1055 FILE *fileTable_createMacrosFile (fileTable ft, cstring fname)
1056 {
1057 # if defined (WIN32) && !defined (BCC32)
1058   int fdesc = _open (cstring_toCharsSafe (fname),
1059 		     O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
1060 		     _S_IREAD | _S_IWRITE);
1061 # else
1062   int fdesc = open (cstring_toCharsSafe (fname),
1063 		    O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
1064 		    S_IRUSR | S_IWUSR);
1065 # endif
1066 
1067   if (fdesc == -1)
1068     {
1069       osd_setTempError ();
1070       llfatalerror (message ("Temporary file for "
1071 			     "pre-processor output already exists.  Trying to "
1072 			     "open: %s.",
1073 			     fname));
1074 
1075       /*@notreached@*/ return NULL;
1076     }
1077   else
1078     {
1079       FILE *res = fdopen (fdesc, "w+");
1080 
1081       if (res != NULL)
1082 	{
1083 	  fileTable_addOpen (ft, res, cstring_copy (fname));
1084 	  DPRINTF (("Opening file: %s / %p", fname, res));
1085 	}
1086       else
1087 	{
1088 	  DPRINTF (("Error opening: %s", fname));
1089 	}
1090 
1091       return res;
1092     }
1093 }
1094 
fileTable_openReadFile(fileTable ft,cstring fname)1095 FILE *fileTable_openReadFile (fileTable ft, cstring fname)
1096 {
1097   FILE *res = fopen (cstring_toCharsSafe (fname), "r");
1098 
1099   if (res != NULL)
1100     {
1101       fileTable_addOpen (ft, res, cstring_copy (fname));
1102       DPRINTF (("Opening read file: %s / %p", fname, res));
1103     }
1104   else
1105     {
1106       DPRINTF (("Cannot open read file: %s", fname));
1107     }
1108 
1109   return res;
1110 }
1111 
1112 /*
1113 ** Allows overwriting
1114 */
1115 
fileTable_openWriteFile(fileTable ft,cstring fname)1116 FILE *fileTable_openWriteFile (fileTable ft, cstring fname)
1117 {
1118   FILE *res = fopen (cstring_toCharsSafe (fname), "w");
1119 
1120   if (res != NULL) {
1121     fileTable_addOpen (ft, res, cstring_copy (fname));
1122     DPRINTF (("Opening file: %s / %p", fname, res));
1123   }
1124 
1125   return res;
1126 }
1127 
fileTable_openWriteUpdateFile(fileTable ft,cstring fname)1128 FILE *fileTable_openWriteUpdateFile (fileTable ft, cstring fname)
1129 {
1130   FILE *res = fopen (cstring_toCharsSafe (fname), "w+");
1131 
1132   if (res != NULL) {
1133     fileTable_addOpen (ft, res, cstring_copy (fname));
1134     DPRINTF (("Opening file: %s / %p", fname, res));
1135   }
1136 
1137   return res;
1138 }
1139 
fileTable_closeFile(fileTable ft,FILE * f)1140 bool fileTable_closeFile (fileTable ft, FILE *f)
1141 {
1142   bool foundit = FALSE;
1143   int i = 0;
1144 
1145   llassert (fileTable_isDefined (ft));
1146 
1147   DPRINTF (("Closing file: %p", f));
1148 
1149   for (i = 0; i < ft->nopen; i++)
1150     {
1151       if (ft->openelements[i]->f == f)
1152 	{
1153 	  DPRINTF (("Closing file: %p = %s", f, ft->openelements[i]->fname));
1154 
1155 	  if (i == ft->nopen - 1)
1156 	    {
1157 	      foentry_free (ft->openelements[i]);
1158 	      ft->openelements[i] = NULL;
1159 	    }
1160 	  else
1161 	    {
1162 	      foentry_free (ft->openelements[i]);
1163 	      ft->openelements[i] = ft->openelements[ft->nopen - 1];
1164 	      ft->openelements[ft->nopen - 1] = NULL;
1165 	    }
1166 
1167 	  ft->nopen--;
1168 	  ft->nopenspace++;
1169 	  foundit = TRUE;
1170 	  break;
1171 	}
1172     }
1173 
1174   llassert (foundit);
1175   return (fclose (f) == 0);
1176 }
1177 
fileTable_closeAll(fileTable ft)1178 void fileTable_closeAll (fileTable ft)
1179 {
1180   int i = 0;
1181 
1182   llassert (fileTable_isDefined (ft));
1183 
1184   for (i = 0; i < ft->nopen; i++)
1185     {
1186       /*
1187 	 lldiagmsg (message ("Unclosed file at exit: %s", ft->openelements[i]->fname));
1188       */
1189 
1190       if (ft->openelements[i]->f != NULL)
1191 	{
1192 	  (void) fclose (ft->openelements[i]->f); /* No check - cleaning up after errors */
1193 	}
1194 
1195       ft->openelements[i]->f = NULL;
1196       foentry_free (ft->openelements[i]);
1197       ft->openelements[i] = NULL;
1198     }
1199 
1200   ft->nopenspace += ft->nopen;
1201   ft->nopen = 0;
1202 }
1203 
1204