First part of transition from not-function header.
[splint-patched.git] / src / imports.c
blobb323f1878ba39ffa9c249d734652adf0386d7790
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);
99 switch (status)
101 case OSD_FILEFOUND:
103 ** This line was missing before version 2.3f. Bug fix by Mike Smith.
104 ** This looks like a bug - infile is already fully qualified path
105 ** parseSignatures() adds another path to the front and fails to
106 ** open the file.
109 (void) parseSignatures (cstring_fromCharsNew (CTRAITSYMSNAME));
110 (void) parseSignatures (infile);
111 break;
112 case OSD_FILENOTFOUND:
113 /* try spec name */
114 status = osd_getPath (context_getLarchPath (),
115 cstring_makeLiteralTemp (CTRAITSPECNAME),
116 &infile);
118 if (status == OSD_FILEFOUND)
120 callLSL (cstring_makeLiteralTemp (CTRAITSPECNAME),
121 message ("includes %s (%s for String)",
122 cstring_fromChars (CTRAITFILENAMEN),
123 cstring_fromChars (sort_getName (g_sortCstring))));
124 cstring_free (infile);
125 break;
127 else
129 lldiagmsg
130 (message ("Unable to find %s or %s. Check LARCH_PATH environment variable.",
131 cstring_fromChars (CTRAITSYMSNAME),
132 cstring_fromChars (CTRAITSPECNAME)));
133 cstring_free (infile);
134 failexit ();
136 case OSD_PATHTOOLONG:
137 lclbug (message ("importCTrait: the concatenated directory and file "
138 "name are too long: %s: "
139 "continuing without it",
140 cstring_fromChars (CTRAITSPECNAME)));
141 cstring_free (infile);
142 break;
147 ** processImport --- load imports from file
149 ** impkind: IMPPLAIN file on SPEC_PATH
150 ** # include "./file.h" if it exists,
151 ** # include "<directory where spec was found>/file.h" if not.
152 ** (warn if neither exists)
153 ** IMPBRACKET file in default LCL imports directory
154 ** # include <file.h>
155 ** IMPQUOTE file directly
156 ** # include "file.h"
159 void
160 processImport (lsymbol importSymbol, ltoken tok, impkind kind)
162 bool readableP, oldexporting;
163 bool compressedFormat = FALSE;
164 inputStream imported, imported2;
165 char *bufptr;
166 char *cptr;
167 cstring name;
168 lsymbol sym;
169 char importName[MAX_NAME_LENGTH + 1];
170 cstring importFileName;
171 cstring path = cstring_undefined;
172 cstring fpath, fpath2;
173 mapping map;
174 filestatus ret;
176 importFileName = lsymbol_toString (importSymbol);
177 name = cstring_concat (importFileName, cstring_makeLiteralTemp (IO_SUFFIX));
180 ** find .lcs file
183 switch (kind)
185 case IMPPLAIN:
186 path = osd_pathListConcat (g_localSpecPath,
187 cstring_toCharsSafe (context_getLarchPath ()));
189 break;
190 case IMPBRACKET:
191 path = cstring_copy (context_getLCLImportDir ());
192 break;
193 case IMPQUOTE:
194 path = cstring_fromCharsNew (g_localSpecPath);
195 break;
196 default:
197 llbuglit ("bad imports case\n");
200 if ((ret = osd_getPath (path, name, &fpath)) != OSD_FILEFOUND)
202 cstring fname2;
204 if (ret == OSD_PATHTOOLONG)
206 llfatalerrorLoc (cstring_makeLiteral ("Path too long"));
209 imported2 = inputStream_create (cstring_copy (importFileName),
210 LCL_EXTENSION, FALSE);
211 fname2 = inputStream_fileName (imported2);
213 if (osd_getPath (path, fname2, &fpath2) == OSD_FILEFOUND)
215 llfatalerrorLoc
216 (message ("Specs must be processed before it can be imported: %s",
217 fpath2));
219 else
221 if (kind == IMPPLAIN || kind == IMPQUOTE)
223 llfatalerrorLoc (message ("Cannot find file to import: %s", name));
225 else
227 llfatalerrorLoc (message ("Cannot find standard import file: %s", name));
233 imported = inputStream_create (fpath, cstring_makeLiteralTemp (IO_SUFFIX), FALSE);
235 readableP = inputStream_open (imported);
237 if (!readableP)
238 { /* can't read ? */
239 llfatalerrorLoc (message ("Cannot open import file for reading: %s",
240 inputStream_fileName (imported)));
243 bufptr = inputStream_nextLine (imported);
245 if (bufptr == 0)
247 llerror (FLG_SYNTAX, message ("Import file is empty: %s",
248 inputStream_fileName (imported)));
249 cstring_free (name);
250 (void) inputStream_close (imported);
251 inputStream_free (imported);
253 cstring_free (path);
254 return;
257 /* was it processed successfully ? */
258 if (firstWord (bufptr, "%FAILED"))
260 llfatalerrorLoc
261 (message ("Imported file was not checked successfully: %s.", name));
265 ** Is it generated by the right version of the checker?
267 ** Uncompressed .lcs files start with %PASSED
268 ** Compressed files start with %LCS
271 if (firstWord (bufptr, "%PASSED"))
273 /* %PASSED Output from LCP Version 2.* and 3.* */
274 /* 1234567890123*/
275 /* +*/
277 cptr = strstr (bufptr, "LCP Version");
279 if (cptr != NULL)
282 ** Only really old files start this way!
285 cptr += 12;
286 if (*cptr != '2' && *cptr != '3')
288 llfatalerrorLoc (message ("Imported file %s is obsolete: %s.",
289 inputStream_fileName (imported),
290 cstring_fromChars (bufptr)));
294 compressedFormat = FALSE;
296 else
298 if (!firstWord (bufptr, "%LCS"))
300 llfatalerrorLoc (message ("Imported file %s is not in correct format: %s",
301 inputStream_fileName (imported),
302 cstring_fromChars (bufptr)));
305 compressedFormat = TRUE;
308 /* push the imported LCL spec onto g_currentImports */
310 context_enterImport ();
312 bufptr = inputStream_nextLine (imported);
313 llassert (bufptr != NULL);
315 /* expect %LCLimports foo bar ... */
316 if (firstWord (bufptr, "%LCLimports "))
318 bufptr = bufptr + strlen ("%LCLimports ");
319 while (sscanf (bufptr, "%s", importName) == 1)
321 bufptr = bufptr + strlen (importName) + 1; /* 1 for space */
322 sym = lsymbol_fromChars (importName);
323 if (sym == importSymbol ||
324 lsymbolSet_member (g_currentImports, sym))
326 /* ensure that the import list does not contain itself: an
327 invariant useful for checking imports cycles. */
328 lclfatalerror (tok,
329 message ("Imports cycle: %s%s imports %s",
330 importFileName,
331 LCL_EXTENSION,
332 cstring_fromChars (importName)));
334 /* push them onto g_currentImports */
335 /* evs - 94 Apr 3: I don't think it should do this! */
336 /* (void) lsymbolSet_insert (g_currentImports, sym); */
339 else
341 lclfatalerror (tok, message ("Unexpected line in imported file %s: %s",
342 name,
343 cstring_fromChars (bufptr)));
346 /* read in the imported info */
347 oldexporting = sort_setExporting (TRUE);
349 map = mapping_create ();
351 /* tok for error line numbering */
353 if (!compressedFormat)
355 sort_import (imported, tok, map);
358 (void) sort_setExporting (oldexporting);
360 /* sort_import updates a mapping of old anonymous sorts to new
361 anonymous sort that is needed in symtable_import */
362 /* mapping_print (map); */
364 if (!compressedFormat)
366 symtable_import (imported, tok, map);
368 else
370 /* symtable_loadImport (imported, tok, map); */
373 check (inputStream_close (imported));
374 inputStream_free (imported);
376 mapping_free (map);
377 cstring_free (name);
378 cstring_free (path);
380 context_leaveImport ();