]> andersk Git - splint.git/blob - src/llmain.c
Remove empty configure file. This should not be in CVS.
[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 # ifdef DOANNOTS
678   initAnnots ();
679 # endif
680
681   inittime = clock ();
682
683   context_resetErrors ();
684   context_clearInCommandLine ();
685
686   anylcl = !fileIdList_isEmpty (lclfiles);
687
688   if (context_doMerge ())
689     {
690       cstring m = context_getMerge ();
691
692       displayScanOpen (message ("< loading %s ", m));
693       loadState (m);
694       displayScanClose ();
695
696       if (!usymtab_existsType (context_getBoolName ()))
697         {
698           usymtab_initBool (); 
699         }
700     }
701   else
702     {
703       if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
704         {
705           ;
706         }
707       else
708         {
709           ctype_initTable ();
710         }
711
712       /* setup bool type and constants */
713       usymtab_initBool (); 
714     }
715
716   fileloc_free (g_currentloc);
717   g_currentloc = fileloc_createBuiltin ();
718
719   /*
720   ** Read metastate files (must happen before loading libraries) 
721   */
722
723   fileIdList_elements (mtfiles, mtfile)
724     {
725       context_setFileId (mtfile);
726       displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
727       mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
728     } end_fileIdList_elements;
729
730   libtime = clock ();
731
732   if (anylcl)
733     {
734       lslProcess (lclfiles);
735     }
736
737   usymtab_initGlobalMarker ();
738
739   /*
740   ** pre-processing
741   **
742   ** call the pre-preprocessor and /lib/cpp to generate appropriate
743   ** files
744   **
745   */
746
747   context_setInCommandLine ();
748   
749   DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
750   
751   cstringList_elements (passThroughArgs, thisarg)
752     {
753       handlePassThroughFlag (cstring_toCharsSafe (thisarg));
754     } 
755   end_cstringList_elements;
756
757   cstringList_free (passThroughArgs);
758
759   cleanupMessages ();
760
761   DPRINTF (("Initializing cpp reader!"));
762   cppReader_initialize ();
763   cppReader_saveDefinitions ();
764   
765   context_clearInCommandLine ();
766
767   if (!context_getFlag (FLG_NOPP))
768     {
769       fileIdList tfiles;
770
771       llflush ();
772
773       displayScanOpen (cstring_makeLiteral ("preprocessing"));
774       
775       lcltime = clock ();
776
777       context_setPreprocessing ();
778       dercfiles = preprocessFiles (xfiles, TRUE);
779       tfiles = preprocessFiles (cfiles, FALSE);
780       warnSysFiles(cfiles);
781       dercfiles = fileIdList_append (dercfiles, tfiles);
782       fileIdList_free (tfiles);
783
784       context_clearPreprocessing ();
785
786       fileIdList_free (cfiles);
787
788       displayScanClose ();
789       pptime = clock ();
790     }
791   else
792     {
793       lcltime = clock ();
794       dercfiles = fileIdList_append (cfiles, xfiles);
795       pptime = clock ();
796     }
797
798   /*
799   ** now, check all the corresponding C files
800   **
801   ** (for now these are just <file>.c, but after pre-processing
802   **  will be <tmpprefix>.<file>.c)
803   */
804
805   {
806 # ifdef WIN32
807     int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
808
809     if (nfiles != 0) 
810       {
811         llbug (message ("Files unclosed: %d", nfiles));
812       }
813 # endif
814   }
815
816   DPRINTF (("Initializing..."));
817
818   exprNode_initMod ();
819
820   DPRINTF (("Okay..."));
821
822   fileIdList_elements (dercfiles, fid)
823     {
824       sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
825       context_setFileId (fid);
826       
827       /* Open source file  */
828       
829       if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
830         {
831           /* previously, this was ignored  ?! */
832           llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
833         }
834       else
835         {
836           yyin = inputStream_getFile (sourceFile); /*< shared <- only */
837         
838           llassert (yyin != NULL);
839
840           displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
841           
842           /*
843           ** Every time, except the first time, through the loop,
844           ** need to call yyrestart to clean up the parse buffer.
845           */
846
847           if (!first_time)
848             {
849               (void) yyrestart (yyin);  
850             }
851           else
852             {
853               first_time = FALSE;
854             }
855           
856           DPRINTF (("Entering..."));
857           context_enterFile ();
858           (void) yyparse ();
859           context_exitCFile ();
860                     
861           (void) inputStream_close (sourceFile);
862         }      
863
864       inputStream_free (sourceFile); /* evans 2002-07-12: why no warning without this?!! */
865     } end_fileIdList_elements;
866
867   fileIdList_free (dercfiles); /* evans 2002-07-12: why no warning without this?!! */
868   cptime = clock ();
869   
870   /* process any leftover macros */
871
872   context_processAllMacros ();
873   
874   /* check everything that was specified was defined */
875   
876   /* don't check if no c files were processed ?
877   **   is this correct behaviour?
878   */
879   
880   displayScan (cstring_makeLiteral ("global checks"));
881
882   cleanupMessages ();
883   
884   if (context_getLinesProcessed () > 0)
885     {
886       usymtab_allDefined ();
887     }
888
889   if (context_maybeSet (FLG_TOPUNUSED))
890     {
891       uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
892
893       if (uentry_isValid (ue))
894         {
895           uentry_setUsed (ue, fileloc_observeBuiltin ());
896         }
897
898       usymtab_allUsed ();
899     }
900
901   if (context_maybeSet (FLG_EXPORTLOCAL))
902     {
903       usymtab_exportLocal ();
904     }
905
906   
907   if (context_maybeSet (FLG_EXPORTHEADER))
908     {
909       usymtab_exportHeader ();
910     }
911
912   if (context_getFlag (FLG_SHOWUSES))
913     {
914       usymtab_displayAllUses ();
915     }
916
917   context_checkSuppressCounts ();
918
919   if (context_doDump ())
920     {
921       cstring dump = context_getDump ();
922
923       dumpState (dump);
924     }
925
926 # ifdef DOANNOTS
927   printAnnots ();
928 # endif
929
930   cleanupFiles ();
931
932   if (context_getFlag (FLG_SHOWSUMMARY))
933     {
934       summarizeErrors (); 
935     }
936
937   
938   {
939     bool isQuiet = context_getFlag (FLG_QUIET);
940     cstring specErrors = cstring_undefined;
941     int nspecErrors = lclNumberErrors ();
942     
943     expsuccess = TRUE;
944
945     if (context_neednl ())
946       fprintf (g_warningstream, "\n");
947     
948     if (nspecErrors > 0)
949       {
950         if (nspecErrors == context_getLCLExpect ())
951           {
952             specErrors = 
953               message ("%d spec warning%&, as expected\n       ", 
954                        nspecErrors);
955           }
956         else
957           {
958             if (context_getLCLExpect () > 0)
959               {
960                 specErrors = 
961                   message ("%d spec warning%&, expected %d\n       ", 
962                            nspecErrors,
963                            (int) context_getLCLExpect ());
964               }
965             else
966               {
967                 specErrors = message ("%d spec warning%&\n       ",
968                                       nspecErrors);
969                 expsuccess = FALSE;
970               }
971           }
972       }
973     else
974         {
975           if (context_getLCLExpect () > 0)
976             {
977               specErrors = message ("No spec warnings, expected %d\n       ", 
978                                     (int) context_getLCLExpect ());
979               expsuccess = FALSE;
980             }
981         }
982
983       if (context_anyErrors ())
984         {
985           if (context_numErrors () == context_getExpect ())
986             {
987               if (!isQuiet) {
988                 llmsg (message ("Finished checking --- "
989                                 "%s%d code warning%&, as expected",
990                                 specErrors, context_numErrors ()));
991               }
992             }
993           else
994             {
995               if (context_getExpect () > 0)
996                 {
997                   if (!isQuiet) {
998                     llmsg (message 
999                            ("Finished checking --- "
1000                             "%s%d code warning%&, expected %d",
1001                             specErrors, context_numErrors (), 
1002                             (int) context_getExpect ()));
1003                   }
1004
1005                   expsuccess = FALSE;
1006                 }
1007               else
1008                 {
1009                   
1010                   if (!isQuiet)
1011                     {
1012                       llmsg (message ("Finished checking --- "
1013                                       "%s%d code warning%&", 
1014                                       specErrors, context_numErrors ()));
1015                     }
1016
1017                   expsuccess = FALSE;
1018                 }
1019             }
1020         }
1021       else
1022         {
1023           if (context_getExpect () > 0)
1024             {
1025               if (!isQuiet) {
1026                 llmsg (message
1027                        ("Finished checking --- "
1028                         "%sno code warnings, expected %d", 
1029                         specErrors,
1030                         (int) context_getExpect ()));
1031               }
1032
1033               expsuccess = FALSE;
1034             }
1035           else
1036             {
1037               if (context_getLinesProcessed () > 0)
1038                 {
1039                   if (cstring_isEmpty (specErrors))
1040                     {
1041                       if (!isQuiet) 
1042                         {
1043                           llmsg (message ("Finished checking --- no warnings"));
1044                         } 
1045                     }
1046                   else
1047                     {
1048                       if (!isQuiet) 
1049                         {
1050                           llmsg (message ("Finished checking --- %sno code warnings",
1051                                           specErrors));
1052                         }
1053                     }
1054                 }
1055               else
1056                 {
1057                   if (!isQuiet) {
1058                     llmsg (message ("Finished checking --- %sno code processed", 
1059                                     specErrors));
1060                   }
1061                 }
1062             }
1063         }
1064
1065       cstring_free (specErrors);
1066   }
1067   
1068   if (context_getFlag (FLG_STATS))
1069     {
1070       clock_t ttime = clock () - before;
1071       int specLines = context_getSpecLinesProcessed ();
1072       cstring specmsg = cstring_undefined;
1073
1074       rstime = clock ();
1075       
1076       if (specLines > 0)
1077         {
1078           specmsg = message ("%d spec, ", specLines);
1079         }
1080       
1081       /* The clock might wrap around, not platform-independent easy way to deal with this... */
1082       if (ttime > 0)
1083         {
1084 # ifndef CLOCKS_PER_SEC
1085           lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n", 
1086                               specmsg,
1087                               context_getLinesProcessed (), 
1088                               (int) ttime));
1089 # else
1090           lldiagmsg (message ("%s%d source lines in %f s.\n", 
1091                               specmsg,
1092                               context_getLinesProcessed (), 
1093                               (double) ttime / CLOCKS_PER_SEC));
1094           DPRINTF (("Time: %ld [%ld - %ld]", ttime, rstime, before));
1095 # endif
1096         }
1097       else
1098         {
1099           lldiagmsg (message ("%s%d source lines\n", 
1100                               specmsg,
1101                               context_getLinesProcessed ()));
1102         }
1103
1104     }
1105   else
1106     {
1107       rstime = clock ();
1108     }
1109   
1110   if (context_getFlag (FLG_TIMEDIST))
1111     {
1112       clock_t ttime = clock () - before;
1113       
1114       if (ttime > 0)
1115         {
1116           char *msg = (char *) dmalloc (256 * sizeof (*msg));
1117           
1118           if (anylcl)
1119             {
1120               (void) snprintf (msg, 256,
1121                         "Time distribution (percent): initialize %.2f / lcl %.2f / "
1122                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1123                         (100.0 * (double) (libtime - before) / ttime),
1124                         (100.0 * (double) (lcltime - libtime) / ttime),
1125                         (100.0 * (double) (pptime - lcltime) / ttime),
1126                         (100.0 * (double) (cptime - pptime) / ttime),
1127                         (100.0 * (double) (rstime - cptime) / ttime));
1128             }
1129           else
1130             {
1131               (void) snprintf (msg, 256,
1132                         "Time distribution (percent): initialize %.2f / "
1133                         "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1134                         (100.0 * (double) (libtime - before) / ttime),
1135                         (100.0 * (double) (pptime - libtime) / ttime),
1136                         (100.0 * (double) (cptime - pptime) / ttime),
1137                         (100.0 * (double) (rstime - cptime) / ttime));
1138             }
1139           
1140           llgenindentmsgnoloc (cstring_fromCharsO (msg));
1141         }
1142     }
1143
1144   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1145   BADBRANCHRET (LLFAILURE);
1146 }
1147
1148 # ifdef WIN32
1149 /*
1150 ** Reenable return value warnings.
1151 */
1152 # pragma warning (default:4035)
1153 # endif 
1154
1155 void
1156 llinterrupt (int i)
1157 {
1158   switch (i)
1159     {
1160     case SIGINT:
1161       fprintf (g_errorstream, "*** Interrupt\n");
1162       llexit (LLINTERRUPT);
1163     case SIGSEGV:
1164       {
1165         cstring loc;
1166         
1167         /* Cheat when there are parse errors */
1168         checkParseError (); 
1169         
1170         fprintf (g_errorstream, "*** Segmentation Violation\n");
1171         
1172         /* Don't catch it if fileloc_unparse causes a signal */
1173         (void) signal (SIGSEGV, NULL);
1174
1175         loc = fileloc_unparse (g_currentloc);
1176         
1177         fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1178                  cstring_toCharsSafe (loc));
1179         cstring_free (loc);
1180         printCodePoint ();
1181         fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
1182         exit (LLGIVEUP);
1183       }
1184     default:
1185       fprintf (g_errorstream, "*** Signal: %d\n", i);
1186       /*@-mustfree@*/
1187       fprintf (g_errorstream, "*** Location (not trusted): %s\n", 
1188                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1189       /*@=mustfree@*/
1190       printCodePoint ();
1191       fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
1192       exit (LLGIVEUP);
1193     }
1194 }
1195
1196 void
1197 cleanupFiles (void)
1198 {
1199   static bool doneCleanup = FALSE;
1200
1201   /* make sure this is only called once! */
1202
1203   if (doneCleanup) return;
1204
1205   setCodePoint ();
1206
1207   /*
1208   ** Close all open files
1209   **    (There should only be open files, if we exited after a fatal error.)
1210   */
1211
1212   fileTable_closeAll (context_fileTable ());
1213
1214   if (context_getFlag (FLG_KEEP))
1215     {
1216       check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1217       fileTable_printTemps (context_fileTable ());
1218     }
1219   else
1220     {
1221 # ifdef WIN32
1222       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1223       
1224       if (nfiles != 0) 
1225         {
1226           llbug (message ("Files unclosed: %d", nfiles));
1227         }
1228 # endif
1229       fileTable_cleanup (context_fileTable ());
1230     }
1231
1232   doneCleanup = TRUE;
1233 }
1234
1235 /*
1236 ** cleans up temp files (if necessary) and exits
1237 */
1238
1239 /*@noreturn@*/ void
1240 llexit (int status)
1241 {
1242   DPRINTF (("llexit: %d", status));
1243
1244 # ifdef WIN32
1245   if (status == LLFAILURE) 
1246     {
1247       _fcloseall ();
1248     }
1249 # endif
1250
1251   cleanupFiles ();
1252
1253   if (status != LLFAILURE)
1254     {
1255       usymtab_destroyMod ();
1256       context_destroyMod ();
1257       exprNode_destroyMod ();
1258       cppReader_destroyMod ();
1259       sRef_destroyMod ();
1260       uentry_destroyMod ();
1261       typeIdSet_destroyMod ();
1262       qual_destroyMod ();
1263       osd_destroyMod ();
1264       fileloc_destroyMod ();
1265 # ifdef USEDMALLOC
1266       dmalloc_shutdown ();
1267 # endif
1268     }
1269
1270   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1271 }
1272
1273 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
1274   /*@modifies fileSystem@*/
1275 {
1276   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1277   int skip = (fileIdList_size (fl) / 5);
1278   int filesprocessed = 0;
1279   fileIdList dfiles = fileIdList_create ();
1280
1281   fileloc_free (g_currentloc);
1282   g_currentloc = fileloc_createBuiltin ();
1283
1284   fileIdList_elements (fl, fid)
1285     {
1286       cstring ppfname = fileTable_fileName (fid);
1287
1288       if (!(osd_fileIsReadable (ppfname)))
1289         {
1290           lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
1291           ppfname = cstring_undefined;
1292         }
1293
1294       if (cstring_isDefined (ppfname))
1295         {
1296           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
1297
1298           if (xhfiles)
1299             {
1300               llassert (fileTable_isXHFile (context_fileTable (), dfile));
1301             }
1302
1303           llassert (cstring_isNonEmpty (ppfname));
1304           
1305           if (msg)
1306             {
1307               if ((filesprocessed % skip) == 0) 
1308                 {
1309                   if (filesprocessed == 0) {
1310                     displayScanContinue (cstring_makeLiteral (" "));
1311                   }
1312                   else {
1313                     displayScanContinue (cstring_makeLiteral ("."));
1314                   }
1315                 }
1316               filesprocessed++;
1317             }
1318
1319           DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1320
1321           if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) 
1322             {
1323               llfatalerror (message ("Preprocessing error for file: %s", 
1324                                      fileTable_rootFileName (fid)));
1325             }
1326           
1327           fileIdList_add (dfiles, dfile);
1328         }
1329     } end_fileIdList_elements; 
1330   
1331   return dfiles;
1332 }
1333
1334 /* This should be in an lclUtils.c file... */
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
1404 void warnSysFiles(fileIdList files)
1405 {
1406   fileIdList_elements (files, file)
1407     {
1408       
1409       if (fileTable_isSystemFile (context_fileTable (), file) )
1410         {
1411           if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1412             {
1413               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);
1414             }
1415         }
1416     } 
1417   end_fileIdList_elements;
1418 }
This page took 0.225907 seconds and 5 git commands to generate.