Don't try calling lsl when file is missing.
[splint-patched.git] / src / imports.c
blobbdda9843e39f0b3dff16f56bc2fb18807d265eed
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 ** imports.c
27 ** module for importing LCL specs.
29 ** AUTHOR:
30 ** Yang Meng Tan,
31 ** Massachusetts Institute of Technology
34 # include "splintMacros.nf"
35 # include "basic.h"
36 # include "osd.h"
37 # include "imports.h"
38 # include "lslparse.h"
40 void
41 outputLCSFile (char *path, char *msg, char *specname)
43 static bool haserror = FALSE;
44 char *sfile = mstring_concat (specname, ".lcs");
45 char *outfile = mstring_concat (path, sfile);
46 char *s;
47 FILE *outfptr = fileTable_openWriteFile (context_fileTable (), cstring_fromChars (outfile));
48 sfree (sfile);
50 DPRINTF (("Output lcl file: %s / %s / %s", path, specname, outfile));
52 /* check write permission */
54 if (outfptr == NULL) /* Cannot open file */
56 if (!haserror)
58 lclplainerror (message ("Cannot write to output file: %s",
59 cstring_fromChars (outfile)));
60 haserror = TRUE;
62 sfree (outfile);
63 return;
66 fprintf (outfptr, "%s", msg);
67 fprintf (outfptr, "%s\n", PACKAGE_STRING);
69 /* output line %LCLimports foo bar ... */
70 fprintf (outfptr, "%%LCLimports ");
72 lsymbolSet_elements (g_currentImports, sym)
74 s = lsymbol_toChars (sym);
76 if (s != NULL && !mstring_equal (s, specname))
78 fprintf (outfptr, "%s ", s);
80 } end_lsymbolSet_elements;
82 fprintf (outfptr, "\n");
84 sort_dump (outfptr, TRUE);
85 symtable_dump (g_symtab, outfptr, TRUE);
87 check (fileTable_closeFile (context_fileTable (), outfptr));
88 sfree (outfile);
91 void
92 importCTrait (void)
94 cstring infile = cstring_undefined;
95 filestatus status = osd_getPath (context_getLarchPath (),
96 cstring_makeLiteralTemp (CTRAITSYMSNAME),
97 &infile);
98 if (status == OSD_FILEFOUND)
101 ** This line was missing before version 2.3f. Bug fix by Mike Smith.
102 ** This looks like a bug - infile is already fully qualified path
103 ** parseSignatures() adds another path to the front and fails to
104 ** open the file.
107 (void) parseSignatures (cstring_fromCharsNew (CTRAITSYMSNAME));
108 (void) parseSignatures (infile);
110 else
112 if (status == OSD_FILENOTFOUND)
114 lldiagmsg
115 (message ("Unable to find %s. Check LARCH_PATH environment variable.",
116 cstring_fromChars (CTRAITSYMSNAME)));
118 else /* if (status == OSD_PATHTOOLONG) */
120 lldiagmsg
121 (message ("The concatenated directory (from LARCH_PATH) and file name (%s) are too long",
122 cstring_fromChars (CTRAITSYMSNAME)));
124 cstring_free (infile);
125 failexit ();
130 ** processImport --- load imports from file
132 ** impkind: IMPPLAIN file on SPEC_PATH
133 ** # include "./file.h" if it exists,
134 ** # include "<directory where spec was found>/file.h" if not.
135 ** (warn if neither exists)
136 ** IMPBRACKET file in default LCL imports directory
137 ** # include <file.h>
138 ** IMPQUOTE file directly
139 ** # include "file.h"
142 void
143 processImport (lsymbol importSymbol, ltoken tok, impkind kind)
145 bool readableP, oldexporting;
146 bool compressedFormat = FALSE;
147 inputStream imported, imported2;
148 char *bufptr;
149 char *cptr;
150 cstring name;
151 lsymbol sym;
152 char importName[MAX_NAME_LENGTH + 1];
153 cstring importFileName;
154 cstring path = cstring_undefined;
155 cstring fpath, fpath2;
156 mapping map;
157 filestatus ret;
159 importFileName = lsymbol_toString (importSymbol);
160 name = cstring_concat (importFileName, cstring_makeLiteralTemp (IO_SUFFIX));
163 ** find .lcs file
166 switch (kind)
168 case IMPPLAIN:
169 path = osd_pathListConcat (g_localSpecPath,
170 cstring_toCharsSafe (context_getLarchPath ()));
172 break;
173 case IMPBRACKET:
174 path = cstring_copy (context_getLCLImportDir ());
175 break;
176 case IMPQUOTE:
177 path = cstring_fromCharsNew (g_localSpecPath);
178 break;
179 default:
180 llbuglit ("bad imports case\n");
183 if ((ret = osd_getPath (path, name, &fpath)) != OSD_FILEFOUND)
185 cstring fname2;
187 if (ret == OSD_PATHTOOLONG)
189 llfatalerrorLoc (cstring_makeLiteral ("Path too long"));
192 imported2 = inputStream_create (cstring_copy (importFileName),
193 LCL_EXTENSION, FALSE);
194 fname2 = inputStream_fileName (imported2);
196 if (osd_getPath (path, fname2, &fpath2) == OSD_FILEFOUND)
198 llfatalerrorLoc
199 (message ("Specs must be processed before it can be imported: %s",
200 fpath2));
202 else
204 if (kind == IMPPLAIN || kind == IMPQUOTE)
206 llfatalerrorLoc (message ("Cannot find file to import: %s", name));
208 else
210 llfatalerrorLoc (message ("Cannot find standard import file: %s", name));
216 imported = inputStream_create (fpath, cstring_makeLiteralTemp (IO_SUFFIX), FALSE);
218 readableP = inputStream_open (imported);
220 if (!readableP)
221 { /* can't read ? */
222 llfatalerrorLoc (message ("Cannot open import file for reading: %s",
223 inputStream_fileName (imported)));
226 bufptr = inputStream_nextLine (imported);
228 if (bufptr == 0)
230 llerror (FLG_SYNTAX, message ("Import file is empty: %s",
231 inputStream_fileName (imported)));
232 cstring_free (name);
233 (void) inputStream_close (imported);
234 inputStream_free (imported);
236 cstring_free (path);
237 return;
240 /* was it processed successfully ? */
241 if (firstWord (bufptr, "%FAILED"))
243 llfatalerrorLoc
244 (message ("Imported file was not checked successfully: %s.", name));
248 ** Is it generated by the right version of the checker?
250 ** Uncompressed .lcs files start with %PASSED
251 ** Compressed files start with %LCS
254 if (firstWord (bufptr, "%PASSED"))
256 /* %PASSED Output from LCP Version 2.* and 3.* */
257 /* 1234567890123*/
258 /* +*/
260 cptr = strstr (bufptr, "LCP Version");
262 if (cptr != NULL)
265 ** Only really old files start this way!
268 cptr += 12;
269 if (*cptr != '2' && *cptr != '3')
271 llfatalerrorLoc (message ("Imported file %s is obsolete: %s.",
272 inputStream_fileName (imported),
273 cstring_fromChars (bufptr)));
277 compressedFormat = FALSE;
279 else
281 if (!firstWord (bufptr, "%LCS"))
283 llfatalerrorLoc (message ("Imported file %s is not in correct format: %s",
284 inputStream_fileName (imported),
285 cstring_fromChars (bufptr)));
288 compressedFormat = TRUE;
291 /* push the imported LCL spec onto g_currentImports */
293 context_enterImport ();
295 bufptr = inputStream_nextLine (imported);
296 llassert (bufptr != NULL);
298 /* expect %LCLimports foo bar ... */
299 if (firstWord (bufptr, "%LCLimports "))
301 bufptr = bufptr + strlen ("%LCLimports ");
302 while (sscanf (bufptr, "%s", importName) == 1)
304 bufptr = bufptr + strlen (importName) + 1; /* 1 for space */
305 sym = lsymbol_fromChars (importName);
306 if (sym == importSymbol ||
307 lsymbolSet_member (g_currentImports, sym))
309 /* ensure that the import list does not contain itself: an
310 invariant useful for checking imports cycles. */
311 lclfatalerror (tok,
312 message ("Imports cycle: %s%s imports %s",
313 importFileName,
314 LCL_EXTENSION,
315 cstring_fromChars (importName)));
317 /* push them onto g_currentImports */
318 /* evs - 94 Apr 3: I don't think it should do this! */
319 /* (void) lsymbolSet_insert (g_currentImports, sym); */
322 else
324 lclfatalerror (tok, message ("Unexpected line in imported file %s: %s",
325 name,
326 cstring_fromChars (bufptr)));
329 /* read in the imported info */
330 oldexporting = sort_setExporting (TRUE);
332 map = mapping_create ();
334 /* tok for error line numbering */
336 if (!compressedFormat)
338 sort_import (imported, tok, map);
341 (void) sort_setExporting (oldexporting);
343 /* sort_import updates a mapping of old anonymous sorts to new
344 anonymous sort that is needed in symtable_import */
345 /* mapping_print (map); */
347 if (!compressedFormat)
349 symtable_import (imported, tok, map);
351 else
353 /* symtable_loadImport (imported, tok, map); */
356 check (inputStream_close (imported));
357 inputStream_free (imported);
359 mapping_free (map);
360 cstring_free (name);
361 cstring_free (path);
363 context_leaveImport ();