]> andersk Git - splint.git/blob - src/llmain.c
Fixed problem with assertion checking for negative shifts in
[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   /* Why was this here?  It is always a bug... */
826 # if 0
827   {
828 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
829     int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
830
831     if (nfiles != 0) 
832       {
833         llbug (message ("Files unclosed: %d", nfiles));
834       }
835 # endif
836   }
837 # endif
838
839   DPRINTF (("Initializing..."));
840
841   exprNode_initMod ();
842
843   DPRINTF (("Okay..."));
844
845   fileIdList_elements (dercfiles, fid)
846     {
847       sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
848       context_setFileId (fid);
849       
850       /* Open source file  */
851       
852       if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
853         {
854           /* previously, this was ignored  ?! */
855           llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
856         }
857       else
858         {
859           yyin = inputStream_getFile (sourceFile); /*< shared <- only */
860         
861           llassert (yyin != NULL);
862
863           displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
864           
865           /*
866           ** Every time, except the first time, through the loop,
867           ** need to call yyrestart to clean up the parse buffer.
868           */
869
870           if (!first_time)
871             {
872               (void) yyrestart (yyin);  
873             }
874           else
875             {
876               first_time = FALSE;
877             }
878           
879           DPRINTF (("Entering..."));
880           context_enterFile ();
881           (void) yyparse ();
882           context_exitCFile ();
883                     
884           (void) inputStream_close (sourceFile);
885         }      
886
887       inputStream_free (sourceFile); /* evans 2002-07-12: why no warning without this?!! */
888     } end_fileIdList_elements;
889
890   fileIdList_free (dercfiles); /* evans 2002-07-12: why no warning without this?!! */
891   cptime = clock ();
892   
893   /* process any leftover macros */
894
895   context_processAllMacros ();
896   
897   /* check everything that was specified was defined */
898   
899   /* don't check if no c files were processed ?
900   **   is this correct behaviour?
901   */
902   
903   displayScan (cstring_makeLiteral ("global checks"));
904
905   cleanupMessages ();
906   
907   if (context_getLinesProcessed () > 0)
908     {
909       usymtab_allDefined ();
910     }
911
912   if (context_maybeSet (FLG_TOPUNUSED))
913     {
914       uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
915
916       if (uentry_isValid (ue))
917         {
918           uentry_setUsed (ue, fileloc_observeBuiltin ());
919         }
920
921       usymtab_allUsed ();
922     }
923
924   if (context_maybeSet (FLG_EXPORTLOCAL))
925     {
926       usymtab_exportLocal ();
927     }
928
929   
930   if (context_maybeSet (FLG_EXPORTHEADER))
931     {
932       usymtab_exportHeader ();
933     }
934
935   if (context_getFlag (FLG_SHOWUSES))
936     {
937       usymtab_displayAllUses ();
938     }
939
940   context_checkSuppressCounts ();
941
942   if (context_doDump ())
943     {
944       cstring dump = context_getDump ();
945
946       dumpState (dump);
947     }
948
949 # ifdef DOANNOTS
950   printAnnots ();
951 # endif
952
953   cleanupFiles ();
954   
955   if (g_csvstream != NULL) {
956     displayScan (message ("Closing CSV file: %s", context_getString (FLG_CSV)));
957     check (fclose (g_csvstream) == 0);
958   }
959   
960   if (context_getFlag (FLG_SHOWSUMMARY))
961     {
962       summarizeErrors (); 
963     }
964   
965   {
966     bool isQuiet = context_getFlag (FLG_QUIET);
967     cstring specErrors = cstring_undefined;
968     int nspecErrors = lclNumberErrors ();
969     
970     expsuccess = TRUE;
971
972     if (context_neednl ())
973       fprintf (g_warningstream, "\n");
974     
975     if (nspecErrors > 0)
976       {
977         if (nspecErrors == context_getLCLExpect ())
978           {
979             specErrors = 
980               message ("%d spec warning%&, as expected\n       ", 
981                        nspecErrors);
982           }
983         else
984           {
985             if (context_getLCLExpect () > 0)
986               {
987                 specErrors = 
988                   message ("%d spec warning%&, expected %d\n       ", 
989                            nspecErrors,
990                            (int) context_getLCLExpect ());
991               }
992             else
993               {
994                 specErrors = message ("%d spec warning%&\n       ",
995                                       nspecErrors);
996                 expsuccess = FALSE;
997               }
998           }
999       }
1000     else
1001         {
1002           if (context_getLCLExpect () > 0)
1003             {
1004               specErrors = message ("No spec warnings, expected %d\n       ", 
1005                                     (int) context_getLCLExpect ());
1006               expsuccess = FALSE;
1007             }
1008         }
1009
1010       if (context_anyErrors ())
1011         {
1012           if (context_numErrors () == context_getExpect ())
1013             {
1014               if (!isQuiet) {
1015                 llmsg (message ("Finished checking --- "
1016                                 "%s%d code warning%&, as expected",
1017                                 specErrors, context_numErrors ()));
1018               }
1019             }
1020           else
1021             {
1022               if (context_getExpect () > 0)
1023                 {
1024                   if (!isQuiet) {
1025                     llmsg (message 
1026                            ("Finished checking --- "
1027                             "%s%d code warning%&, expected %d",
1028                             specErrors, context_numErrors (), 
1029                             (int) context_getExpect ()));
1030                   }
1031
1032                   expsuccess = FALSE;
1033                 }
1034               else
1035                 {
1036                   
1037                   if (!isQuiet)
1038                     {
1039                       llmsg (message ("Finished checking --- "
1040                                       "%s%d code warning%&", 
1041                                       specErrors, context_numErrors ()));
1042                     }
1043
1044                   expsuccess = FALSE;
1045                 }
1046             }
1047         }
1048       else
1049         {
1050           if (context_getExpect () > 0)
1051             {
1052               if (!isQuiet) {
1053                 llmsg (message
1054                        ("Finished checking --- "
1055                         "%sno code warnings, expected %d", 
1056                         specErrors,
1057                         (int) context_getExpect ()));
1058               }
1059
1060               expsuccess = FALSE;
1061             }
1062           else
1063             {
1064               if (context_getLinesProcessed () > 0)
1065                 {
1066                   if (cstring_isEmpty (specErrors))
1067                     {
1068                       if (!isQuiet) 
1069                         {
1070                           llmsg (message ("Finished checking --- no warnings"));
1071                         } 
1072                     }
1073                   else
1074                     {
1075                       if (!isQuiet) 
1076                         {
1077                           llmsg (message ("Finished checking --- %sno code warnings",
1078                                           specErrors));
1079                         }
1080                     }
1081                 }
1082               else
1083                 {
1084                   if (!isQuiet) {
1085                     llmsg (message ("Finished checking --- %sno code processed", 
1086                                     specErrors));
1087                   }
1088                 }
1089             }
1090         }
1091
1092       cstring_free (specErrors);
1093   
1094       if (context_numBugs () > 0) {
1095         expsuccess = FALSE;
1096         if (!isQuiet) {
1097           llmsg (message ("   %d internal bugs reported", context_numBugs ()));
1098         }
1099       }
1100   }
1101   
1102   if (context_getFlag (FLG_STATS))
1103     {
1104       clock_t ttime = clock () - before;
1105       int specLines = context_getSpecLinesProcessed ();
1106       cstring specmsg = cstring_undefined;
1107       
1108       rstime = clock ();
1109       
1110       if (specLines > 0)
1111         {
1112           specmsg = message ("%d spec, ", specLines);
1113         }
1114       
1115       /* The clock might wrap around, not platform-independent easy way to deal with this... */
1116       if (ttime > 0)
1117         {
1118 # ifndef CLOCKS_PER_SEC
1119           lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n", 
1120                               specmsg,
1121                               context_getLinesProcessed (), 
1122                               (int) ttime));
1123 # else
1124           lldiagmsg (message ("%s%d source lines in %f s.\n", 
1125                               specmsg,
1126                               context_getLinesProcessed (), 
1127                               (double) ttime / CLOCKS_PER_SEC));
1128           DPRINTF (("Time: %ld [%ld - %ld]", ttime, rstime, before));
1129 # endif
1130         }
1131       else
1132         {
1133           lldiagmsg (message ("%s%d source lines\n", 
1134                               specmsg,
1135                               context_getLinesProcessed ()));
1136         }
1137
1138     }
1139   else
1140     {
1141       rstime = clock ();
1142     }
1143   
1144   if (context_getFlag (FLG_TIMEDIST))
1145     {
1146       clock_t ttime = clock () - before;
1147       
1148       if (ttime > 0)
1149         {
1150           char *msg = (char *) dmalloc (256 * sizeof (*msg));
1151           
1152           if (anylcl)
1153             {
1154               /* Gack: really should figure out how to make configure find snprintf... */
1155 # ifdef WIN32
1156               (void) _snprintf (msg, 256,
1157 # else
1158               (void) snprintf (msg, 256,
1159 # endif
1160                         "Time distribution (percent): initialize %.2f / lcl %.2f / "
1161                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1162                         (100.0 * (double) (libtime - before) / ttime),
1163                         (100.0 * (double) (lcltime - libtime) / ttime),
1164                         (100.0 * (double) (pptime - lcltime) / ttime),
1165                         (100.0 * (double) (cptime - pptime) / ttime),
1166                         (100.0 * (double) (rstime - cptime) / ttime));
1167             }
1168           else
1169             {
1170 # ifdef WIN32
1171               (void) _snprintf (msg, 256,
1172 # else
1173               (void) snprintf (msg, 256,
1174 # endif
1175                         "Time distribution (percent): initialize %.2f / "
1176                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1177                         (100.0 * (double) (libtime - before) / ttime),
1178                         (100.0 * (double) (pptime - libtime) / ttime),
1179                         (100.0 * (double) (cptime - pptime) / ttime),
1180                         (100.0 * (double) (rstime - cptime) / ttime));
1181             }
1182           
1183           llgenindentmsgnoloc (cstring_fromCharsO (msg));
1184         }
1185     }
1186
1187   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1188   BADBRANCHRET (LLFAILURE);
1189 }
1190
1191 # ifdef WIN32
1192 /*
1193 ** Reenable return value warnings.
1194 */
1195 # pragma warning (default:4035)
1196 # endif 
1197
1198 void
1199 llinterrupt (int i)
1200 {
1201   switch (i)
1202     {
1203     case SIGINT:
1204       fprintf (g_errorstream, "*** Interrupt\n");
1205       llexit (LLINTERRUPT);
1206     case SIGSEGV:
1207       {
1208         cstring loc;
1209         
1210         /* Cheat when there are parse errors */
1211         checkParseError (); 
1212         
1213         fprintf (g_errorstream, "*** Segmentation Violation\n");
1214         
1215         /* Don't catch it if fileloc_unparse causes a signal */
1216         (void) signal (SIGSEGV, NULL);
1217
1218         loc = fileloc_unparse (g_currentloc);
1219         
1220         fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1221                  cstring_toCharsSafe (loc));
1222         cstring_free (loc);
1223         printCodePoint ();
1224         fprintf (g_errorstream, "*** Please report bug to %s\n*** A useful bug report should include everything we need to reproduce the bug.\n", SPLINT_MAINTAINER);
1225         exit (LLGIVEUP);
1226       }
1227     default:
1228       fprintf (g_errorstream, "*** Signal: %d\n", i);
1229       /*@-mustfree@*/
1230       fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1231                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1232       /*@=mustfree@*/
1233       printCodePoint ();
1234       fprintf (g_errorstream, "*** Please report bug to %s\n*** A useful bug report should include everything we need to reproduce the bug.", SPLINT_MAINTAINER);
1235       exit (LLGIVEUP);
1236     }
1237 }
1238
1239 void
1240 cleanupFiles (void)
1241 {
1242   static bool doneCleanup = FALSE;
1243
1244   /* make sure this is only called once! */
1245
1246   if (doneCleanup) return;
1247
1248   setCodePoint ();
1249
1250   /*
1251   ** Close all open files
1252   **    (There should only be open files, if we exited after a fatal error.)
1253   */
1254
1255   fileTable_closeAll (context_fileTable ());
1256
1257   if (context_getFlag (FLG_KEEP))
1258     {
1259       check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1260       fileTable_printTemps (context_fileTable ());
1261     }
1262   else
1263     {
1264 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
1265       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1266       
1267       if (nfiles != 0) 
1268         {
1269           llbug (message ("Files unclosed: %d", nfiles));
1270         }
1271 # endif
1272       fileTable_cleanup (context_fileTable ());
1273     }
1274
1275   doneCleanup = TRUE;
1276 }
1277
1278 /*
1279 ** cleans up temp files (if necessary) and exits
1280 */
1281
1282 /*@noreturn@*/ void
1283 llexit (int status)
1284 {
1285   DPRINTF (("llexit: %d", status));
1286
1287 # if defined (WIN32) || defined (OS2) && defined (__IBMC__)
1288   if (status == LLFAILURE) 
1289     {
1290       _fcloseall ();
1291     }
1292 # endif
1293
1294   cleanupFiles ();
1295
1296   if (status != LLFAILURE)
1297     {
1298       usymtab_destroyMod ();
1299
1300       /*drl I'm commenting this line out
1301                 because it is causing Splint to crash when built with
1302                         2.95 I'm not sure if this is a compiler bug or if if has to do with bool
1303                                 Any way if we're going to exist the program why do we bother freeing stuff...
1304       */
1305       /*      context_destroyMod (); */
1306       exprNode_destroyMod ();
1307       cppReader_destroyMod ();
1308       sRef_destroyMod ();
1309       uentry_destroyMod ();
1310       typeIdSet_destroyMod ();
1311       qual_destroyMod ();
1312       osd_destroyMod ();
1313       fileloc_destroyMod ();
1314 # ifdef USEDMALLOC
1315       dmalloc_shutdown ();
1316 # endif
1317     }
1318
1319   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1320 }
1321
1322 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
1323   /*@modifies fileSystem@*/
1324 {
1325   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1326   int skip = (fileIdList_size (fl) / 5);
1327   int filesprocessed = 0;
1328   fileIdList dfiles = fileIdList_create ();
1329
1330   fileloc_free (g_currentloc);
1331   g_currentloc = fileloc_createBuiltin ();
1332
1333   fileIdList_elements (fl, fid)
1334     {
1335       cstring ppfname = fileTable_fileName (fid);
1336
1337       if (!(osd_fileIsReadable (ppfname)))
1338         {
1339           lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
1340           ppfname = cstring_undefined;
1341         }
1342
1343       if (cstring_isDefined (ppfname))
1344         {
1345           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
1346
1347           if (xhfiles)
1348             {
1349               llassert (fileTable_isXHFile (context_fileTable (), dfile));
1350             }
1351
1352           llassert (cstring_isNonEmpty (ppfname));
1353           
1354           if (msg)
1355             {
1356               if ((filesprocessed % skip) == 0) 
1357                 {
1358                   if (filesprocessed == 0) {
1359                     displayScanContinue (cstring_makeLiteral (" "));
1360                   }
1361                   else {
1362                     displayScanContinue (cstring_makeLiteral ("."));
1363                   }
1364                 }
1365               filesprocessed++;
1366             }
1367
1368           DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1369
1370           if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) 
1371             {
1372               llfatalerror (message ("Preprocessing error for file: %s", 
1373                                      fileTable_rootFileName (fid)));
1374             }
1375           
1376           fileIdList_add (dfiles, dfile);
1377         }
1378     } end_fileIdList_elements; 
1379   
1380   return dfiles;
1381 }
1382
1383 /* This should be in an lclUtils.c file... */
1384 char *specFullName (char *specfile, /*@out@*/ char **inpath)
1385 {
1386   /* extract the path and the specname associated with the given file */
1387   char *specname = (char *) dmalloc (sizeof (*specname) 
1388                                      * (strlen (specfile) + 9));
1389   char *ospecname = specname;
1390   char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
1391   size_t size;
1392   long int i, j;
1393   
1394   /* initialized path to empty string or may have accidental garbage */
1395   *path = '\0';
1396
1397   /*@-mayaliasunique@*/ 
1398   strcpy (specname, specfile);
1399   /*@=mayaliasunique@*/ 
1400
1401   /* trim off pathnames in specfile */
1402   size = strlen (specname);
1403
1404   for (i = size_toInt (size) - 1; i >= 0; i--)
1405     {
1406       if (specname[i] == CONNECTCHAR)
1407         {
1408           /* strcpy (specname, (char *)specname+i+1); */
1409           for (j = 0; j <= i; j++)      /* include '/'  */
1410             {
1411               path[j] = specname[j];
1412             }
1413
1414           path[i + 1] = '\0';
1415           specname += i + 1;
1416           break;
1417         }
1418     }
1419
1420   /* 
1421   ** also remove .lcl file extension, assume it's the last extension
1422   ** of the file name 
1423   */
1424
1425   size = strlen (specname);
1426
1427   for (i = size_toInt (size) - 1; i >= 0; i--)
1428     {
1429       if (specname[i] == '.')
1430         {
1431           specname[i] = '\0';
1432           break;
1433         }
1434     }
1435   
1436   *inpath = path;
1437
1438   /*
1439   ** If specname no longer points to the original char,
1440   ** we need to allocate a new pointer and copy the string.
1441   */
1442
1443   if (specname != ospecname) {
1444     char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
1445     strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
1446     sfree (ospecname);
1447     return rspecname;
1448   } 
1449
1450   return specname;
1451 }
1452
1453 void warnSysFiles(fileIdList files)
1454 {
1455   fileIdList_elements (files, file)
1456     {
1457       
1458       if (fileTable_isSystemFile (context_fileTable (), file) )
1459         {
1460           if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1461             {
1462               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);
1463             }
1464         }
1465     } 
1466   end_fileIdList_elements;
1467 }
This page took 0.234677 seconds and 5 git commands to generate.