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