]> andersk Git - splint.git/blob - src/imports.c
10611552928d6f94038fa88fcfab372b6f481452
[splint.git] / src / imports.c
1 /*
2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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 ** imports.c
26 **
27 ** module for importing LCL specs.
28 **
29 **  AUTHOR:
30 **      Yang Meng Tan,
31 **         Massachusetts Institute of Technology
32 */
33
34 # include "lclintMacros.nf"
35 # include "llbasic.h" 
36 # include "osd.h"
37 # include "llgrammar.h" /* need simpleOp, MULOP and logicalOp in makeInfixTermNode */
38 # include "lclscan.h"
39 # include "checking.h"
40 # include "imports.h"
41 # include "lslparse.h"
42 # include "lh.h"
43 # include "llmain.h"
44 # include "portab.h"
45 # include "herald.h"
46
47 void
48 outputLCSFile (char *path, char *msg, char *specname)
49 {
50   static bool haserror = FALSE;
51   char *sfile = mstring_concat (specname, ".lcs");
52   char *outfile = mstring_concat (path, sfile);
53   char *s;
54   FILE *outfptr = fopen (outfile, "w");
55   sfree (sfile);
56
57   DPRINTF (("Output lcl file: %s / %s / %s", path, specname, outfile));
58   
59   /* check write permission */
60   
61   if (outfptr == 0)
62     {                           /* fopen fails */
63       if (!haserror)
64         {
65           lclplainerror (message ("Cannot write to output file: %s", 
66                                   cstring_fromChars (outfile)));
67           haserror = TRUE;
68         }
69       sfree (outfile);
70       return;
71     }
72
73   fprintf (outfptr, "%s", msg);
74   fprintf (outfptr, "%s\n", LCL_PARSE_VERSION);
75   
76   /* output line %LCLimports foo bar ... */
77   fprintf (outfptr, "%%LCLimports ");
78
79   lsymbolSet_elements (g_currentImports, sym)
80     {
81       s = lsymbol_toChars (sym);
82
83       if (s != NULL && !mstring_equal (s, specname))
84         {
85           fprintf (outfptr, "%s ", s);
86         }
87     } end_lsymbolSet_elements;
88   
89   fprintf (outfptr, "\n");
90   
91   sort_dump (outfptr, TRUE);
92   symtable_dump (g_symtab, outfptr, TRUE);
93
94   check (fclose (outfptr) == 0);  
95   sfree (outfile);  
96 }
97
98 void
99 importCTrait (void)
100 {
101   cstring infile = cstring_undefined;
102   filestatus status = osd_findOnLarchPath (cstring_makeLiteralTemp (CTRAITSYMSNAME), 
103                                            &infile);
104
105   switch (status)
106     {
107     case OSD_FILEFOUND:
108       /*
109       ** This line was missing before version 2.3f.  Bug fix by Mike Smith.
110       **    This looks like a bug - infile is already fully qualified path  
111       **    parseSignatures() adds another path to the front and fails to   
112       **    open the file.                                                  
113       */
114            
115       (void) parseSignatures (cstring_fromCharsNew (CTRAITSYMSNAME));
116       (void) parseSignatures (infile);
117       break;
118     case OSD_FILENOTFOUND:
119       /* try spec name */
120       status = osd_findOnLarchPath (cstring_makeLiteralTemp (CTRAITSPECNAME),
121                                     &infile);
122
123       if (status == OSD_FILEFOUND)
124         {
125           callLSL (cstring_makeLiteralTemp (CTRAITSPECNAME),
126                    message ("includes %s (%s for String)",
127                             cstring_fromChars (CTRAITFILENAMEN), 
128                             cstring_fromChars (sort_getName (sort_cstring))));
129           cstring_free (infile);
130           break;
131         }
132       else
133         {
134           lldiagmsg 
135             (message ("Unable to find %s or %s.  Check LARCH_PATH environment variable.",
136                       cstring_fromChars (CTRAITSYMSNAME), 
137                       cstring_fromChars (CTRAITSPECNAME)));
138           cstring_free (infile);
139           llexit (LLFAILURE);
140         }
141     case OSD_PATHTOOLONG:
142       lclbug (message ("importCTrait: the concatenated directory and file "
143                        "name are too long: %s: "
144                        "continuing without it", 
145                        cstring_fromChars (CTRAITSPECNAME)));
146       cstring_free (infile);
147       break;
148     }
149 }
150
151 /*
152 ** processImport --- load imports from file
153 **
154 **    impkind: IMPPLAIN  file on SPEC_PATH
155 **                       # include "./file.h" if it exists,
156 **                       # include "<directory where spec was found>/file.h" if not.
157 **                         (warn if neither exists)
158 **            IMPBRACKET file in default LCL imports directory
159 **                       # include <file.h>
160 **            IMPQUOTE   file directly
161 **                       # include "file.h"
162 */
163
164 void
165 processImport (lsymbol importSymbol, ltoken tok, impkind kind)
166 {
167   bool readableP, oldexporting;
168   bool compressedFormat = FALSE;
169   inputStream imported, imported2, lclsource;
170   char *bufptr;
171   char *tmpbufptr;
172   char *cptr;
173   cstring name;
174   lsymbol sym;
175   char importName[MAX_NAME_LENGTH + 1];
176   cstring importFileName;
177   cstring path = cstring_undefined;
178   cstring fpath, fpath2;
179   mapping map;
180   filestatus ret;
181
182   importFileName = lsymbol_toString (importSymbol);
183   name = cstring_concat (importFileName, cstring_makeLiteralTemp (IO_SUFFIX));
184
185   /*
186   ** find .lcs file
187   */
188   
189   switch (kind)
190     {
191     case IMPPLAIN:
192       path = message ("%s%c%s", cstring_fromChars (g_localSpecPath), SEPCHAR, 
193                       context_getLarchPath ());
194
195       break;
196     case IMPBRACKET:
197       path = cstring_copy (context_getLCLImportDir ());
198       break;
199     case IMPQUOTE:
200       path = cstring_fromCharsNew (g_localSpecPath);
201       break;
202     default:
203       llbuglit ("bad imports case\n");
204     }
205
206   if ((ret = osd_getPath (path, name, &fpath)) != OSD_FILEFOUND)
207     {
208       cstring fname2;
209       
210       if (ret == OSD_PATHTOOLONG)
211         {
212           llfatalerrorLoc (cstring_makeLiteral ("Path too long"));
213         }
214       
215       imported2 = inputStream_create (cstring_copy (importFileName),
216                                       LCL_EXTENSION, FALSE);
217       fname2 = inputStream_fileName (imported2);
218
219       if (osd_getPath (path, fname2, &fpath2) == OSD_FILEFOUND)
220         {
221           llfatalerrorLoc
222             (message ("Specs must be processed before it can be imported: %s", 
223                       fpath2));
224         }
225       else
226         {
227           if (kind == IMPPLAIN || kind == IMPQUOTE)
228             {
229               llfatalerrorLoc (message ("Cannot find file to import: %s", name));
230             }
231           else
232             {
233               llfatalerrorLoc (message ("Cannot find standard import file: %s", name));
234             }
235         }
236     }
237
238   
239   imported = inputStream_create (fpath, cstring_makeLiteralTemp (IO_SUFFIX), FALSE);
240     
241   readableP = inputStream_open (imported);
242     
243   if (!readableP)
244     {                   /* can't read ? */
245       llfatalerrorLoc (message ("Cannot open import file for reading: %s",
246                                 inputStream_fileName (imported)));
247     }
248
249   bufptr = inputStream_nextLine (imported);
250
251   if (bufptr == 0)
252     {
253       llerror (FLG_SYNTAX, message ("Import file is empty: %s", 
254                                     inputStream_fileName (imported)));
255       cstring_free (name);
256       (void) inputStream_close (imported);
257       inputStream_free (imported);
258
259       cstring_free (path);
260       return;
261     }
262
263   /* was it processed successfully ? */
264   if (firstWord (bufptr, "%FAILED"))
265     {
266       llfatalerrorLoc
267         (message ("Imported file was not checked successfully: %s.", name));
268     }
269   
270   /*
271   ** Is it generated by the right version of the checker? 
272   **
273   ** Uncompressed  .lcs files start with %PASSED
274   ** Compressed files start with %LCS 
275   */
276   
277   if (firstWord (bufptr, "%PASSED"))
278     {
279       /* %PASSED Output from LCP Version 2.* and 3.* */
280       /*                     1234567890123*/
281       /*                                 +*/
282
283       cptr = strstr (bufptr, "LCP Version");
284       
285       if (cptr != NULL)
286         {
287           /* 
288           ** Only really old files start this way!
289           */
290
291           cptr += 12;
292           if (*cptr != '2' && *cptr != '3')
293             {
294               llfatalerrorLoc (message ("Imported file %s is obsolete: %s.",
295                                         inputStream_fileName (imported),
296                                         cstring_fromChars (bufptr)));
297             }
298         }
299
300       compressedFormat = FALSE;
301     }
302   else 
303     {
304       if (!firstWord (bufptr, "%LCS"))
305         {
306           llfatalerrorLoc (message ("Imported file %s is not in correct format: %s",
307                                     inputStream_fileName (imported),
308                                     cstring_fromChars (bufptr)));
309         }
310       
311       compressedFormat = TRUE;
312     }
313   
314   /* push the imported LCL spec onto g_currentImports */
315
316   context_enterImport ();
317   
318   bufptr = inputStream_nextLine (imported);
319   llassert (bufptr != NULL);
320
321   tmpbufptr = bufptr;
322
323     /* expect %LCLimports foo bar ... */
324   if (firstWord (bufptr, "%LCLimports "))
325     {
326       bufptr = bufptr + strlen ("%LCLimports ");
327       while (sscanf (bufptr, "%s", importName) == 1)
328         {
329           bufptr = bufptr + strlen (importName) + 1;    /* 1 for space */
330           sym = lsymbol_fromChars (importName);
331           if (sym == importSymbol || 
332               lsymbolSet_member (g_currentImports, sym))
333             {
334               /* ensure that the import list does not contain itself: an
335                  invariant useful for checking imports cycles. */
336               lclsource = LCLScanSource ();
337               lclfatalerror (tok, 
338                              message ("Imports cycle: %s%s imports %s",
339                                       importFileName,
340                                       LCL_EXTENSION,
341                                       cstring_fromChars (importName)));
342             }     
343           /* push them onto g_currentImports */
344           /* evs - 94 Apr 3:  I don't think it should do this! */
345           /* (void) lsymbolSet_insert (g_currentImports, sym); */
346         }
347     }
348   else
349     {
350       lclsource = LCLScanSource ();
351       lclfatalerror (tok, message ("Unexpected line in imported file %s: %s", 
352                                    name, 
353                                    cstring_fromChars (bufptr)));
354     }
355           
356   /* read in the imported info */
357   oldexporting = sort_setExporting (TRUE);
358
359   map = mapping_create ();
360
361   /* tok for error line numbering */
362
363   if (!compressedFormat)
364     {
365       sort_import (imported, tok, map); 
366     }
367   
368   (void) sort_setExporting (oldexporting);
369   
370   /* sort_import updates a mapping of old anonymous sorts to new
371      anonymous sort that is needed in symtable_import */
372   /* mapping_print (map); */
373   
374   if (!compressedFormat)
375     {
376       symtable_import (imported, tok, map);
377     }
378   else
379     {
380       /* symtable_loadImport (imported, tok, map); */
381     }
382   
383   check (inputStream_close (imported));
384   inputStream_free (imported);
385   
386   mapping_free (map);
387   cstring_free (name);
388   cstring_free (path);
389
390   context_leaveImport ();  
391 }
392
393
394
This page took 1.70523 seconds and 3 git commands to generate.