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