]> andersk Git - splint.git/blob - src/llmain.c
Commented out the context_destroyMod (); destroy line
[splint.git] / src / llmain.c
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 ** llmain.c
26 **
27 ** Main module for Splint annotation-assisted program checker
28 */
29
30 # include <signal.h>
31 # include <time.h>
32 /*
33 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
34 */
35
36 # ifdef WIN32
37 # ifndef _WIN32
38 # error "Inconsistent definitions."
39 # endif
40 # else
41 # ifdef _WIN32
42 # error "Inconsistent definitions."
43 # endif
44 # endif
45
46 # ifdef WIN32
47 # include <windows.h>
48 # include <process.h>
49 # endif
50
51 # include "splintMacros.nf"
52 # include "basic.h"
53 # include "osd.h"
54 # include "help.h"
55 # include "gram.h"
56 # include "lclscan.h"
57 # include "scanline.h"
58 # include "lclscanline.h"
59 # include "lclsyntable.h"
60 # include "lcltokentable.h"
61 # include "lslparse.h"
62 # include "scan.h"
63 # include "syntable.h"
64 # include "tokentable.h"
65 # include "lslinit.h"
66 # include "lclinit.h"
67 # include "lh.h"
68 # include "imports.h"
69
70 # include "Headers/version.h" /* Visual C++ finds the wrong version.h */
71 # include "lcllib.h"
72 # include "cgrammar.h"
73 # include "rcfiles.h"
74 # include "llmain.h"
75
76 extern /*@external@*/ int yydebug;
77 static void cleanupFiles (void);
78 /*
79 ** evans 2002-07-03: renamed from interrupt to avoid conflict with WATCOM compiler keyword
80 **    (Suggested by Adam Clarke)
81 */
82
83 static void llinterrupt (int p_i);
84
85 static void describeVars (void);
86 static bool specialFlagsHelp (char *p_next);
87 static bool hasShownHerald = FALSE;
88 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath) 
89      /*@modifies *p_inpath@*/ ;
90
91 static bool anylcl = FALSE;
92 static clock_t inittime;
93
94 static fileIdList preprocessFiles (fileIdList, bool)
95   /*@modifies fileSystem@*/ ;
96
97 static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/;
98
99 static
100 void lslCleanup (void)
101    /*@globals killed g_symtab@*/
102    /*@modifies internalState, g_symtab@*/
103 {
104   /*
105   ** Cleanup all the LCL/LSL.
106   */
107
108   static bool didCleanup = FALSE;
109
110   llassert (!didCleanup);
111   llassert (anylcl);
112
113   didCleanup = TRUE;
114
115   lsymbol_destroyMod ();
116   LCLSynTableCleanup ();
117   LCLTokenTableCleanup ();
118   LCLScanLineCleanup ();
119   LCLScanCleanup ();
120
121   /* clean up LSL parsing */
122
123   lsynTableCleanup ();
124   ltokenTableCleanup ();
125   lscanLineCleanup ();
126   LSLScanCleanup ();
127
128   symtable_free (g_symtab);
129   sort_destroyMod (); 
130 }
131
132 static void
133 lslProcess (fileIdList lclfiles)
134    /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
135               undef killed g_symtab; @*/
136    /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
137 {
138   char *path = NULL;
139   bool parser_status = FALSE;
140   bool overallStatus = FALSE;
141   
142   lslinit_process ();
143   inittime = clock ();
144     
145   context_resetSpecLines ();
146
147   fileIdList_elements (lclfiles, fid)
148     {
149       cstring actualName = cstring_undefined;
150       cstring fname = fileTable_fileName (fid);
151       
152       if (osd_getPath (cstring_fromChars (g_localSpecPath), 
153                        fname, &actualName) == OSD_FILENOTFOUND)
154         {
155           if (mstring_equal (g_localSpecPath, "."))
156             {
157               lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
158             }
159           else
160             {
161               lldiagmsg (message ("Spec file not found: %q (on %s)", 
162                                   osd_outputPath (fname), 
163                                   cstring_fromChars (g_localSpecPath)));
164             }
165         }
166       else
167         {
168           inputStream specFile;
169           /*@access cstring@*/
170           char *namePtr = actualName;
171
172           while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR) 
173             {
174               namePtr += 2;
175             }
176           /*@noaccess cstring@*/
177
178           g_currentSpec = cstring_fromCharsNew (namePtr);
179
180           specFile = inputStream_create (cstring_copy (g_currentSpec),
181                                          LCL_EXTENSION, TRUE);
182           
183           llassert (inputStream_isDefined (specFile));
184           
185           g_currentSpecName = specFullName 
186             (cstring_toCharsSafe (g_currentSpec),
187              &path);
188
189           setSpecFileId (fid);
190                   
191           displayScan (message ("reading spec %s", g_currentSpec));
192           
193           /* Open the source file */
194           
195           if (!inputStream_open (specFile))
196             {
197               lldiagmsg (message ("Cannot open file: %q",
198                                   osd_outputPath (inputStream_fileName (specFile))));
199               inputStream_free (specFile);
200             }
201           else
202             {
203               scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
204               dummy_scope->kind = SPE_INVALID;
205               
206               lhInit (specFile);
207               LCLScanReset (specFile);
208               
209               /* 
210               ** Minor hacks to allow more than one LCL file to
211               ** be scanned, while keeping initializations
212               */
213               
214               symtable_enterScope (g_symtab, dummy_scope);
215               resetImports (cstring_fromChars (g_currentSpecName));
216               context_enterLCLfile ();
217               (void) lclHadNewError ();
218               
219               parser_status = (ylparse () != 0);
220               context_exitLCLfile ();
221               lhCleanup ();
222               overallStatus = parser_status || lclHadNewError (); 
223
224               if (context_getFlag (FLG_DOLCS))
225                 {
226                   if (overallStatus)
227                     {
228                       outputLCSFile (path, "%FAILED Output from ",
229                                      g_currentSpecName);
230                     }
231                   else
232                     {
233                       outputLCSFile (path, "%PASSED Output from ", 
234                                      g_currentSpecName);
235                     }
236                 }
237
238               (void) inputStream_close (specFile);
239               inputStream_free (specFile);
240
241               symtable_exitScope (g_symtab);
242             }      
243         }
244       cstring_free (actualName);
245     } end_fileIdList_elements; 
246     
247     /* Can cleanup lsl stuff right away */
248     
249     lslCleanup ();
250     
251     g_currentSpec = cstring_undefined;
252     g_currentSpecName = NULL;
253 }
254
255 static void handlePassThroughFlag (char *arg)
256 {
257   char *curarg = arg;
258   char *quotechar = strchr (curarg, '\"');
259   int offset = 0;
260   bool open = FALSE;
261   char *freearg = NULL;
262
263   while (quotechar != NULL)
264     {
265       if (*(quotechar - 1) == '\\')
266         {
267           char *tp = quotechar - 2;
268           bool escape = TRUE;
269
270           while (*tp == '\\')
271             {
272               escape = !escape;
273               tp--;
274             }
275           
276           if (escape)
277             {
278               curarg = quotechar + 1;
279               quotechar = strchr (curarg, '\"');
280               continue;
281             }
282         }
283       
284       llassert (quotechar != NULL);
285       *quotechar = '\0';
286       offset = (quotechar - arg) + 2;
287       
288       if (open)
289         {
290           arg = cstring_toCharsSafe
291             (message ("%s\"\'%s", 
292                       cstring_fromChars (arg), 
293                       cstring_fromChars (quotechar + 1))); 
294           freearg = arg;
295           open = FALSE;
296         }
297       else
298         {
299           arg = cstring_toCharsSafe
300             (message ("%s\'\"%s", 
301                       cstring_fromChars (arg), 
302                       cstring_fromChars (quotechar + 1)));
303           freearg = arg;
304           open = TRUE;
305         }
306       
307       curarg = arg + offset;
308       quotechar = strchr (curarg, '\"');
309     }
310
311   if (open)
312     {
313       showHerald ();
314       voptgenerror (FLG_BADFLAG,
315                     message ("Unclosed quote in flag: %s",
316                              cstring_fromChars (arg)),
317                     g_currentloc);
318     }
319   else
320     {
321       if (arg[0] == 'D') {
322         cstring def;
323         
324         /* 
325         ** If the value is surrounded by single quotes ('), remove
326         ** them.  This is an artifact of UNIX command line?
327         */
328
329         def = osd_fixDefine (cstring_fromChars (arg + 1));
330         DPRINTF (("Do define: %s", def));
331         cppDoDefine (def);
332         DPRINTF (("After define"));
333         cstring_free (def);
334       } else if (arg[0] == 'U') {
335         cppDoUndefine (cstring_fromChars (arg + 1));
336       } else {
337         BADBRANCH;
338       }
339     }
340   
341   sfree (freearg);
342 }
343
344 void showHerald (void)
345 {
346   if (hasShownHerald || context_getFlag (FLG_QUIET)) 
347     {
348       return;
349     }
350   else
351     {
352       fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION);
353       hasShownHerald = TRUE;
354       llflush ();
355     }
356 }
357
358 /*
359 ** Disable MSVC++ warning about return value.  Methinks humbly splint control
360 ** comments are a mite more legible.
361 */
362
363 # ifdef WIN32
364 # pragma warning (disable:4035) 
365 # endif
366
367 int main (int argc, char *argv[])
368   /*@globals killed undef g_currentloc,
369              killed       g_localSpecPath,  
370              killed undef g_currentSpec,
371              killed undef g_currentSpecName,
372              killed undef yyin,
373                     undef g_warningstream, g_messagestream, g_errorstream;
374    @*/
375   /*@modifies g_currentloc, g_localSpecPath, g_currentSpec, g_currentSpecName, 
376               fileSystem, yyin; 
377   @*/
378 {
379   bool first_time = TRUE;
380   bool expsuccess;
381   inputStream sourceFile = inputStream_undefined;
382  
383   fileIdList dercfiles;
384   cstringList passThroughArgs = cstringList_undefined;
385   fileIdList cfiles, xfiles, lclfiles, mtfiles;
386   clock_t before, lcltime, libtime, pptime, cptime, rstime;
387   int i = 0;
388
389 # ifdef __EMX__
390   _wildcard (&argc, &argv);
391 # endif
392
393   g_warningstream = stdout;
394   g_messagestream = stderr;
395   g_errorstream = stderr;
396
397   (void) signal (SIGINT, llinterrupt);
398   (void) signal (SIGSEGV, llinterrupt); 
399
400   flags_initMod ();
401   qual_initMod ();
402   clabstract_initMod ();
403   typeIdSet_initMod ();
404   osd_initMod ();
405   cppReader_initMod ();
406
407   setCodePoint ();
408   
409   g_currentloc = fileloc_createBuiltin ();
410     
411   before = clock ();
412   context_initMod ();
413
414   context_setInCommandLine ();
415
416   if (argc <= 1)
417     {
418       help_showAvailableHelp ();
419       llexit (LLSUCCESS);
420     }
421   
422   /* -help must be the first flag to get help */
423   if (flagcode_isHelpFlag (flags_identifyFlag (cstring_fromChars (argv[1]))))
424     {
425       /*
426       ** Skip first flag and help flag
427       */
428
429       help_processFlags (argc - 2, argv + 2);
430       llexit (LLSUCCESS);
431     }
432
433   setCodePoint ();
434   yydebug = 0;
435
436   /*
437   ** Add include directories from environment.
438   */
439
440   {
441     cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
442     cstring oincval = incval;
443
444     if (cstring_isDefined (incval))
445       {
446         /*
447         ** Each directory on the include path is a system include directory.
448         */
449
450         DPRINTF (("include: %s", incval));
451         context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
452
453         while (cstring_isDefined (incval))
454           {
455             /*@access cstring@*/
456             char *nextsep = strchr (incval, PATH_SEPARATOR);
457
458             if (nextsep != NULL)
459               {
460                 cstring dir;
461                 *nextsep = '\0';
462                 dir = cstring_copy (incval);
463
464                 if (cstring_length (dir) == 0
465                     || !isalpha ((int) cstring_firstChar (dir)))
466                   {
467                     /* 
468                     ** win32 environment values can have special values,
469                     ** ignore them
470                     */
471                   }
472                 else
473                   {
474                     cppAddIncludeDir (dir);
475                   }
476
477                 *nextsep = PATH_SEPARATOR;
478                 incval = cstring_fromChars (nextsep + 1);
479                 cstring_free (dir);
480               }
481             else
482               {
483                 break;
484               }
485
486             /*@noaccess cstring@*/
487           }
488       }
489     else /* 2001-09-09: herbert */
490       {
491         /* Put C_INCLUDE_PATH directories in sysdirs */
492         cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
493
494         if (cstring_isDefined (cincval))
495           {
496             context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
497           }
498       }
499     /* /herbert */
500
501     cstring_free (oincval);
502   }
503
504   /*
505   ** check RCFILE for default flags
506   */
507
508   /*
509   ** Process command line message formatting flags before reading rc file
510   */
511
512   {
513     cstring home = osd_getHomeDir ();
514     cstring fname  = cstring_undefined;
515     bool defaultf = TRUE;
516     bool nof = FALSE;
517
518     for (i = 1; i < argc; i++)
519       {
520         char *thisarg;
521         thisarg = argv[i];
522         
523         if (*thisarg == '-' || *thisarg == '+')
524           {
525             bool set = (*thisarg == '+');
526             flagcode opt;
527
528             thisarg++;
529
530             /*
531             ** Don't report warnings this time
532             */
533
534             opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
535
536             if (opt == FLG_NOF)
537               {
538                 nof = TRUE;
539               }
540             else if (flagcode_isMessageControlFlag (opt))
541               {
542                 /*
543                 ** Need to set it immediately, so rc file scan is displayed
544                 */
545
546                 context_userSetFlag (opt, set);
547
548                 if (flagcode_hasArgument (opt))
549                   {
550                     llassert (flagcode_hasString (opt));
551                     
552                     if (++i < argc)
553                       {
554                         fname = cstring_fromChars (argv[i]);
555                         flags_setStringFlag (opt, fname);
556                       }
557                     else
558                       {
559                         voptgenerror
560                           (FLG_BADFLAG,
561                            message
562                            ("Flag %s must be followed by a string",
563                             flagcode_unparse (opt)),
564                            g_currentloc);
565                       }
566                   }
567               }
568             else if (opt == FLG_OPTF)
569               {
570                 if (++i < argc)
571                   {
572                     defaultf = FALSE;
573                     fname = cstring_fromChars (argv[i]);
574                     (void) rcfiles_read (fname, &passThroughArgs, TRUE);
575                   }
576                 else
577                   llfatalerror
578                     (cstring_makeLiteral ("Flag f to select options file "
579                                           "requires an argument"));
580               }
581             else
582               {
583                 ; /* wait to process later */
584               }
585           }
586       }
587         
588     setCodePoint ();
589
590     if (!nof && defaultf)
591       {
592         /*
593         ** No explicit rc file, first try reading ~/.splintrc
594         */
595
596         if (cstring_isUndefined (fname))
597           {
598             if (!cstring_isEmpty (home)) 
599               {
600                 bool readhomerc, readaltrc;
601                 cstring homename, altname;
602
603                 homename = message ("%s%h%s", home, CONNECTCHAR,
604                                  cstring_fromChars (RCFILE));
605                 readhomerc = rcfiles_read (homename, &passThroughArgs, FALSE);
606                 
607                 /*
608                 ** Try ~/.splintrc also for historical accuracy
609                 */
610                 
611                 altname = message ("%s%h%s", home, CONNECTCHAR,
612                                  cstring_fromChars (ALTRCFILE));
613                 readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
614
615                 if (readhomerc && readaltrc)
616                   {
617
618                     voptgenerror 
619                       (FLG_WARNRC,
620                        message ("Found both %s and %s files. Using both files, "
621                                 "but recommend using only %s to avoid confusion.",
622                                 homename, altname, homename),
623                        g_currentloc);
624                   }
625
626                 cstring_free (homename);
627                 cstring_free (altname);
628               }
629           }
630         
631         /*
632         ** Next, read .splintrc in the current working directory
633         */
634         
635         {
636           cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
637           cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
638           bool readrc, readaltrc;
639           
640           readrc = rcfiles_read (rcname, &passThroughArgs, FALSE);
641           readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
642           
643           if (readrc && readaltrc)
644             {
645               voptgenerror (FLG_WARNRC,
646                             message ("Found both %s and %s files. Using both files, "
647                                      "but recommend using only %s to avoid confusion.",
648                                      rcname, altname, rcname),
649                             g_currentloc);
650               
651             }
652
653           cstring_free (rcname);
654           cstring_free (altname);
655         }
656       }
657   }
658   
659   setCodePoint ();
660   llassert (fileloc_isBuiltin (g_currentloc));
661
662   cfiles = fileIdList_create ();
663   xfiles = fileIdList_create ();
664   lclfiles = fileIdList_create ();
665   mtfiles = fileIdList_create ();
666
667   /* argv[0] is the program name, don't pass it to flags_processFlags */
668   flags_processFlags (TRUE, xfiles, cfiles,
669                       lclfiles, mtfiles, 
670                       &passThroughArgs,
671                       argc - 1, argv + 1);
672
673   showHerald (); 
674
675   if (context_getFlag (FLG_CSV)) {
676     cstring fname = context_getString (FLG_CSV);
677
678     if (cstring_isDefined (fname)) {
679       if (osd_fileExists (fname) && !context_getFlag (FLG_CSVOVERWRITE)) {
680         lldiagmsg (message ("Specified CSV output file already exists (use +csvoverwrite to automatically overwrite): %s",
681                             fname));
682       } else {
683         g_csvstream = fopen (cstring_toCharsSafe (fname), "w");
684         
685         DPRINTF (("Creating: %s", fname));
686         if (g_csvstream == NULL) {
687           lldiagmsg (message ("Cannot open file for CSV output: %s", fname));
688         } else {
689           displayScan (message ("Starting CSV output file: %s", context_getString (FLG_CSV)));
690           fprintf (g_csvstream, 
691                    "Warning, Flag Code, Flag Name, Priority, File, Line, Column, Warning Text, Additional Text\n");
692         }
693       }
694     }
695   }
696
697 # ifdef DOANNOTS
698   initAnnots ();
699 # endif
700
701   inittime = clock ();
702
703   context_resetErrors ();
704   context_clearInCommandLine ();
705
706   anylcl = !fileIdList_isEmpty (lclfiles);
707
708   if (context_doMerge ())
709     {
710       cstring m = context_getMerge ();
711
712       displayScanOpen (message ("< loading %s ", m));
713       loadState (m);
714       displayScanClose ();
715
716       if (!usymtab_existsType (context_getBoolName ()))
717         {
718           usymtab_initBool (); 
719         }
720     }
721   else
722     {
723       if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
724         {
725           ;
726         }
727       else
728         {
729           ctype_initTable ();
730         }
731
732       /* setup bool type and constants */
733       usymtab_initBool (); 
734     }
735
736   fileloc_free (g_currentloc);
737   g_currentloc = fileloc_createBuiltin ();
738
739   /*
740   ** Read metastate files (must happen before loading libraries) 
741   */
742
743   fileIdList_elements (mtfiles, mtfile)
744     {
745       context_setFileId (mtfile);
746       displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
747       mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
748     } end_fileIdList_elements;
749
750   libtime = clock ();
751
752   if (anylcl)
753     {
754       lslProcess (lclfiles);
755     }
756
757   usymtab_initGlobalMarker ();
758
759   /*
760   ** pre-processing
761   **
762   ** call the pre-preprocessor and /lib/cpp to generate appropriate
763   ** files
764   **
765   */
766
767   context_setInCommandLine ();
768   
769   DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
770   
771   cstringList_elements (passThroughArgs, thisarg)
772     {
773       handlePassThroughFlag (cstring_toCharsSafe (thisarg));
774     } 
775   end_cstringList_elements;
776
777   cstringList_free (passThroughArgs);
778
779   cleanupMessages ();
780
781   DPRINTF (("Initializing cpp reader!"));
782   cppReader_initialize ();
783   cppReader_saveDefinitions ();
784   
785   context_clearInCommandLine ();
786
787   if (!context_getFlag (FLG_NOPP))
788     {
789       fileIdList tfiles;
790
791       llflush ();
792
793       displayScanOpen (cstring_makeLiteral ("preprocessing"));
794       
795       lcltime = clock ();
796
797       context_setPreprocessing ();
798       dercfiles = preprocessFiles (xfiles, TRUE);
799       tfiles = preprocessFiles (cfiles, FALSE);
800       warnSysFiles(cfiles);
801       dercfiles = fileIdList_append (dercfiles, tfiles);
802       fileIdList_free (tfiles);
803
804       context_clearPreprocessing ();
805
806       fileIdList_free (cfiles);
807
808       displayScanClose ();
809       pptime = clock ();
810     }
811   else
812     {
813       lcltime = clock ();
814       dercfiles = fileIdList_append (cfiles, xfiles);
815       pptime = clock ();
816     }
817
818   /*
819   ** now, check all the corresponding C files
820   **
821   ** (for now these are just <file>.c, but after pre-processing
822   **  will be <tmpprefix>.<file>.c)
823   */
824
825   {
826 # ifdef WIN32
827     int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
828
829     if (nfiles != 0) 
830       {
831         llbug (message ("Files unclosed: %d", nfiles));
832       }
833 # endif
834   }
835
836   DPRINTF (("Initializing..."));
837
838   exprNode_initMod ();
839
840   DPRINTF (("Okay..."));
841
842   fileIdList_elements (dercfiles, fid)
843     {
844       sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
845       context_setFileId (fid);
846       
847       /* Open source file  */
848       
849       if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
850         {
851           /* previously, this was ignored  ?! */
852           llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
853         }
854       else
855         {
856           yyin = inputStream_getFile (sourceFile); /*< shared <- only */
857         
858           llassert (yyin != NULL);
859
860           displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
861           
862           /*
863           ** Every time, except the first time, through the loop,
864           ** need to call yyrestart to clean up the parse buffer.
865           */
866
867           if (!first_time)
868             {
869               (void) yyrestart (yyin);  
870             }
871           else
872             {
873               first_time = FALSE;
874             }
875           
876           DPRINTF (("Entering..."));
877           context_enterFile ();
878           (void) yyparse ();
879           context_exitCFile ();
880                     
881           (void) inputStream_close (sourceFile);
882         }      
883
884       inputStream_free (sourceFile); /* evans 2002-07-12: why no warning without this?!! */
885     } end_fileIdList_elements;
886
887   fileIdList_free (dercfiles); /* evans 2002-07-12: why no warning without this?!! */
888   cptime = clock ();
889   
890   /* process any leftover macros */
891
892   context_processAllMacros ();
893   
894   /* check everything that was specified was defined */
895   
896   /* don't check if no c files were processed ?
897   **   is this correct behaviour?
898   */
899   
900   displayScan (cstring_makeLiteral ("global checks"));
901
902   cleanupMessages ();
903   
904   if (context_getLinesProcessed () > 0)
905     {
906       usymtab_allDefined ();
907     }
908
909   if (context_maybeSet (FLG_TOPUNUSED))
910     {
911       uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
912
913       if (uentry_isValid (ue))
914         {
915           uentry_setUsed (ue, fileloc_observeBuiltin ());
916         }
917
918       usymtab_allUsed ();
919     }
920
921   if (context_maybeSet (FLG_EXPORTLOCAL))
922     {
923       usymtab_exportLocal ();
924     }
925
926   
927   if (context_maybeSet (FLG_EXPORTHEADER))
928     {
929       usymtab_exportHeader ();
930     }
931
932   if (context_getFlag (FLG_SHOWUSES))
933     {
934       usymtab_displayAllUses ();
935     }
936
937   context_checkSuppressCounts ();
938
939   if (context_doDump ())
940     {
941       cstring dump = context_getDump ();
942
943       dumpState (dump);
944     }
945
946 # ifdef DOANNOTS
947   printAnnots ();
948 # endif
949
950   cleanupFiles ();
951   
952   if (g_csvstream != NULL) {
953     displayScan (message ("Closing CSV file: %s", context_getString (FLG_CSV)));
954     check (fclose (g_csvstream) == 0);
955   }
956   
957   if (context_getFlag (FLG_SHOWSUMMARY))
958     {
959       summarizeErrors (); 
960     }
961   
962   {
963     bool isQuiet = context_getFlag (FLG_QUIET);
964     cstring specErrors = cstring_undefined;
965     int nspecErrors = lclNumberErrors ();
966     
967     expsuccess = TRUE;
968
969     if (context_neednl ())
970       fprintf (g_warningstream, "\n");
971     
972     if (nspecErrors > 0)
973       {
974         if (nspecErrors == context_getLCLExpect ())
975           {
976             specErrors = 
977               message ("%d spec warning%&, as expected\n       ", 
978                        nspecErrors);
979           }
980         else
981           {
982             if (context_getLCLExpect () > 0)
983               {
984                 specErrors = 
985                   message ("%d spec warning%&, expected %d\n       ", 
986                            nspecErrors,
987                            (int) context_getLCLExpect ());
988               }
989             else
990               {
991                 specErrors = message ("%d spec warning%&\n       ",
992                                       nspecErrors);
993                 expsuccess = FALSE;
994               }
995           }
996       }
997     else
998         {
999           if (context_getLCLExpect () > 0)
1000             {
1001               specErrors = message ("No spec warnings, expected %d\n       ", 
1002                                     (int) context_getLCLExpect ());
1003               expsuccess = FALSE;
1004             }
1005         }
1006
1007       if (context_anyErrors ())
1008         {
1009           if (context_numErrors () == context_getExpect ())
1010             {
1011               if (!isQuiet) {
1012                 llmsg (message ("Finished checking --- "
1013                                 "%s%d code warning%&, as expected",
1014                                 specErrors, context_numErrors ()));
1015               }
1016             }
1017           else
1018             {
1019               if (context_getExpect () > 0)
1020                 {
1021                   if (!isQuiet) {
1022                     llmsg (message 
1023                            ("Finished checking --- "
1024                             "%s%d code warning%&, expected %d",
1025                             specErrors, context_numErrors (), 
1026                             (int) context_getExpect ()));
1027                   }
1028
1029                   expsuccess = FALSE;
1030                 }
1031               else
1032                 {
1033                   
1034                   if (!isQuiet)
1035                     {
1036                       llmsg (message ("Finished checking --- "
1037                                       "%s%d code warning%&", 
1038                                       specErrors, context_numErrors ()));
1039                     }
1040
1041                   expsuccess = FALSE;
1042                 }
1043             }
1044         }
1045       else
1046         {
1047           if (context_getExpect () > 0)
1048             {
1049               if (!isQuiet) {
1050                 llmsg (message
1051                        ("Finished checking --- "
1052                         "%sno code warnings, expected %d", 
1053                         specErrors,
1054                         (int) context_getExpect ()));
1055               }
1056
1057               expsuccess = FALSE;
1058             }
1059           else
1060             {
1061               if (context_getLinesProcessed () > 0)
1062                 {
1063                   if (cstring_isEmpty (specErrors))
1064                     {
1065                       if (!isQuiet) 
1066                         {
1067                           llmsg (message ("Finished checking --- no warnings"));
1068                         } 
1069                     }
1070                   else
1071                     {
1072                       if (!isQuiet) 
1073                         {
1074                           llmsg (message ("Finished checking --- %sno code warnings",
1075                                           specErrors));
1076                         }
1077                     }
1078                 }
1079               else
1080                 {
1081                   if (!isQuiet) {
1082                     llmsg (message ("Finished checking --- %sno code processed", 
1083                                     specErrors));
1084                   }
1085                 }
1086             }
1087         }
1088
1089       cstring_free (specErrors);
1090   }
1091   
1092   if (context_getFlag (FLG_STATS))
1093     {
1094       clock_t ttime = clock () - before;
1095       int specLines = context_getSpecLinesProcessed ();
1096       cstring specmsg = cstring_undefined;
1097
1098       rstime = clock ();
1099       
1100       if (specLines > 0)
1101         {
1102           specmsg = message ("%d spec, ", specLines);
1103         }
1104       
1105       /* The clock might wrap around, not platform-independent easy way to deal with this... */
1106       if (ttime > 0)
1107         {
1108 # ifndef CLOCKS_PER_SEC
1109           lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n", 
1110                               specmsg,
1111                               context_getLinesProcessed (), 
1112                               (int) ttime));
1113 # else
1114           lldiagmsg (message ("%s%d source lines in %f s.\n", 
1115                               specmsg,
1116                               context_getLinesProcessed (), 
1117                               (double) ttime / CLOCKS_PER_SEC));
1118           DPRINTF (("Time: %ld [%ld - %ld]", ttime, rstime, before));
1119 # endif
1120         }
1121       else
1122         {
1123           lldiagmsg (message ("%s%d source lines\n", 
1124                               specmsg,
1125                               context_getLinesProcessed ()));
1126         }
1127
1128     }
1129   else
1130     {
1131       rstime = clock ();
1132     }
1133   
1134   if (context_getFlag (FLG_TIMEDIST))
1135     {
1136       clock_t ttime = clock () - before;
1137       
1138       if (ttime > 0)
1139         {
1140           char *msg = (char *) dmalloc (256 * sizeof (*msg));
1141           
1142           if (anylcl)
1143             {
1144               /* Gack: really should figure out how to make configure find snprintf... */
1145 # ifdef WIN32
1146               (void) _snprintf (msg, 256,
1147 # else
1148               (void) snprintf (msg, 256,
1149 # endif
1150                         "Time distribution (percent): initialize %.2f / lcl %.2f / "
1151                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1152                         (100.0 * (double) (libtime - before) / ttime),
1153                         (100.0 * (double) (lcltime - libtime) / ttime),
1154                         (100.0 * (double) (pptime - lcltime) / ttime),
1155                         (100.0 * (double) (cptime - pptime) / ttime),
1156                         (100.0 * (double) (rstime - cptime) / ttime));
1157             }
1158           else
1159             {
1160 # ifdef WIN32
1161               (void) _snprintf (msg, 256,
1162 # else
1163               (void) snprintf (msg, 256,
1164 # endif
1165                         "Time distribution (percent): initialize %.2f / "
1166                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1167                         (100.0 * (double) (libtime - before) / ttime),
1168                         (100.0 * (double) (pptime - libtime) / ttime),
1169                         (100.0 * (double) (cptime - pptime) / ttime),
1170                         (100.0 * (double) (rstime - cptime) / ttime));
1171             }
1172           
1173           llgenindentmsgnoloc (cstring_fromCharsO (msg));
1174         }
1175     }
1176
1177   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1178   BADBRANCHRET (LLFAILURE);
1179 }
1180
1181 # ifdef WIN32
1182 /*
1183 ** Reenable return value warnings.
1184 */
1185 # pragma warning (default:4035)
1186 # endif 
1187
1188 void
1189 llinterrupt (int i)
1190 {
1191   switch (i)
1192     {
1193     case SIGINT:
1194       fprintf (g_errorstream, "*** Interrupt\n");
1195       llexit (LLINTERRUPT);
1196     case SIGSEGV:
1197       {
1198         cstring loc;
1199         
1200         /* Cheat when there are parse errors */
1201         checkParseError (); 
1202         
1203         fprintf (g_errorstream, "*** Segmentation Violation\n");
1204         
1205         /* Don't catch it if fileloc_unparse causes a signal */
1206         (void) signal (SIGSEGV, NULL);
1207
1208         loc = fileloc_unparse (g_currentloc);
1209         
1210         fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1211                  cstring_toCharsSafe (loc));
1212         cstring_free (loc);
1213         printCodePoint ();
1214         fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
1215         exit (LLGIVEUP);
1216       }
1217     default:
1218       fprintf (g_errorstream, "*** Signal: %d\n", i);
1219       /*@-mustfree@*/
1220       fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1221                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1222       /*@=mustfree@*/
1223       printCodePoint ();
1224       fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
1225       exit (LLGIVEUP);
1226     }
1227 }
1228
1229 void
1230 cleanupFiles (void)
1231 {
1232   static bool doneCleanup = FALSE;
1233
1234   /* make sure this is only called once! */
1235
1236   if (doneCleanup) return;
1237
1238   setCodePoint ();
1239
1240   /*
1241   ** Close all open files
1242   **    (There should only be open files, if we exited after a fatal error.)
1243   */
1244
1245   fileTable_closeAll (context_fileTable ());
1246
1247   if (context_getFlag (FLG_KEEP))
1248     {
1249       check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1250       fileTable_printTemps (context_fileTable ());
1251     }
1252   else
1253     {
1254 # ifdef WIN32
1255       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1256       
1257       if (nfiles != 0) 
1258         {
1259           llbug (message ("Files unclosed: %d", nfiles));
1260         }
1261 # endif
1262       fileTable_cleanup (context_fileTable ());
1263     }
1264
1265   doneCleanup = TRUE;
1266 }
1267
1268 /*
1269 ** cleans up temp files (if necessary) and exits
1270 */
1271
1272 /*@noreturn@*/ void
1273 llexit (int status)
1274 {
1275   DPRINTF (("llexit: %d", status));
1276
1277 # ifdef WIN32
1278   if (status == LLFAILURE) 
1279     {
1280       _fcloseall ();
1281     }
1282 # endif
1283
1284   cleanupFiles ();
1285
1286   if (status != LLFAILURE)
1287     {
1288       usymtab_destroyMod ();
1289
1290       /*drl I'm commenting this line out
1291                 because it is causing Splint to crash when built with
1292                         2.95 I'm not sure if this is a compiler bug or if if has to do with bool
1293                                 Any way if we're going to exist the program why do we bother freeing stuff...
1294       */
1295       /*      context_destroyMod (); */
1296       exprNode_destroyMod ();
1297       cppReader_destroyMod ();
1298       sRef_destroyMod ();
1299       uentry_destroyMod ();
1300       typeIdSet_destroyMod ();
1301       qual_destroyMod ();
1302       osd_destroyMod ();
1303       fileloc_destroyMod ();
1304 # ifdef USEDMALLOC
1305       dmalloc_shutdown ();
1306 # endif
1307     }
1308
1309   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1310 }
1311
1312 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
1313   /*@modifies fileSystem@*/
1314 {
1315   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1316   int skip = (fileIdList_size (fl) / 5);
1317   int filesprocessed = 0;
1318   fileIdList dfiles = fileIdList_create ();
1319
1320   fileloc_free (g_currentloc);
1321   g_currentloc = fileloc_createBuiltin ();
1322
1323   fileIdList_elements (fl, fid)
1324     {
1325       cstring ppfname = fileTable_fileName (fid);
1326
1327       if (!(osd_fileIsReadable (ppfname)))
1328         {
1329           lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
1330           ppfname = cstring_undefined;
1331         }
1332
1333       if (cstring_isDefined (ppfname))
1334         {
1335           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
1336
1337           if (xhfiles)
1338             {
1339               llassert (fileTable_isXHFile (context_fileTable (), dfile));
1340             }
1341
1342           llassert (cstring_isNonEmpty (ppfname));
1343           
1344           if (msg)
1345             {
1346               if ((filesprocessed % skip) == 0) 
1347                 {
1348                   if (filesprocessed == 0) {
1349                     displayScanContinue (cstring_makeLiteral (" "));
1350                   }
1351                   else {
1352                     displayScanContinue (cstring_makeLiteral ("."));
1353                   }
1354                 }
1355               filesprocessed++;
1356             }
1357
1358           DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1359
1360           if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) 
1361             {
1362               llfatalerror (message ("Preprocessing error for file: %s", 
1363                                      fileTable_rootFileName (fid)));
1364             }
1365           
1366           fileIdList_add (dfiles, dfile);
1367         }
1368     } end_fileIdList_elements; 
1369   
1370   return dfiles;
1371 }
1372
1373 /* This should be in an lclUtils.c file... */
1374 char *specFullName (char *specfile, /*@out@*/ char **inpath)
1375 {
1376   /* extract the path and the specname associated with the given file */
1377   char *specname = (char *) dmalloc (sizeof (*specname) 
1378                                      * (strlen (specfile) + 9));
1379   char *ospecname = specname;
1380   char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
1381   size_t size;
1382   long int i, j;
1383   
1384   /* initialized path to empty string or may have accidental garbage */
1385   *path = '\0';
1386
1387   /*@-mayaliasunique@*/ 
1388   strcpy (specname, specfile);
1389   /*@=mayaliasunique@*/ 
1390
1391   /* trim off pathnames in specfile */
1392   size = strlen (specname);
1393
1394   for (i = size_toInt (size) - 1; i >= 0; i--)
1395     {
1396       if (specname[i] == CONNECTCHAR)
1397         {
1398           /* strcpy (specname, (char *)specname+i+1); */
1399           for (j = 0; j <= i; j++)      /* include '/'  */
1400             {
1401               path[j] = specname[j];
1402             }
1403
1404           path[i + 1] = '\0';
1405           specname += i + 1;
1406           break;
1407         }
1408     }
1409
1410   /* 
1411   ** also remove .lcl file extension, assume it's the last extension
1412   ** of the file name 
1413   */
1414
1415   size = strlen (specname);
1416
1417   for (i = size_toInt (size) - 1; i >= 0; i--)
1418     {
1419       if (specname[i] == '.')
1420         {
1421           specname[i] = '\0';
1422           break;
1423         }
1424     }
1425   
1426   *inpath = path;
1427
1428   /*
1429   ** If specname no longer points to the original char,
1430   ** we need to allocate a new pointer and copy the string.
1431   */
1432
1433   if (specname != ospecname) {
1434     char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
1435     strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
1436     sfree (ospecname);
1437     return rspecname;
1438   } 
1439
1440   return specname;
1441 }
1442
1443 void warnSysFiles(fileIdList files)
1444 {
1445   fileIdList_elements (files, file)
1446     {
1447       
1448       if (fileTable_isSystemFile (context_fileTable (), file) )
1449         {
1450           if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1451             {
1452               voptgenerror (FLG_WARNSYSFILES, message ("Warning %s is a considered a system file. No errors in this file will be reported.", fileTable_rootFileName (file) ), g_currentloc);
1453             }
1454         }
1455     } 
1456   end_fileIdList_elements;
1457 }
This page took 0.156261 seconds and 5 git commands to generate.