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