]> andersk Git - splint.git/blob - src/llmain.c
Added code to support CSV output (-csv flag).
[splint.git] / src / llmain.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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 "llbasic.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                         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               (void) snprintf (msg, 256,
1147                         "Time distribution (percent): initialize %.2f / lcl %.2f / "
1148                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1149                         (100.0 * (double) (libtime - before) / ttime),
1150                         (100.0 * (double) (lcltime - libtime) / ttime),
1151                         (100.0 * (double) (pptime - lcltime) / ttime),
1152                         (100.0 * (double) (cptime - pptime) / ttime),
1153                         (100.0 * (double) (rstime - cptime) / ttime));
1154             }
1155           else
1156             {
1157               (void) snprintf (msg, 256,
1158                         "Time distribution (percent): initialize %.2f / "
1159                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1160                         (100.0 * (double) (libtime - before) / ttime),
1161                         (100.0 * (double) (pptime - libtime) / ttime),
1162                         (100.0 * (double) (cptime - pptime) / ttime),
1163                         (100.0 * (double) (rstime - cptime) / ttime));
1164             }
1165           
1166           llgenindentmsgnoloc (cstring_fromCharsO (msg));
1167         }
1168     }
1169
1170   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1171   BADBRANCHRET (LLFAILURE);
1172 }
1173
1174 # ifdef WIN32
1175 /*
1176 ** Reenable return value warnings.
1177 */
1178 # pragma warning (default:4035)
1179 # endif 
1180
1181 void
1182 llinterrupt (int i)
1183 {
1184   switch (i)
1185     {
1186     case SIGINT:
1187       fprintf (g_errorstream, "*** Interrupt\n");
1188       llexit (LLINTERRUPT);
1189     case SIGSEGV:
1190       {
1191         cstring loc;
1192         
1193         /* Cheat when there are parse errors */
1194         checkParseError (); 
1195         
1196         fprintf (g_errorstream, "*** Segmentation Violation\n");
1197         
1198         /* Don't catch it if fileloc_unparse causes a signal */
1199         (void) signal (SIGSEGV, NULL);
1200
1201         loc = fileloc_unparse (g_currentloc);
1202         
1203         fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1204                  cstring_toCharsSafe (loc));
1205         cstring_free (loc);
1206         printCodePoint ();
1207         fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
1208         exit (LLGIVEUP);
1209       }
1210     default:
1211       fprintf (g_errorstream, "*** Signal: %d\n", i);
1212       /*@-mustfree@*/
1213       fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1214                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1215       /*@=mustfree@*/
1216       printCodePoint ();
1217       fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
1218       exit (LLGIVEUP);
1219     }
1220 }
1221
1222 void
1223 cleanupFiles (void)
1224 {
1225   static bool doneCleanup = FALSE;
1226
1227   /* make sure this is only called once! */
1228
1229   if (doneCleanup) return;
1230
1231   setCodePoint ();
1232
1233   /*
1234   ** Close all open files
1235   **    (There should only be open files, if we exited after a fatal error.)
1236   */
1237
1238   fileTable_closeAll (context_fileTable ());
1239
1240   if (context_getFlag (FLG_KEEP))
1241     {
1242       check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1243       fileTable_printTemps (context_fileTable ());
1244     }
1245   else
1246     {
1247 # ifdef WIN32
1248       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1249       
1250       if (nfiles != 0) 
1251         {
1252           llbug (message ("Files unclosed: %d", nfiles));
1253         }
1254 # endif
1255       fileTable_cleanup (context_fileTable ());
1256     }
1257
1258   doneCleanup = TRUE;
1259 }
1260
1261 /*
1262 ** cleans up temp files (if necessary) and exits
1263 */
1264
1265 /*@noreturn@*/ void
1266 llexit (int status)
1267 {
1268   DPRINTF (("llexit: %d", status));
1269
1270 # ifdef WIN32
1271   if (status == LLFAILURE) 
1272     {
1273       _fcloseall ();
1274     }
1275 # endif
1276
1277   cleanupFiles ();
1278
1279   if (status != LLFAILURE)
1280     {
1281       usymtab_destroyMod ();
1282       context_destroyMod ();
1283       exprNode_destroyMod ();
1284       cppReader_destroyMod ();
1285       sRef_destroyMod ();
1286       uentry_destroyMod ();
1287       typeIdSet_destroyMod ();
1288       qual_destroyMod ();
1289       osd_destroyMod ();
1290       fileloc_destroyMod ();
1291 # ifdef USEDMALLOC
1292       dmalloc_shutdown ();
1293 # endif
1294     }
1295
1296   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1297 }
1298
1299 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
1300   /*@modifies fileSystem@*/
1301 {
1302   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1303   int skip = (fileIdList_size (fl) / 5);
1304   int filesprocessed = 0;
1305   fileIdList dfiles = fileIdList_create ();
1306
1307   fileloc_free (g_currentloc);
1308   g_currentloc = fileloc_createBuiltin ();
1309
1310   fileIdList_elements (fl, fid)
1311     {
1312       cstring ppfname = fileTable_fileName (fid);
1313
1314       if (!(osd_fileIsReadable (ppfname)))
1315         {
1316           lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
1317           ppfname = cstring_undefined;
1318         }
1319
1320       if (cstring_isDefined (ppfname))
1321         {
1322           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
1323
1324           if (xhfiles)
1325             {
1326               llassert (fileTable_isXHFile (context_fileTable (), dfile));
1327             }
1328
1329           llassert (cstring_isNonEmpty (ppfname));
1330           
1331           if (msg)
1332             {
1333               if ((filesprocessed % skip) == 0) 
1334                 {
1335                   if (filesprocessed == 0) {
1336                     displayScanContinue (cstring_makeLiteral (" "));
1337                   }
1338                   else {
1339                     displayScanContinue (cstring_makeLiteral ("."));
1340                   }
1341                 }
1342               filesprocessed++;
1343             }
1344
1345           DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1346
1347           if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) 
1348             {
1349               llfatalerror (message ("Preprocessing error for file: %s", 
1350                                      fileTable_rootFileName (fid)));
1351             }
1352           
1353           fileIdList_add (dfiles, dfile);
1354         }
1355     } end_fileIdList_elements; 
1356   
1357   return dfiles;
1358 }
1359
1360 /* This should be in an lclUtils.c file... */
1361 char *specFullName (char *specfile, /*@out@*/ char **inpath)
1362 {
1363   /* extract the path and the specname associated with the given file */
1364   char *specname = (char *) dmalloc (sizeof (*specname) 
1365                                      * (strlen (specfile) + 9));
1366   char *ospecname = specname;
1367   char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
1368   size_t size;
1369   long int i, j;
1370   
1371   /* initialized path to empty string or may have accidental garbage */
1372   *path = '\0';
1373
1374   /*@-mayaliasunique@*/ 
1375   strcpy (specname, specfile);
1376   /*@=mayaliasunique@*/ 
1377
1378   /* trim off pathnames in specfile */
1379   size = strlen (specname);
1380
1381   for (i = size_toInt (size) - 1; i >= 0; i--)
1382     {
1383       if (specname[i] == CONNECTCHAR)
1384         {
1385           /* strcpy (specname, (char *)specname+i+1); */
1386           for (j = 0; j <= i; j++)      /* include '/'  */
1387             {
1388               path[j] = specname[j];
1389             }
1390
1391           path[i + 1] = '\0';
1392           specname += i + 1;
1393           break;
1394         }
1395     }
1396
1397   /* 
1398   ** also remove .lcl file extension, assume it's the last extension
1399   ** of the file name 
1400   */
1401
1402   size = strlen (specname);
1403
1404   for (i = size_toInt (size) - 1; i >= 0; i--)
1405     {
1406       if (specname[i] == '.')
1407         {
1408           specname[i] = '\0';
1409           break;
1410         }
1411     }
1412   
1413   *inpath = path;
1414
1415   /*
1416   ** If specname no longer points to the original char,
1417   ** we need to allocate a new pointer and copy the string.
1418   */
1419
1420   if (specname != ospecname) {
1421     char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
1422     strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
1423     sfree (ospecname);
1424     return rspecname;
1425   } 
1426
1427   return specname;
1428 }
1429
1430 void warnSysFiles(fileIdList files)
1431 {
1432   fileIdList_elements (files, file)
1433     {
1434       
1435       if (fileTable_isSystemFile (context_fileTable (), file) )
1436         {
1437           if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1438             {
1439               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);
1440             }
1441         }
1442     } 
1443   end_fileIdList_elements;
1444 }
This page took 0.55529 seconds and 5 git commands to generate.