]> andersk Git - splint.git/blob - src/llmain.c
Added the flag warnsysfiles (default +) if this flag is set splint warns if the user...
[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
55 # ifndef NOLCL
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 # endif
71
72 # include "Headers/version.h" /* Visual C++ finds the wrong version.h */
73 # include "fileIdList.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
82 static void printMail (void);
83 static void printMaintainer (void);
84 static void printReferences (void);
85 static void printFlags (void);
86 static void printAnnotations (void);
87 static void printParseErrors (void);
88 static void printComments (void);
89 static void describePrefixCodes (void);
90 static void cleanupFiles (void);
91 static void showHelp (void);
92 static void interrupt (int p_i);
93
94 static bool readOptionsFile (cstring p_fname,
95                              cstringSList *p_passThroughArgs,
96                              bool p_report) 
97    /*@modifies fileSystem, internalState, *p_passThroughArgs@*/ ;
98    
99 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
100    /*@modifies *p_passThroughArgs, p_rcfile@*/
101    /*@ensures closed p_rcfile@*/ ;
102
103 static void describeVars (void);
104 static bool specialFlagsHelp (char *p_next);
105 static bool hasShownHerald = FALSE;
106 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath) 
107      /*@modifies *p_inpath@*/ ;
108
109 static bool anylcl = FALSE;
110 static clock_t inittime;
111
112 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
113
114 static fileIdList preprocessFiles (fileIdList, bool)
115   /*@modifies fileSystem@*/ ;
116
117   void warnSysFiles(fileIdList files) /*@*/;
118
119 # ifndef NOLCL
120
121 static
122 void lslCleanup (void)
123    /*@globals killed g_symtab@*/
124    /*@modifies internalState, g_symtab@*/
125 {
126   /*
127   ** Cleanup all the LCL/LSL.
128   */
129
130   static bool didCleanup = FALSE;
131
132   llassert (!didCleanup);
133   llassert (anylcl);
134
135   didCleanup = TRUE;
136
137   lsymbol_destroyMod ();
138   LCLSynTableCleanup ();
139   LCLTokenTableCleanup ();
140   LCLScanLineCleanup ();
141   LCLScanCleanup ();
142
143   /* clean up LSL parsing */
144
145   lsynTableCleanup ();
146   ltokenTableCleanup ();
147   lscanLineCleanup ();
148   LSLScanCleanup ();
149
150   symtable_free (g_symtab);
151   sort_destroyMod (); 
152 }
153
154 static
155   void lslInit (void)
156   /*@globals undef g_symtab; @*/
157   /*@modifies g_symtab, internalState, fileSystem; @*/
158 {
159   /*
160   ** Open init file provided by user, or use the default LCL init file 
161   */
162   
163   cstring larchpath = context_getLarchPath ();
164   inputStream LSLinitFile = inputStream_undefined;
165
166   setCodePoint ();
167
168   if (inputStream_isUndefined (initFile))
169     {
170       initFile = inputStream_create (cstring_makeLiteral (INITFILENAME), 
171                                      cstring_makeLiteralTemp (LCLINIT_SUFFIX),
172                                      FALSE);
173       
174       if (!inputStream_getPath (larchpath, initFile))
175         {
176           lldiagmsg (message ("Continuing without LCL init file: %s",
177                               inputStream_fileName (initFile)));
178         }
179       else 
180         {
181           if (!inputStream_open (initFile))
182             {
183               lldiagmsg (message ("Continuing without LCL init file: %s",
184                                   inputStream_fileName (initFile)));
185             }
186         }
187     }
188   else 
189     {
190       if (!inputStream_open (initFile))
191         {
192           lldiagmsg (message ("Continuing without LCL init file: %s",
193                               inputStream_fileName (initFile)));
194         }
195     }
196
197   /* Initialize checker */
198
199   lsymbol_initMod ();
200   LCLSynTableInit ();
201
202   setCodePoint ();
203
204   LCLSynTableReset ();
205   LCLTokenTableInit ();
206
207   setCodePoint ();
208
209   LCLScanLineInit ();
210   setCodePoint ();
211   LCLScanLineReset ();
212   setCodePoint ();
213   LCLScanInit ();
214
215   setCodePoint ();
216
217   /* need this to initialize LCL checker */
218
219   llassert (inputStream_isDefined (initFile));      
220   if (inputStream_isOpen (initFile))
221     {
222       setCodePoint ();
223
224       LCLScanReset (initFile);
225       LCLProcessInitFileInit ();
226       LCLProcessInitFileReset ();
227
228       setCodePoint ();
229       LCLProcessInitFile ();
230       LCLProcessInitFileCleanup ();
231
232       setCodePoint ();
233       check (inputStream_close (initFile));
234     }
235   
236   /* Initialize LSL init files, for parsing LSL signatures from LSL */
237   
238   LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"), 
239                                     cstring_makeLiteralTemp (".lsi"),
240                                     FALSE);
241   
242   if (!inputStream_getPath (larchpath, LSLinitFile))
243     {
244       lldiagmsg (message ("Continuing without LSL init file: %s",
245                           inputStream_fileName (LSLinitFile)));
246     }
247   else 
248     {
249       if (!inputStream_open (LSLinitFile))
250         {
251           lldiagmsg (message ("Continuing without LSL init file: %s",
252                               inputStream_fileName (LSLinitFile)));
253         }
254     }
255       
256   setCodePoint ();
257   lsynTableInit ();
258   lsynTableReset ();
259
260   setCodePoint ();
261   ltokenTableInit ();
262
263   setCodePoint ();
264   lscanLineInit ();
265   lscanLineReset ();
266   LSLScanInit ();
267
268   if (inputStream_isOpen (LSLinitFile))
269     {
270       setCodePoint ();
271       LSLScanReset (LSLinitFile);
272       LSLProcessInitFileInit ();
273       setCodePoint ();
274       LSLProcessInitFile ();
275       setCodePoint ();
276       check (inputStream_close (LSLinitFile));
277     }
278       
279   inputStream_free (LSLinitFile);
280   
281   if (lclHadError ())
282     {
283       lclplainerror 
284         (cstring_makeLiteral ("LSL init file error.  Attempting to continue."));
285     }
286   
287   setCodePoint ();
288   g_symtab = symtable_new ();
289   
290   /* 
291   ** sort_init must come after symtab has been initialized 
292   */
293   sort_init ();
294   abstract_init ();
295   setCodePoint ();
296   
297   inittime = clock ();
298   
299   /* 
300   ** Equivalent to importing old spec_csupport.lcl
301   ** define immutable LCL type "bool" and bool constants TRUE and FALSE
302   ** and initialized them to be equal to LSL's "true" and "false".
303   **
304   ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
305   */
306       
307   LCLBuiltins (); 
308   LCLReportEolTokens (FALSE);
309 }
310
311 static void
312 lslProcess (fileIdList lclfiles)
313    /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
314               undef killed g_symtab; @*/
315    /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
316 {
317   char *path = NULL;
318   bool parser_status = FALSE;
319   bool overallStatus = FALSE;
320   
321   lslInit ();
322   
323   context_resetSpecLines ();
324
325   fileIdList_elements (lclfiles, fid)
326     {
327       cstring actualName = cstring_undefined;
328       cstring fname = fileTable_fileName (fid);
329       
330       if (osd_getPath (cstring_fromChars (g_localSpecPath), 
331                        fname, &actualName) == OSD_FILENOTFOUND)
332         {
333           if (mstring_equal (g_localSpecPath, "."))
334             {
335               lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
336             }
337           else
338             {
339               lldiagmsg (message ("Spec file not found: %q (on %s)", 
340                                   osd_outputPath (fname), 
341                                   cstring_fromChars (g_localSpecPath)));
342             }
343         }
344       else
345         {
346           inputStream specFile;
347           /*@access cstring@*/
348           char *namePtr = actualName;
349
350           while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR) 
351             {
352               namePtr += 2;
353             }
354           /*@noaccess cstring@*/
355
356           g_currentSpec = cstring_fromCharsNew (namePtr);
357
358           specFile = inputStream_create (cstring_copy (g_currentSpec),
359                                          LCL_EXTENSION, TRUE);
360           
361           llassert (inputStream_isDefined (specFile));
362           
363           g_currentSpecName = specFullName 
364             (cstring_toCharsSafe (g_currentSpec),
365              &path);
366
367           setSpecFileId (fid);
368                   
369           if (context_getFlag (FLG_SHOWSCAN))
370             {
371               lldiagmsg (message ("< reading spec %s >", g_currentSpec));
372             }
373           
374           /* Open the source file */
375           
376           if (!inputStream_open (specFile))
377             {
378               lldiagmsg (message ("Cannot open file: %q",
379                                   osd_outputPath (inputStream_fileName (specFile))));
380               inputStream_free (specFile);
381             }
382           else
383             {
384               scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
385               dummy_scope->kind = SPE_INVALID;
386               
387               lhInit (specFile);
388               LCLScanReset (specFile);
389               
390               /* 
391               ** Minor hacks to allow more than one LCL file to
392               ** be scanned, while keeping initializations
393               */
394               
395               symtable_enterScope (g_symtab, dummy_scope);
396               resetImports (cstring_fromChars (g_currentSpecName));
397               context_enterLCLfile ();
398               (void) lclHadNewError ();
399               
400               parser_status = (ylparse () != 0);
401               context_exitLCLfile ();
402               lhCleanup ();
403               overallStatus = parser_status || lclHadNewError (); 
404
405               if (context_getFlag (FLG_DOLCS))
406                 {
407                   if (overallStatus)
408                     {
409                       outputLCSFile (path, "%FAILED Output from ",
410                                      g_currentSpecName);
411                     }
412                   else
413                     {
414                       outputLCSFile (path, "%PASSED Output from ", 
415                                      g_currentSpecName);
416                     }
417                 }
418
419               (void) inputStream_close (specFile);
420               inputStream_free (specFile);
421
422               symtable_exitScope (g_symtab);
423             }      
424         }
425       cstring_free (actualName);
426     } end_fileIdList_elements; 
427     
428     /* Can cleanup lsl stuff right away */
429     
430     lslCleanup ();
431     
432     g_currentSpec = cstring_undefined;
433     g_currentSpecName = NULL;
434 }
435 # endif
436
437 static void handlePassThroughFlag (char *arg)
438 {
439   char *curarg = arg;
440   char *quotechar = strchr (curarg, '\"');
441   int offset = 0;
442   bool open = FALSE;
443   char *freearg = NULL;
444
445   while (quotechar != NULL)
446     {
447       if (*(quotechar - 1) == '\\')
448         {
449           char *tp = quotechar - 2;
450           bool escape = TRUE;
451
452           while (*tp == '\\')
453             {
454               escape = !escape;
455               tp--;
456             }
457           
458           if (escape)
459             {
460               curarg = quotechar + 1;
461               quotechar = strchr (curarg, '\"');
462               continue;
463             }
464         }
465       
466       llassert (quotechar != NULL);
467       *quotechar = '\0';
468       offset = (quotechar - arg) + 2;
469       
470       if (open)
471         {
472           arg = cstring_toCharsSafe
473             (message ("%s\"\'%s", 
474                       cstring_fromChars (arg), 
475                       cstring_fromChars (quotechar + 1))); 
476           freearg = arg;
477           open = FALSE;
478         }
479       else
480         {
481           arg = cstring_toCharsSafe
482             (message ("%s\'\"%s", 
483                       cstring_fromChars (arg), 
484                       cstring_fromChars (quotechar + 1)));
485           freearg = arg;
486           open = TRUE;
487         }
488       
489       curarg = arg + offset;
490       quotechar = strchr (curarg, '\"');
491     }
492
493   if (open)
494     {
495       showHerald ();
496       voptgenerror (FLG_BADFLAG,
497                     message ("Unclosed quote in flag: %s",
498                              cstring_fromChars (arg)),
499                     g_currentloc);
500     }
501   else
502     {
503       if (arg[0] == 'D') {
504         cstring def;
505         
506         /* 
507         ** If the value is surrounded by single quotes ('), remove
508         ** them.  This is an artifact of UNIX command line?
509         */
510
511         def = osd_fixDefine (cstring_fromChars (arg + 1));
512         DPRINTF (("Do define: %s", def));
513         cppDoDefine (def);
514         DPRINTF (("After define"));
515         cstring_free (def);
516       } else if (arg[0] == 'U') {
517         cppDoUndefine (cstring_fromChars (arg + 1));
518       } else {
519         BADBRANCH;
520       }
521     }
522   
523   sfree (freearg);
524 }
525
526 void showHerald (void)
527 {
528   if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
529
530   else
531     {
532       fprintf (g_msgstream, "%s\n\n", SPLINT_VERSION);
533       hasShownHerald = TRUE;
534       llflush ();
535     }
536 }
537
538 static cstring findLarchPathFile (/*@temp@*/ cstring s)
539 {
540   cstring pathName;
541   filestatus status;
542   
543   status = osd_getPath (context_getLarchPath (), s, &pathName);
544   
545   if (status == OSD_FILEFOUND)
546     {
547       return pathName;
548     }
549   else if (status == OSD_FILENOTFOUND)
550     {
551       showHerald ();
552       lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
553     }
554   else if (status == OSD_PATHTOOLONG)
555     {
556       /* Directory and filename are too long.  Report error. */
557       llbuglit ("soure_getPath: Filename plus directory from search path too long");
558     }
559   else
560     {
561       BADBRANCH;
562     }
563
564   return cstring_undefined;
565 }
566
567 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
568 {
569   cstring pathName = findLarchPathFile (s);
570
571   if (cstring_isDefined (pathName))
572     {
573       if (fileTable_exists (context_fileTable (), pathName))
574         {
575           showHerald ();
576           lldiagmsg (message ("File listed multiple times: %s", pathName));
577           cstring_free (pathName);
578         }
579       else
580         {
581           fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
582         }
583     }
584 }
585
586 static void addFile (fileIdList files, /*@only@*/ cstring s)
587 {
588   if (fileTable_exists (context_fileTable (), s))
589     {
590       showHerald ();
591       lldiagmsg (message ("File listed multiple times: %s", s));
592       cstring_free (s);
593     }
594   else
595     {
596       fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
597     }
598 }
599
600 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
601 {
602   cstring pathName = findLarchPathFile (s);
603
604   if (cstring_isDefined (pathName))
605     {
606       if (fileTable_exists (context_fileTable (), pathName))
607         {
608           showHerald ();
609           lldiagmsg (message ("File listed multiple times: %s", s));
610         }
611       else
612         {
613           fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
614         }
615     }
616
617   cstring_free (pathName);
618 }
619
620 /*
621 ** Disable MSVC++ warning about return value.  Methinks humbly splint control
622 ** comments are a mite more legible.
623 */
624
625 # ifdef WIN32
626 # pragma warning (disable:4035) 
627 # endif
628
629 int main (int argc, char *argv[])
630 # ifdef NOLCL
631   /*@globals killed undef g_currentloc,
632              killed undef yyin,
633                     undef g_msgstream;
634    @*/
635   /*@modifies g_currentloc, fileSystem,
636               yyin; 
637   @*/
638 # else
639   /*@globals killed undef g_currentloc,
640              killed undef initFile,
641              killed       g_localSpecPath,  
642              killed undef g_currentSpec,
643              killed undef g_currentSpecName,
644              killed undef yyin,
645                     undef g_msgstream;
646    @*/
647   /*@modifies g_currentloc, initFile, 
648               g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
649               yyin; 
650   @*/
651 # endif
652 {
653   bool first_time = TRUE;
654   bool showhelp = FALSE;
655   bool allhelp = TRUE;
656   bool expsuccess;
657   inputStream sourceFile = inputStream_undefined;
658  
659   fileIdList dercfiles;
660   cstringSList fl = cstringSList_undefined;
661   cstringSList passThroughArgs = cstringSList_undefined;
662   fileIdList cfiles, xfiles, lclfiles, mtfiles;
663   clock_t before, lcltime, libtime, pptime, cptime, rstime;
664   int i = 0;
665
666 # ifdef __EMX__
667   _wildcard (&argc, &argv);
668 # endif
669
670   g_msgstream = stdout;
671
672   (void) signal (SIGINT, interrupt);
673   (void) signal (SIGSEGV, interrupt); 
674
675   cfiles = fileIdList_create ();
676   xfiles = fileIdList_create ();
677   lclfiles = fileIdList_create ();
678   mtfiles = fileIdList_create ();
679
680   flags_initMod ();
681   clabstract_initMod ();
682   typeIdSet_initMod ();
683   cppReader_initMod ();
684   osd_initMod ();
685
686   setCodePoint ();
687   
688   g_currentloc = fileloc_createBuiltin ();
689   
690   before = clock ();
691   context_initMod ();
692
693   context_setInCommandLine ();
694
695   if (argc <= 1)
696     {
697       showHelp ();
698       llexit (LLGIVEUP);
699     }
700
701   setCodePoint ();
702   yydebug = 0;
703
704   /*
705   ** Add include directories from environment.
706   */
707
708   {
709     cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
710     cstring oincval = incval;
711
712     if (cstring_isDefined (incval))
713       {
714         /*
715         ** Each directory on the include path is a system include directory.
716         */
717
718         DPRINTF (("include: %s", incval));
719         context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
720
721         while (cstring_isDefined (incval))
722           {
723             /*@access cstring@*/
724             char *nextsep = strchr (incval, PATH_SEPARATOR);
725
726             if (nextsep != NULL)
727               {
728                 cstring dir;
729                 *nextsep = '\0';
730                 dir = cstring_copy (incval);
731
732                 if (cstring_length (dir) == 0
733                     || !isalpha ((int) cstring_firstChar (dir)))
734                   {
735                     /* 
736                     ** win32 environment values can have special values,
737                     ** ignore them
738                     */
739                   }
740                 else
741                   {
742                     cppAddIncludeDir (dir);
743                   }
744
745                 *nextsep = PATH_SEPARATOR;
746                 incval = cstring_fromChars (nextsep + 1);
747                 cstring_free (dir);
748               }
749             else
750               {
751                 break;
752               }
753
754             /*@noaccess cstring@*/
755           }
756       }
757     else /* 2001-09-09: herbert */
758       {
759         /* Put C_INCLUDE_PATH directories in sysdirs */
760         cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
761         if (cstring_isDefined (cincval))
762           {
763             context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
764           }
765       }
766     /* /herbert */
767
768     cstring_free (oincval);
769   }
770
771   /*
772   ** check RCFILE for default flags
773   */
774
775   {
776     cstring home = osd_getHomeDir ();
777     cstring fname  = cstring_undefined;
778     bool defaultf = TRUE;
779     bool nof = FALSE;
780
781     for (i = 1; i < argc; i++)
782       {
783         char *thisarg;
784         thisarg = argv[i];
785         
786         if (*thisarg == '-' || *thisarg == '+')
787           {
788             bool set = (*thisarg == '+');
789             flagcode opt;
790
791             thisarg++;
792
793             /*
794             ** Don't report warnings this time
795             */
796
797             opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
798
799             if (opt == FLG_NOF)
800               {
801                 nof = TRUE;
802               }
803             else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
804               {
805                 /*
806                 ** Need to set it immediately, so rc file scan is displayed
807                 */
808
809                 context_userSetFlag (opt, set);
810               }
811             else if (opt == FLG_OPTF)
812               {
813                 if (++i < argc)
814                   {
815                     defaultf = FALSE;
816                     fname = cstring_fromChars (argv[i]);
817                     (void) readOptionsFile (fname, &passThroughArgs, TRUE);
818                   }
819                 else
820                   llfatalerror
821                     (cstring_makeLiteral ("Flag f to select options file "
822                                           "requires an argument"));
823               }
824             else
825               {
826                 ; /* wait to process later */
827               }
828           }
829       }
830         
831     setCodePoint ();
832
833     if (!nof && defaultf)
834       {
835         /*
836         ** No explicit rc file, first try reading ~/.splintrc
837         */
838
839         if (cstring_isUndefined (fname))
840           {
841             if (!cstring_isEmpty (home)) 
842               {
843                 bool readhomerc, readaltrc;
844                 cstring homename, altname;
845
846                 homename = message ("%s%h%s", home, CONNECTCHAR,
847                                  cstring_fromChars (RCFILE));
848                 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
849                 
850                 /*
851                 ** Try ~/.splintrc also for historical accuracy
852                 */
853                 
854                 altname = message ("%s%h%s", home, CONNECTCHAR,
855                                  cstring_fromChars (ALTRCFILE));
856                 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
857
858                 if (readhomerc && readaltrc)
859                   {
860
861                     voptgenerror 
862                       (FLG_WARNRC,
863                        message ("Found both %s and %s files. Using both files, "
864                                 "but recommend using only %s to avoid confusion.",
865                                 homename, altname, homename),
866                        g_currentloc);
867                   }
868
869                 cstring_free (homename);
870                 cstring_free (altname);
871               }
872           }
873         
874         /*
875         ** Next, read .splintrc in the current working directory
876         */
877         
878         {
879           cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
880           cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
881           bool readrc, readaltrc;
882           
883           readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
884           readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
885           
886           if (readrc && readaltrc)
887             {
888               voptgenerror (FLG_WARNRC,
889                             message ("Found both %s and %s files. Using both files, "
890                                      "but recommend using only %s to avoid confusion.",
891                                      rcname, altname, rcname),
892                             g_currentloc);
893               
894             }
895
896           cstring_free (rcname);
897           cstring_free (altname);
898         }
899       }
900   }
901   
902   setCodePoint ();
903   
904   for (i = 1; i < argc; i++)
905     {
906       char *thisarg;
907       flagcode opt;
908       
909       thisarg = argv[i];
910       
911       if (showhelp)
912         {
913           if (allhelp)
914             {
915               showHerald ();
916             }
917           
918           allhelp = FALSE;
919           
920           if (*thisarg == '-' || *thisarg == '+')
921             {
922               thisarg++;        /* skip '-' */
923             }
924           if (mstring_equal (thisarg, "modes"))
925             {
926               llmsg (describeModes ());
927             }
928           else if (mstring_equal (thisarg, "vars")
929                    || mstring_equal (thisarg, "env"))
930             {
931               describeVars ();
932             }
933           else if (mstring_equal (thisarg, "annotations"))
934             {
935               printAnnotations ();
936             }
937           else if (mstring_equal (thisarg, "parseerrors"))
938             {
939               printParseErrors ();
940             }
941           else if (mstring_equal (thisarg, "comments"))
942             {
943               printComments ();
944             }
945           else if (mstring_equal (thisarg, "prefixcodes"))
946             {
947               describePrefixCodes ();
948             }
949           else if (mstring_equal (thisarg, "references") 
950                    || mstring_equal (thisarg, "refs"))
951             {
952               printReferences ();
953             }
954           else if (mstring_equal (thisarg, "mail"))
955             {
956               printMail ();
957             }
958           else if (mstring_equal (thisarg, "maintainer")
959                    || mstring_equal (thisarg, "version"))
960             {
961               printMaintainer ();
962             }
963           else if (mstring_equal (thisarg, "flags"))
964             {
965               if (i + 1 < argc)
966                 {
967                   char *next = argv[i + 1];
968                   
969                   if (specialFlagsHelp (next))
970                     {
971                       i++;
972                     }
973                   else
974                     {
975                       flagkind k = identifyCategory (cstring_fromChars (next));
976                       
977                       if (k != FK_NONE)
978                         {
979                           printCategory (k);
980                           i++;
981                         }
982                     }
983                 }
984               else
985                 {
986                   printFlags ();
987                 }
988             }
989           else
990             {
991               cstring s = describeFlag (cstring_fromChars (thisarg));
992               
993               if (cstring_isDefined (s))
994                 {
995                   llmsg (s);
996                 }
997             }
998         }
999       else
1000         {
1001           if (*thisarg == '-' || *thisarg == '+')
1002             {
1003               bool set = (*thisarg == '+');
1004               cstring flagname;
1005               
1006               thisarg++;        /* skip '-' */
1007               flagname = cstring_fromChars (thisarg);
1008
1009               DPRINTF (("Flag: %s", flagname));
1010               opt = flags_identifyFlag (flagname);
1011               DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1012
1013               if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
1014                 {
1015                   /* showscan already processed */
1016                   DPRINTF (("Skipping!"));
1017                 }
1018               else if (flagcode_isInvalid (opt))
1019                 {
1020                   DPRINTF (("Invalid: %s", flagname));
1021
1022                   if (isMode (flagname))
1023                     {
1024                       context_setMode (flagname);
1025                     }
1026                   else
1027                     {
1028                       DPRINTF (("Error!"));
1029                       voptgenerror (FLG_BADFLAG,
1030                                     message ("Unrecognized option: %s", 
1031                                              cstring_fromChars (thisarg)),
1032                                     g_currentloc);
1033                     }
1034                 }
1035               else
1036                 {
1037                   context_userSetFlag (opt, set);
1038                   
1039                   if (flagcode_hasArgument (opt))
1040                     {
1041                       if (opt == FLG_HELP)
1042                         {
1043                           showhelp = TRUE;
1044                         }
1045                       else if (flagcode_isPassThrough (opt)) /* -D or -U */
1046                         { 
1047                           passThroughArgs = cstringSList_add 
1048                             (passThroughArgs, cstring_fromChars (thisarg));
1049                         }
1050                       else if (flagcode_hasNumber (opt))
1051                         {
1052                           if (++i < argc)
1053                             {
1054                               setValueFlag (opt, cstring_fromChars (argv[i]));
1055                             }
1056                           else
1057                             {
1058                               llfatalerror 
1059                                 (message
1060                                  ("Flag %s must be followed by a number",
1061                                   flagcode_unparse (opt)));
1062                             }
1063                         } 
1064                       else if (flagcode_hasChar (opt))
1065                         {
1066                           if (++i < argc)
1067                             {
1068                               setValueFlag (opt, cstring_fromChars (argv[i]));
1069                             }
1070                           else
1071                             {
1072                               llfatalerror 
1073                                 (message
1074                                  ("Flag %s must be followed by a character",
1075                                   flagcode_unparse (opt)));
1076                             }
1077                         } 
1078                       else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1079                         {
1080                           cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1081                           
1082                           switch (opt)
1083                             {
1084                             case FLG_INCLUDEPATH:
1085                               cppAddIncludeDir (dir);
1086                               /*@switchbreak@*/ break;
1087                             case FLG_SPECPATH:
1088                               /*@-mustfree@*/
1089                               g_localSpecPath = cstring_toCharsSafe
1090                                 (message ("%s%h%s", 
1091                                           cstring_fromChars (g_localSpecPath), 
1092                                           PATH_SEPARATOR,
1093                                           dir));
1094                               /*@=mustfree@*/
1095                               /*@switchbreak@*/ break;
1096                               BADDEFAULT;
1097                             }
1098                         }
1099                       else if (flagcode_hasString (opt)
1100                                || opt == FLG_INIT || opt == FLG_OPTF)
1101                         {
1102                           if (++i < argc)
1103                             {
1104                               cstring arg = cstring_fromChars (argv[i]);
1105                               
1106                               if (opt == FLG_OPTF)
1107                                 {
1108                                   ; /* -f already processed */
1109                                 }
1110                               else if (opt == FLG_INIT)
1111                                 {
1112 # ifndef NOLCL
1113                                   initFile = inputStream_create 
1114                                     (arg, 
1115                                      cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1116                                      FALSE);
1117 # endif
1118                                   break;
1119                                 }
1120                               else
1121                                 {
1122                                   DPRINTF (("String flag: %s / %s",
1123                                             flagcode_unparse (opt), arg));
1124                                   if (opt == FLG_MTSFILE)
1125                                     {
1126                                       /*
1127                                       ** arg identifies mts files
1128                                       */
1129                                       cstring tmp =  message ("%s%s", arg, MTS_EXTENSION);
1130                                       addLarchPathFile (mtfiles, tmp);
1131                                       cstring_free (tmp);
1132                                       tmp = message ("%s%s", arg, XH_EXTENSION);
1133                                       addXHFile (xfiles, tmp);
1134                                       cstring_free (tmp);
1135                                     }
1136                                   else
1137                                     {
1138                                       setStringFlag (opt, cstring_copy (arg));
1139                                     }
1140                                 }
1141                             }
1142                           else
1143                             {
1144                               llfatalerror 
1145                                 (message
1146                                  ("Flag %s must be followed by a string",
1147                                   flagcode_unparse (opt)));
1148                             }
1149                         }
1150                       else
1151                         {
1152                           /* no argument */
1153                         }
1154                     }
1155                 }
1156             }
1157           else /* its a filename */
1158             {
1159               DPRINTF (("Adding filename: %s", thisarg));
1160               fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1161             }
1162         }
1163     }
1164
1165   setCodePoint ();  
1166   showHerald (); 
1167   
1168   /*
1169   ** create lists of C and LCL files
1170   */
1171
1172   cstringSList_elements (fl, current)
1173     {
1174       cstring ext = fileLib_getExtension (current);
1175       
1176       if (cstring_isUndefined (ext))
1177         {
1178           /* no extension --- both C and LCL with default extensions */
1179           
1180           addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1181           addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1182         }
1183       else if (cstring_equal (ext, XH_EXTENSION))
1184         {
1185           addXHFile (xfiles, current);
1186         }
1187       else if (cstring_equal (ext, PP_EXTENSION))
1188         {
1189           if (!context_getFlag (FLG_NOPP))
1190             {
1191               voptgenerror 
1192                 (FLG_FILEEXTENSIONS,
1193                  message ("File extension %s used without +nopp flag (will be processed as C source code): %s", 
1194                           ext, current),
1195                  g_currentloc);
1196             }
1197           
1198           addFile (cfiles, cstring_copy (current));
1199         }
1200       else if (cstring_equal (ext, LCL_EXTENSION)) 
1201         {
1202           addFile (lclfiles, cstring_copy (current));
1203         }
1204       else if (fileLib_isCExtension (ext))
1205         {
1206           addFile (cfiles, cstring_copy (current));
1207         }
1208       else if (cstring_equal (ext, MTS_EXTENSION))
1209         {
1210           addLarchPathFile (mtfiles, current);
1211         }
1212       else 
1213         {
1214           voptgenerror 
1215             (FLG_FILEEXTENSIONS,
1216              message ("Unrecognized file extension: %s (assuming %s is C source code)", 
1217                       current, ext),
1218              g_currentloc);
1219           
1220           addFile (cfiles, cstring_copy (current));
1221         }
1222     } end_cstringSList_elements;
1223   
1224   if (showhelp)
1225     {
1226       if (allhelp)
1227         {
1228           showHelp ();
1229         }
1230       fprintf (g_msgstream, "\n");
1231
1232       fileIdList_free (cfiles);
1233       fileIdList_free (xfiles);
1234       fileIdList_free (lclfiles);
1235       
1236       llexit (LLSUCCESS);
1237     }
1238
1239 # ifdef DOANNOTS
1240   initAnnots ();
1241 # endif
1242
1243   inittime = clock ();
1244
1245   context_resetErrors ();
1246   context_clearInCommandLine ();
1247
1248   anylcl = !fileIdList_isEmpty (lclfiles);
1249
1250   if (context_doMerge ())
1251     {
1252       cstring m = context_getMerge ();
1253
1254       if (context_getFlag (FLG_SHOWSCAN))
1255         {
1256           fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1257         }
1258
1259       loadState (m);
1260
1261       if (context_getFlag (FLG_SHOWSCAN))
1262         {
1263           fprintf (g_msgstream, " >\n");
1264         }
1265
1266       if (!usymtab_existsType (context_getBoolName ()))
1267         {
1268           usymtab_initBool (); 
1269         }
1270     }
1271   else
1272     {
1273       if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1274         {
1275           ;
1276         }
1277       else
1278         {
1279           ctype_initTable ();
1280         }
1281
1282       /* setup bool type and constants */
1283       usymtab_initBool (); 
1284     }
1285
1286   fileloc_free (g_currentloc);
1287   g_currentloc = fileloc_createBuiltin ();
1288
1289   /*
1290   ** Read metastate files (must happen before loading libraries) 
1291   */
1292
1293   fileIdList_elements (mtfiles, mtfile)
1294     {
1295       context_setFileId (mtfile);
1296
1297       if (context_getFlag (FLG_SHOWSCAN))
1298         {
1299           lldiagmsg (message ("< processing %s >", fileTable_rootFileName (mtfile)));
1300         }
1301       
1302       mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1303     } end_fileIdList_elements;
1304
1305   libtime = clock ();
1306
1307   if (anylcl)
1308     {
1309 # ifdef NOLCL
1310       llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1311 # else
1312       lslProcess (lclfiles);
1313 # endif
1314     }
1315
1316   usymtab_initGlobalMarker ();
1317
1318   /*
1319   ** pre-processing
1320   **
1321   ** call the pre-preprocessor and /lib/cpp to generate appropriate
1322   ** files
1323   **
1324   */
1325
1326   context_setInCommandLine ();
1327
1328   DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1329   
1330   cstringSList_elements (passThroughArgs, thisarg) {
1331     handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1332   } end_cstringSList_elements;
1333
1334   cstringSList_free (passThroughArgs);
1335
1336   cleanupMessages ();
1337
1338   DPRINTF (("Initializing cpp reader!"));
1339   cppReader_initialize ();
1340   cppReader_saveDefinitions ();
1341   
1342   context_clearInCommandLine ();
1343
1344   if (!context_getFlag (FLG_NOPP))
1345     {
1346       fileIdList tfiles;
1347
1348       llflush ();
1349
1350       if (context_getFlag (FLG_SHOWSCAN))
1351         {
1352           fprintf (stderr, "< preprocessing"); 
1353         }
1354       
1355       lcltime = clock ();
1356
1357       context_setPreprocessing ();
1358       dercfiles = preprocessFiles (xfiles, TRUE);
1359       tfiles = preprocessFiles (cfiles, FALSE);
1360       warnSysFiles(cfiles);
1361       dercfiles = fileIdList_append (dercfiles, tfiles);
1362       fileIdList_free (tfiles);
1363
1364       context_clearPreprocessing ();
1365
1366       fileIdList_free (cfiles);
1367
1368       if (context_getFlag (FLG_SHOWSCAN))
1369         {
1370           fprintf (stderr, " >\n");
1371         }
1372       
1373       pptime = clock ();
1374     }
1375   else
1376     {
1377       lcltime = clock ();
1378       dercfiles = fileIdList_append (cfiles, xfiles);
1379       pptime = clock ();
1380     }
1381
1382   /*
1383   ** now, check all the corresponding C files
1384   **
1385   ** (for now these are just <file>.c, but after pre-processing
1386   **  will be <tmpprefix>.<file>.c)
1387   */
1388
1389   {
1390 # ifdef WIN32
1391     int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1392
1393     if (nfiles != 0) 
1394       {
1395         llbug (message ("Files unclosed: %d", nfiles));
1396       }
1397 # endif
1398   }
1399
1400   DPRINTF (("Initializing..."));
1401
1402   exprNode_initMod ();
1403
1404   DPRINTF (("Okay..."));
1405
1406   fileIdList_elements (dercfiles, fid)
1407     {
1408       sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1409       context_setFileId (fid);
1410       
1411       /* Open source file  */
1412       
1413       if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1414         {
1415           /* previously, this was ignored  ?! */
1416           llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1417         }
1418       else
1419         {
1420           yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1421         
1422           llassert (yyin != NULL);
1423
1424           if (context_getFlag (FLG_SHOWSCAN))
1425             {
1426               lldiagmsg (message ("< checking %q >", osd_outputPath (fileTable_rootFileName (fid))));
1427             }
1428           
1429           /*
1430           ** Every time, except the first time, through the loop,
1431           ** need to call yyrestart to clean up the parse buffer.
1432           */
1433
1434           if (!first_time)
1435             {
1436               (void) yyrestart (yyin);  
1437             }
1438           else
1439             {
1440               first_time = FALSE;
1441             }
1442           
1443           DPRINTF (("Entering..."));
1444           context_enterFile ();
1445           (void) yyparse ();
1446           context_exitCFile ();
1447                     
1448           (void) inputStream_close (sourceFile);
1449         }      
1450     } end_fileIdList_elements;
1451
1452   cptime = clock ();
1453   
1454   /* process any leftover macros */
1455
1456   context_processAllMacros ();
1457   
1458   /* check everything that was specified was defined */
1459   
1460   /* don't check if no c files were processed ?
1461   **   is this correct behaviour?
1462   */
1463   
1464   if (context_getFlag (FLG_SHOWSCAN))
1465     {
1466       lldiagmsg (cstring_makeLiteral ("< global checks >"));
1467     }
1468
1469   cleanupMessages ();
1470   
1471   if (context_getLinesProcessed () > 0)
1472     {
1473       usymtab_allDefined ();
1474     }
1475
1476   if (context_maybeSet (FLG_TOPUNUSED))
1477     {
1478       uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1479
1480       if (uentry_isValid (ue))
1481         {
1482           uentry_setUsed (ue, fileloc_observeBuiltin ());
1483         }
1484
1485       usymtab_allUsed ();
1486     }
1487
1488   if (context_maybeSet (FLG_EXPORTLOCAL))
1489     {
1490       usymtab_exportLocal ();
1491     }
1492
1493   
1494   if (context_maybeSet (FLG_EXPORTHEADER))
1495     {
1496       usymtab_exportHeader ();
1497     }
1498
1499   if (context_getFlag (FLG_SHOWUSES))
1500     {
1501       usymtab_displayAllUses ();
1502     }
1503
1504   context_checkSuppressCounts ();
1505
1506   if (context_doDump ())
1507     {
1508       cstring dump = context_getDump ();
1509
1510       dumpState (dump);
1511     }
1512
1513 # ifdef DOANNOTS
1514   printAnnots ();
1515 # endif
1516
1517   cleanupFiles ();
1518
1519   if (context_getFlag (FLG_SHOWSUMMARY))
1520     {
1521       summarizeErrors (); 
1522     }
1523
1524   
1525   {
1526     bool isQuiet = context_getFlag (FLG_QUIET);
1527     cstring specErrors = cstring_undefined;
1528 # ifndef NOLCL
1529     int nspecErrors = lclNumberErrors ();
1530 # endif
1531     
1532     expsuccess = TRUE;
1533
1534     if (context_neednl ())
1535       fprintf (g_msgstream, "\n");
1536     
1537 # ifndef NOLCL
1538     if (nspecErrors > 0)
1539       {
1540         if (nspecErrors == context_getLCLExpect ())
1541           {
1542             specErrors = 
1543               message ("%d spec warning%&, as expected\n       ", 
1544                        nspecErrors);
1545           }
1546         else
1547           {
1548             if (context_getLCLExpect () > 0)
1549               {
1550                 specErrors = 
1551                   message ("%d spec warning%&, expected %d\n       ", 
1552                            nspecErrors,
1553                            (int) context_getLCLExpect ());
1554               }
1555             else
1556               {
1557                 specErrors = message ("%d spec warning%&\n       ",
1558                                       nspecErrors);
1559                 expsuccess = FALSE;
1560               }
1561           }
1562       }
1563     else
1564         {
1565           if (context_getLCLExpect () > 0)
1566             {
1567               specErrors = message ("No spec warnings, expected %d\n       ", 
1568                                     (int) context_getLCLExpect ());
1569               expsuccess = FALSE;
1570             }
1571         }
1572 # endif
1573
1574       if (context_anyErrors ())
1575         {
1576           if (context_numErrors () == context_getExpect ())
1577             {
1578               if (!isQuiet) {
1579                 llmsg (message ("Finished checking --- "
1580                                 "%s%d code warning%&, as expected",
1581                                 specErrors, context_numErrors ()));
1582               }
1583             }
1584           else
1585             {
1586               if (context_getExpect () > 0)
1587                 {
1588                   if (!isQuiet) {
1589                     llmsg (message 
1590                            ("Finished checking --- "
1591                             "%s%d code warning%&, expected %d",
1592                             specErrors, context_numErrors (), 
1593                             (int) context_getExpect ()));
1594                   }
1595
1596                   expsuccess = FALSE;
1597                 }
1598               else
1599                 {
1600                   
1601                   if (!isQuiet)
1602                     {
1603                       llmsg (message ("Finished checking --- "
1604                                       "%s%d code warning%&", 
1605                                       specErrors, context_numErrors ()));
1606                     }
1607
1608                   expsuccess = FALSE;
1609                 }
1610             }
1611         }
1612       else
1613         {
1614           if (context_getExpect () > 0)
1615             {
1616               if (!isQuiet) {
1617                 llmsg (message
1618                        ("Finished checking --- "
1619                         "%sno code warnings, expected %d", 
1620                         specErrors,
1621                         (int) context_getExpect ()));
1622               }
1623
1624               expsuccess = FALSE;
1625             }
1626           else
1627             {
1628               if (context_getLinesProcessed () > 0)
1629                 {
1630                   if (cstring_isEmpty (specErrors))
1631                     {
1632                       if (!isQuiet) 
1633                         {
1634                           llmsg (message ("Finished checking --- no warnings"));
1635                         } 
1636                     }
1637                   else
1638                     {
1639                       if (!isQuiet) 
1640                         {
1641                           llmsg (message ("Finished checking --- %sno code warnings",
1642                                           specErrors));
1643                         }
1644                     }
1645                 }
1646               else
1647                 {
1648                   if (!isQuiet) {
1649                     llmsg (message ("Finished checking --- %sno code processed", 
1650                                     specErrors));
1651                   }
1652                 }
1653             }
1654         }
1655
1656       cstring_free (specErrors);
1657   }
1658   
1659   if (context_getFlag (FLG_STATS))
1660     {
1661       clock_t ttime = clock () - before;
1662       int specLines = context_getSpecLinesProcessed ();
1663       
1664       rstime = clock ();
1665       
1666       if (specLines > 0)
1667         {
1668           fprintf (g_msgstream, "%d spec, ", specLines);
1669         }
1670       
1671 # ifndef CLOCKS_PER_SEC
1672       fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n", 
1673                context_getLinesProcessed (), 
1674                (long) ttime);
1675 # else
1676       fprintf (g_msgstream, "%d source lines in %.2f s.\n", 
1677                context_getLinesProcessed (), 
1678                (double) ttime / CLOCKS_PER_SEC);
1679 # endif
1680     }
1681   else
1682     {
1683       rstime = clock ();
1684     }
1685   
1686   if (context_getFlag (FLG_TIMEDIST))
1687     {
1688       clock_t ttime = clock () - before;
1689       
1690       if (ttime > 0)
1691         {
1692           char *msg = (char *) dmalloc (256 * sizeof (*msg));
1693           
1694           if (anylcl)
1695             {
1696               sprintf (msg, 
1697                        "Time distribution (percent): initialize %.2f / lcl %.2f / "
1698                        "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1699                        (100.0 * (double) (libtime - before) / ttime),
1700                        (100.0 * (double) (lcltime - libtime) / ttime),
1701                        (100.0 * (double) (pptime - lcltime) / ttime),
1702                        (100.0 * (double) (cptime - pptime) / ttime),
1703                        (100.0 * (double) (rstime - cptime) / ttime));
1704             }
1705           else
1706             {
1707               sprintf (msg, 
1708                        "Time distribution (percent): initialize %.2f / "
1709                        "pre-process %.2f / c check %.2f / finalize %.2f \n", 
1710                        (100.0 * (double) (libtime - before) / ttime),
1711                        (100.0 * (double) (pptime - libtime) / ttime),
1712                        (100.0 * (double) (cptime - pptime) / ttime),
1713                        (100.0 * (double) (rstime - cptime) / ttime));
1714             }
1715           
1716           llgenindentmsgnoloc (cstring_fromCharsO (msg));
1717         }
1718     }
1719
1720   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1721   BADBRANCHRET (LLFAILURE);
1722 }
1723
1724 # ifdef WIN32
1725 /*
1726 ** Reenable return value warnings.
1727 */
1728 # pragma warning (default:4035)
1729 # endif 
1730
1731 void
1732 showHelp (void)
1733 {
1734   showHerald ();
1735   
1736   llmsg (message ("Source files are .c, .h and %s files.  If there is no suffix,",
1737                   LCL_EXTENSION));
1738   llmsg (message ("   Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1739   llmsglit ("");
1740   llmsglit ("Use splint -help <topic or flag name> for more information");
1741   llmsglit ("");
1742   llmsglit ("Topics:");
1743   llmsglit ("");
1744   llmsglit ("   annotations (describes source-code annotations)");
1745   llmsglit ("   comments (describes control comments)");
1746   llmsglit ("   flags (describes flag categories)");
1747   llmsglit ("   flags <category> (describes flags in category)");
1748   llmsglit ("   flags all (short description of all flags)");
1749   llmsglit ("   flags alpha (list all flags alphabetically)");
1750   llmsglit ("   flags full (full description of all flags)");
1751   llmsglit ("   mail (information on mailing lists)");
1752   llmsglit ("   modes (show mode settings)");
1753   llmsglit ("   parseerrors (help on handling parser errors)");
1754   llmsglit ("   prefixcodes (character codes in namespace prefixes)");
1755   llmsglit ("   references (sources for more information)");
1756   llmsglit ("   vars (environment variables)"); 
1757   llmsglit ("   version (information on compilation, maintainer)");
1758   llmsglit ("");
1759 }
1760
1761 static bool
1762 specialFlagsHelp (char *next)
1763 {
1764   if ((next != NULL) && (*next != '-') && (*next != '+'))
1765     {
1766       if (mstring_equal (next, "alpha"))
1767         {
1768           printAlphaFlags ();
1769           return TRUE;
1770         }
1771       else if (mstring_equal (next, "all"))
1772         {
1773           printAllFlags (TRUE, FALSE);
1774           return TRUE;
1775         }
1776       else if (mstring_equal (next, "categories")
1777                || mstring_equal (next, "cats"))
1778         {
1779           listAllCategories ();
1780           return TRUE;
1781         }
1782       else if (mstring_equal (next, "full"))
1783         {
1784           printAllFlags (FALSE, TRUE);
1785           return TRUE;
1786         }
1787       else if (mstring_equal (next, "manual"))
1788         {
1789           printFlagManual (FALSE);
1790           return TRUE;
1791         }
1792       else if (mstring_equal (next, "webmanual"))
1793         {
1794           printFlagManual (TRUE);
1795           return TRUE;
1796         }
1797       else
1798         {
1799           return FALSE;
1800         }
1801     }
1802   else
1803     {
1804       return FALSE;
1805     }
1806 }
1807
1808 void
1809 printParseErrors (void)
1810 {
1811   llmsglit ("Parse Errors");
1812   llmsglit ("------------");
1813   llmsglit ("");
1814   llmsglit ("Splint will sometimes encounter a parse error for code that "
1815             "can be parsed with a local compiler. There are a few likely "
1816             "causes for this and a number of techniques that can be used "
1817             "to work around the problem.");
1818   llmsglit ("");
1819   llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1820             "language with compiler-specific keywords and syntax. While "
1821             "it is not advisible to use these, oftentimes one has no choice "
1822             "when the system header files use compiler extensions. ");
1823   llmsglit ("");
1824   llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1825             "if the +gnuextensions flag is set. You may be able to workaround "
1826             "other compiler extensions by using a pre-processor define. "
1827             "Alternately, you can surround the unparseable code with");
1828   llmsglit ("");
1829   llmsglit ("   # ifndef S_SPLINT_S");
1830   llmsglit ("   ...");
1831   llmsglit ("   # endif");
1832   llmsglit ("");
1833   /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1834   llmsglit ("Missing type definitions --- an undefined type name will usually "
1835             "lead to a parse error. This often occurs when a standard header "
1836             "file defines some type that is not part of the standard library. ");
1837   llmsglit ("By default, Splint does not process the local files corresponding "
1838             "to standard library headers, but uses a library specification "
1839             "instead so dependencies on local system headers can be detected. "
1840             "If another system header file that does not correspond to a "
1841             "standard library header uses one of these superfluous types, "
1842             "a parse error will result.");
1843   llmsglit ("");
1844   llmsglit ("If the parse error is inside a posix standard header file, the "
1845             "first thing to try is +posixlib. This makes Splint use "
1846             "the posix library specification instead of reading the posix "
1847             "header files.");
1848   llmsglit ("");
1849   llmsglit ("Otherwise, you may need to either manually define the problematic "
1850             "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1851             "splint to process the header file that defines it. This is done "
1852             "by setting -skipisoheaders or -skipposixheaders before "
1853             "the file that defines the type is #include'd.");
1854   llmsglit ("(See splint -help "
1855             "skipisoheaders and splint -help skipposixheaders for a list of "
1856             "standard headers.)  For example, if <sys/local.h> uses a type "
1857             "defined by posix header <sys/types.h> but not defined by the "
1858             "posix library, we might do: ");
1859   llmsglit ("");
1860   llmsglit ("   /*@-skipposixheaders@*/");
1861   llmsglit ("   # include <sys/types.h>");
1862   llmsglit ("   /*@=skipposixheaders@*/");
1863   llmsglit ("   # include <sys/local.h>");
1864   llmsglit ("");
1865   llmsglit ("to force Splint to process <sys/types.h>.");
1866   llmsglit ("");
1867   llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1868             "to continue after a parse error.  This is usually not successful "
1869             "and the author does not consider assertion failures when +trytorecover "
1870             "is used to be bugs.");
1871 }
1872
1873 void
1874 printAnnotations (void)
1875 {
1876   llmsglit ("Annotations");
1877   llmsglit ("-----------");
1878   llmsglit ("");
1879   llmsglit ("Annotations are semantic comments that document certain "
1880             "assumptions about functions, variables, parameters, and types. ");
1881   llmsglit ("");
1882   llmsglit ("They may be used to indicate where the representation of a "
1883             "user-defined type is hidden, to limit where a global variable may "
1884             "be used or modified, to constrain what a function implementation "
1885             "may do to its parameters, and to express checked assumptions about "
1886             "variables, types, structure fields, function parameters, and "
1887             "function results.");
1888   llmsglit ("");
1889   llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1890             "played by any printable character, selected using -commentchar <char>.");
1891   llmsglit ("");
1892   llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1893   llmsglit ("");
1894   llmsglit ("Globals: (in function declarations)");
1895   llmsglit ("   /*@globals <globitem>,+ @*/");
1896   llmsglit ("      globitem is an identifier, internalState or fileSystem");
1897   llmsglit ("");
1898   llmsglit ("Modifies: (in function declarations)");
1899   llmsglit ("   /*@modifies <moditem>,+ @*/");
1900   llmsglit ("      moditem is an lvalue");
1901   llmsglit ("   /*@modifies nothing @*/");
1902   llmsglit ("   /*@*/   (Abbreviation for no globals and modifies nothing.)");
1903   llmsglit ("");
1904   llmsglit ("Iterators:");
1905   llmsglit ("   /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1906   llmsglit ("");
1907   llmsglit ("Constants:");
1908   llmsglit ("   /*@constant <declaration> @*/ - declares a constant");
1909   llmsglit ("");
1910   llmsglit ("Alternate Types:");
1911   llmsglit ("   /*@alt <basic-type>,+ @*/");
1912   llmsglit ("   (e.g., int /*@alt char@*/ is a type matching either int or char)");
1913   llmsglit ("");
1914   llmsglit ("Declarator Annotations");
1915   llmsglit ("");
1916   llmsglit ("Type Definitions:");
1917   llmsglit ("   /*@abstract@*/ - representation is hidden from clients");
1918   llmsglit ("   /*@concrete@*/ - representation is visible to clients");
1919   llmsglit ("   /*@immutable@*/ - instances of the type cannot change value");
1920   llmsglit ("   /*@mutable@*/ - instances of the type can change value");
1921   llmsglit ("   /*@refcounted@*/ - reference counted type");
1922   llmsglit ("");
1923   llmsglit ("Global Variables:");
1924   llmsglit ("   /*@unchecked@*/ - weakest checking for global use");
1925   llmsglit ("   /*@checkmod@*/ - check modification by not use of global");
1926   llmsglit ("   /*@checked@*/ - check use and modification of global");
1927   llmsglit ("   /*@checkedstrict@*/ - check use of global strictly");
1928   llmsglit ("");
1929   llmsglit ("Memory Management:");
1930   llmsglit ("   /*@dependent@*/ - a reference to externally-owned storage");
1931   llmsglit ("   /*@keep@*/ - a parameter that is kept by the called function");
1932   llmsglit ("   /*@killref@*/ - a refcounted parameter, killed by the call");
1933   llmsglit ("   /*@only@*/ - an unshared reference");
1934   llmsglit ("   /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1935   llmsglit ("   /*@shared@*/ - shared reference that is never deallocated");
1936   llmsglit ("   /*@temp@*/ - temporary parameter");
1937   llmsglit ("");
1938   llmsglit ("Aliasing:");
1939   llmsglit ("   /*@unique@*/ - may not be aliased by any other visible reference");
1940   llmsglit ("   /*@returned@*/ - may be aliased by the return value");
1941   llmsglit ("");
1942   llmsglit ("Exposure:");
1943   llmsglit ("   /*@observer@*/ - reference that cannot be modified");
1944   llmsglit ("   /*@exposed@*/ - exposed reference to storage in another object");
1945   llmsglit ("");
1946   llmsglit ("Definition State:");
1947   llmsglit ("   /*@out@*/ - storage reachable from reference need not be defined");
1948   llmsglit ("   /*@in@*/ - all storage reachable from reference must be defined");
1949   llmsglit ("   /*@partial@*/ - partially defined, may have undefined fields");
1950   llmsglit ("   /*@reldef@*/ - relax definition checking");
1951   llmsglit ("");
1952   llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1953   llmsglit ("   undef - variable is undefined before the call");
1954   llmsglit ("   killed - variable is undefined after the call");
1955   llmsglit ("");
1956   llmsglit ("Null State:");
1957   llmsglit ("   /*@null@*/ - possibly null pointer");
1958   llmsglit ("   /*@notnull@*/ - definitely non-null pointer");
1959   llmsglit ("   /*@relnull@*/ - relax null checking");
1960   llmsglit ("");
1961   llmsglit ("Null Predicates:");
1962   llmsglit ("   /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1963   llmsglit ("   /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1964   llmsglit ("");
1965   llmsglit ("Execution:");
1966   llmsglit ("   /*@noreturn@*/ - function never returns");
1967   llmsglit ("   /*@maynotreturn@*/ - function may or may not return");
1968   llmsglit ("   /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1969   llmsglit ("   /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1970   llmsglit ("   /*@alwaysreturns@*/ - function always returns");
1971   llmsglit ("");
1972   llmsglit ("Side-Effects:");
1973   llmsglit ("   /*@sef@*/ - corresponding actual parameter has no side effects");
1974   llmsglit ("");
1975   llmsglit ("Declaration:");
1976   llmsglit ("   /*@unused@*/ - need not be used (no unused errors reported)");
1977   llmsglit ("   /*@external@*/ - defined externally (no undefined error reported)");
1978   llmsglit ("");
1979   llmsglit ("Case:");
1980   llmsglit ("   /*@fallthrough@*/ - fall-through case");
1981   llmsglit ("");
1982   llmsglit ("Break:");
1983   llmsglit ("   /*@innerbreak@*/ - break is breaking an inner loop or switch");
1984   llmsglit ("   /*@loopbreak@*/ - break is breaking a loop");
1985   llmsglit ("   /*@switchbreak@*/ - break is breaking a switch");
1986   llmsglit ("   /*@innercontinue@*/ - continue is continuing an inner loop");
1987   llmsglit ("");
1988   llmsglit ("Unreachable Code:");
1989   llmsglit ("   /*@notreached@*/ - statement may be unreachable.");
1990   llmsglit ("");
1991   llmsglit ("Special Functions:");
1992   llmsglit ("   /*@printflike@*/ - check variable arguments like printf");
1993   llmsglit ("   /*@scanflike@*/ - check variable arguments like scanf");
1994 }
1995
1996 void
1997 printComments (void)
1998 {
1999   llmsglit ("Control Comments");
2000   llmsglit ("----------------");
2001   llmsglit ("");
2002   llmsglit ("Setting Flags");
2003   llmsglit ("");
2004   llmsglit ("Most flags (all except those characterized as \"globally-settable only\") can be set locally using control comments. A control comment can set flags locally to override the command line settings. The original flag settings are restored before processing the next file.");
2005   llmsglit ("");
2006   llmsglit ("The syntax for setting flags in control comments is the same as that of the command line, except that flags may also be preceded by = to restore their setting to the original command-line value. For instance,");
2007   llmsglit ("   /*@+boolint -modifies =showfunc@*/");
2008   llmsglit ("sets boolint on (this makes bool and int indistinguishable types), sets modifies off (this prevents reporting of modification errors), and sets showfunc to its original setting (this controls  whether or not the name of a function is displayed before a message).");
2009   llmsglit ("");
2010   llmsglit ("Error Suppression");
2011   llmsglit ("");
2012   llmsglit ("Several comments are provided for suppressing messages. In general, it is usually better to use specific flags to suppress a particular error permanently, but the general error suppression flags may be more convenient for quickly suppressing messages for code that will be corrected or documented later.");
2013   llmsglit ("");
2014   llmsglit ("/*@ignore@*/ ... /*@end@*/");
2015   llgenindentmsgnoloc
2016     (cstring_makeLiteral 
2017      ("No errors will be reported in code regions between /*@ignore@*/ and /*@end@*/. These comments can be used to easily suppress an unlimited number of messages."));
2018   llmsglit ("/*@i@*/");
2019     llgenindentmsgnoloc
2020     (cstring_makeLiteral 
2021      ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2022   llmsglit ("/*@i<n>@*/");
2023   llgenindentmsgnoloc
2024     (cstring_makeLiteral 
2025      ("No errors will be reported from an /*@i<n>@*/ (e.g., /*@i3@*/) comment to the end of the line. If there are not exactly n errors suppressed from the comment point to the end of the line, Splint will report an error."));
2026   llmsglit ("/*@t@*/, /*@t<n>@*/");
2027   llgenindentmsgnoloc
2028     (cstring_makeLiteral 
2029      ("Like i and i<n>, except controlled by +tmpcomments flag. These can be used to temporarily suppress certain errors. Then, -tmpcomments can be set to find them again."));
2030   llmsglit ("");
2031   llmsglit ("Type Access");
2032   llmsglit ("");
2033   llmsglit ("/*@access <type>@*/"); 
2034   llmsglit ("   Allows the following code to access the representation of <type>");
2035   llmsglit ("/*@noaccess <type>@*/");
2036   llmsglit ("   Hides the representation of <type>");
2037   llmsglit ("");
2038   llmsglit ("Macro Expansion");
2039   llmsglit ("");
2040   llmsglit ("/*@notfunction@*/");
2041   llgenindentmsgnoloc 
2042     (cstring_makeLiteral
2043      ("Indicates that the next macro definition is not intended to be a "
2044       "function, and should be expanded in line instead of checked as a "
2045       "macro function definition."));
2046 }
2047
2048   
2049 void
2050 printFlags (void)
2051 {
2052   llmsglit ("Flag Categories");
2053   llmsglit ("---------------");
2054   listAllCategories ();
2055   llmsglit ("\nTo see the flags in a flag category, do\n   splint -help flags <category>");
2056   llmsglit ("To see a list of all flags in alphabetical order, do\n   splint -help flags alpha");
2057   llmsglit ("To see a full description of all flags, do\n   splint -help flags full");
2058 }
2059
2060 void
2061 printMaintainer (void)
2062 {
2063   llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2064   llmsglit (LCL_COMPILE);
2065 }
2066
2067 void
2068 printMail (void)
2069 {
2070   llmsglit ("Mailing Lists");
2071   llmsglit ("-------------");
2072   llmsglit ("");
2073   llmsglit ("There are two mailing lists associated with Splint: ");
2074   llmsglit ("");
2075   llmsglit ("   lclint-announce@virginia.edu");
2076   llmsglit ("");
2077   llmsglit ("      Reserved for announcements of new releases and bug fixes.");
2078   llmsglit ("      To subscribe, send a message to majordomo@virginia.edu with body: ");
2079   llmsglit ("           subscribe lclint-announce");
2080   llmsglit ("");
2081   llmsglit ("   lclint-interest@virginia.edu");
2082   llmsglit ("");
2083   llmsglit ("      Informal discussions on the use and development of Splint.");
2084   llmsglit ("      To subscribe, send a message to majordomo@virginia.edu with body: ");
2085   llmsglit ("           subscribe lclint-interest");
2086 }
2087
2088 void
2089 printReferences (void)
2090 {
2091   llmsglit ("References");
2092   llmsglit ("----------");
2093   llmsglit ("");
2094   llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2095 }
2096
2097 void
2098 describePrefixCodes (void)
2099 {
2100   llmsglit ("Prefix Codes");
2101   llmsglit ("------------");
2102   llmsglit ("");
2103   llmsglit ("These characters have special meaning in name prefixes:");
2104   llmsglit ("");
2105   llmsg (message ("   %h  Any uppercase letter [A-Z]", PFX_UPPERCASE));
2106   llmsg (message ("   %h  Any lowercase letter [a-z]", PFX_LOWERCASE));
2107   llmsg (message ("   %h  Any character (valid in a C identifier)", PFX_ANY));
2108   llmsg (message ("   %h  Any digit [0-9]", PFX_DIGIT));
2109   llmsg (message ("   %h  Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2110   llmsg (message ("   %h  Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2111   llmsg (message ("   %h  Any letter [A-Za-z]", PFX_ANYLETTER));
2112   llmsg (message ("   %h  Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2113   llmsglit ("   *  Zero or more repetitions of the previous character class until the end of the name");
2114 }
2115
2116 void
2117 describeVars (void)
2118 {
2119   cstring eval;
2120   cstring def;
2121
2122   eval = context_getLarchPath ();
2123   def = osd_getEnvironmentVariable (LARCH_PATH);
2124
2125   if (cstring_isDefined (def) || 
2126       !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2127     {
2128       llmsg (message ("LARCH_PATH = %s", eval));
2129     }
2130   else
2131     {
2132       llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2133                       cstring_fromChars (DEFAULT_LARCHPATH)));
2134     }
2135   
2136   llmsglit ("   --- path used to find larch initialization files and LSL traits");
2137
2138   eval = context_getLCLImportDir ();
2139   def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2140
2141   if (cstring_isDefined (def) ||
2142       !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2143     {
2144       llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2145     }
2146   else
2147     {
2148       llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR), 
2149                       cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR))); 
2150     }
2151   
2152   llmsglit ("   --- directory containing lcl standard library files "
2153             "(import with < ... >)");;
2154
2155   llmsg (message 
2156          ("include path = %q (set by environment variable %s and -I flags)",
2157           cppReader_getIncludePath (), INCLUDEPATH_VAR));
2158
2159   llmsglit ("   --- path used to find #include'd files");
2160
2161   llmsg (message 
2162          ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2163           context_getString (FLG_SYSTEMDIRS),
2164           INCLUDEPATH_VAR));
2165
2166   llmsglit ("   --- if file is found on this path, it is treated as a system file for error reporting");
2167 }
2168
2169 void
2170 interrupt (int i)
2171 {
2172   switch (i)
2173     {
2174     case SIGINT:
2175       fprintf (stderr, "*** Interrupt\n");
2176       llexit (LLINTERRUPT);
2177     case SIGSEGV:
2178       {
2179         cstring loc;
2180         
2181         /* Cheat when there are parse errors */
2182         checkParseError (); 
2183         
2184         fprintf (stderr, "*** Segmentation Violation\n");
2185         
2186         /* Don't catch it if fileloc_unparse causes a signal */
2187         (void) signal (SIGSEGV, NULL);
2188
2189         loc = fileloc_unparse (g_currentloc);
2190         
2191         fprintf (stderr, "*** Location (not trusted): %s\n", 
2192                  cstring_toCharsSafe (loc));
2193         cstring_free (loc);
2194         printCodePoint ();
2195         fprintf (stderr, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2196         exit (LLGIVEUP);
2197       }
2198     default:
2199       fprintf (stderr, "*** Signal: %d\n", i);
2200       /*@-mustfree@*/
2201       fprintf (stderr, "*** Location (not trusted): %s\n", 
2202                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2203       /*@=mustfree@*/
2204       printCodePoint ();
2205       fprintf (stderr, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2206       exit (LLGIVEUP);
2207     }
2208 }
2209
2210 void
2211 cleanupFiles (void)
2212 {
2213   static bool doneCleanup = FALSE;
2214
2215   /* make sure this is only called once! */
2216
2217   if (doneCleanup) return;
2218
2219   setCodePoint ();
2220
2221   /*
2222   ** Close all open files
2223   **    (There should only be open files, if we exited after a fatal error.)
2224   */
2225
2226   fileTable_closeAll (context_fileTable ());
2227
2228   if (context_getFlag (FLG_KEEP))
2229     {
2230       check (fputs ("Temporary files kept:\n", stderr) != EOF);
2231       fileTable_printTemps (context_fileTable ());
2232     }
2233   else
2234     {
2235 # ifdef WIN32
2236       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2237       
2238       if (nfiles != 0) 
2239         {
2240           llbug (message ("Files unclosed: %d", nfiles));
2241         }
2242 # endif
2243       fileTable_cleanup (context_fileTable ());
2244     }
2245
2246   doneCleanup = TRUE;
2247 }
2248
2249 /*
2250 ** cleans up temp files (if necessary) and exits
2251 */
2252
2253 /*@noreturn@*/ void
2254 llexit (int status)
2255 {
2256   DPRINTF (("llexit: %d", status));
2257
2258 # ifdef WIN32
2259   if (status == LLFAILURE) 
2260     {
2261       _fcloseall ();
2262     }
2263 # endif
2264
2265   cleanupFiles ();
2266
2267   if (status != LLFAILURE)
2268     {
2269       context_destroyMod ();
2270       exprNode_destroyMod ();
2271       
2272       sRef_destroyMod ();
2273       uentry_destroyMod ();
2274       typeIdSet_destroyMod ();
2275       
2276 # ifdef USEDMALLOC
2277       dmalloc_shutdown ();
2278 # endif
2279     }
2280
2281   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2282 }
2283
2284 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2285 {
2286   bool res = FALSE;
2287
2288   if (fileTable_exists (context_fileTable (), fname))
2289     {
2290       if (report)
2291         {
2292           voptgenerror
2293             (FLG_WARNRC, 
2294              message ("Multiple attempts to read options file: %s", fname),
2295              g_currentloc);
2296         }
2297     }
2298   else
2299     {
2300       FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2301       
2302       if (innerf != NULL)
2303         {
2304           fileloc fc = g_currentloc;
2305           g_currentloc = fileloc_createRc (fname);
2306
2307           if (context_getFlag (FLG_SHOWSCAN))
2308             {
2309               lldiagmsg (message ("< reading options from %q >", 
2310                                   fileloc_outputFilename (g_currentloc)));
2311             }
2312           
2313           loadrc (innerf, passThroughArgs);
2314           fileloc_reallyFree (g_currentloc);
2315           g_currentloc = fc;
2316           res = TRUE;
2317         }
2318       else 
2319         {
2320           if (report)
2321             {
2322               voptgenerror
2323                 (FLG_WARNRC, 
2324                  message ("Cannot open options file: %s", fname),
2325                  g_currentloc);
2326             }
2327         }
2328     }
2329
2330   return res;
2331 }
2332
2333 /*
2334 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2335 */
2336
2337 void
2338 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2339    /*@modifies rcfile@*/
2340    /*@ensures closed rcfile@*/
2341 {
2342   char *s = mstring_create (MAX_LINE_LENGTH);
2343   char *os = s;
2344   
2345   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2346
2347   s = os;
2348
2349   while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2350     {
2351       char c;
2352       bool set = FALSE;     
2353       char *thisflag;
2354       flagcode opt;
2355
2356       DPRINTF (("Line: %s", s));
2357       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2358             
2359       while (*s == ' ' || *s == '\t')
2360         {
2361           s++;
2362           incColumn ();
2363         }
2364       
2365       while (*s != '\0')
2366         {
2367           bool escaped = FALSE;
2368           bool quoted = FALSE;
2369           c = *s;
2370
2371           DPRINTF (("Process: %s", s));
2372           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2373           /* comment characters */
2374           if (c == '#' || c == ';' || c == '\n') 
2375             {
2376               /*@innerbreak@*/
2377               break;
2378             }
2379           
2380           if (c == '-' || c == '+')
2381             {
2382               set = (c == '+');
2383             }
2384           else
2385             {
2386               showHerald ();
2387               voptgenerror (FLG_BADFLAG, 
2388                             message ("Bad flag syntax (+ or - expected, "
2389                                      "+ is assumed): %s", 
2390                                      cstring_fromChars (s)),
2391                             g_currentloc);
2392               s--;
2393               set = TRUE;
2394             }
2395           
2396           s++;
2397           incColumn ();
2398           
2399           thisflag = s;
2400           
2401           while ((c = *s) != '\0')
2402             { /* remember to handle spaces and quotes in -D and -U ... */
2403               if (escaped)
2404                 {
2405                   escaped = FALSE;
2406                 }
2407               else if (quoted)
2408                 {
2409                   if (c == '\\')
2410                     {
2411                       escaped = TRUE;
2412                     }
2413                   else if (c == '\"')
2414                     {
2415                       quoted = FALSE;
2416                     }
2417                   else
2418                     {
2419                       ;
2420                     }
2421                 }
2422               else if (c == '\"')
2423                 {
2424                   quoted = TRUE;
2425                 }
2426               else
2427                 {
2428                  if (c == ' ' || c == '\t' || c == '\n')
2429                    {
2430                      /*@innerbreak@*/ break;
2431                    }
2432                }
2433                   
2434               s++; 
2435               incColumn ();
2436             }
2437
2438           DPRINTF (("Nulling: %c", *s));
2439           *s = '\0';
2440
2441           if (mstring_isEmpty (thisflag))
2442             {
2443               llfatalerror (message ("Missing flag: %s",
2444                                      cstring_fromChars (os)));
2445             }
2446
2447           DPRINTF (("Flag: %s", thisflag));
2448
2449           opt = flags_identifyFlag (cstring_fromChars (thisflag));
2450           
2451           if (flagcode_isSkip (opt))
2452             {
2453               ;
2454             }
2455           else if (flagcode_isInvalid (opt))
2456             {
2457               DPRINTF (("Invalid: %s", thisflag));
2458
2459               if (isMode (cstring_fromChars (thisflag)))
2460                 {
2461                   context_setMode (cstring_fromChars (thisflag));
2462                 }
2463               else
2464                 {
2465                   voptgenerror (FLG_BADFLAG,
2466                                 message ("Unrecognized option: %s", 
2467                                          cstring_fromChars (thisflag)),
2468                                 g_currentloc);
2469                 }
2470             }
2471           else
2472             {
2473               context_userSetFlag (opt, set);
2474
2475               if (flagcode_hasArgument (opt))
2476                 {
2477                   if (opt == FLG_HELP)
2478                     {
2479                       showHerald ();
2480                       voptgenerror (FLG_BADFLAG,
2481                                     message ("Cannot use help in rc files"),
2482                                     g_currentloc);
2483                     }
2484                   else if (flagcode_isPassThrough (opt)) /* -D or -U */
2485                     {
2486                       cstring arg = cstring_fromCharsNew (thisflag);
2487                       cstring_markOwned (arg);
2488                       *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2489                       DPRINTF (("Pass through: %s",
2490                                 cstringSList_unparse (*passThroughArgs)));
2491                     }
2492                   else if (opt == FLG_INCLUDEPATH 
2493                            || opt == FLG_SPECPATH)
2494                     {
2495                       cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2496                                       
2497                       switch (opt)
2498                         {
2499                         case FLG_INCLUDEPATH:
2500                           cppAddIncludeDir (dir);
2501                           /*@switchbreak@*/ break;
2502                         case FLG_SPECPATH:
2503                           /*@-mustfree@*/
2504                           g_localSpecPath = cstring_toCharsSafe
2505                             (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2506                           /*@=mustfree@*/
2507                           /*@switchbreak@*/ break;
2508                           BADDEFAULT;
2509                         }
2510                     }
2511                   else if (flagcode_hasString (opt)
2512                            || flagcode_hasNumber (opt)
2513                            || flagcode_hasChar (opt)
2514                            || opt == FLG_INIT || opt == FLG_OPTF)
2515                     {
2516                       cstring extra = cstring_undefined;
2517                       char *rest, *orest;
2518                       char rchar;
2519                       
2520                       *s = c;
2521                       rest = mstring_copy (s);
2522                       DPRINTF (("Here: rest = %s", rest));
2523                       orest = rest;
2524                       *s = '\0';
2525                       
2526                       while ((rchar = *rest) != '\0'
2527                              && (isspace ((int) rchar)))
2528                         {
2529                           rest++;
2530                           s++;
2531                         }
2532                       
2533                       DPRINTF (("Yo: %s", rest));
2534
2535                       while ((rchar = *rest) != '\0' 
2536                              && !isspace ((int) rchar))
2537                         {
2538                           extra = cstring_appendChar (extra, rchar);
2539                           rest++; 
2540                           s++;
2541                         }
2542                       
2543                       DPRINTF (("Yo: %s", extra));
2544                       sfree (orest);
2545
2546                       if (cstring_isUndefined (extra))
2547                         {
2548                           showHerald ();
2549                           voptgenerror 
2550                             (FLG_BADFLAG,
2551                              message
2552                              ("Flag %s must be followed by an argument",
2553                               flagcode_unparse (opt)),
2554                              g_currentloc);
2555                         }
2556                       else
2557                         {
2558                           s--;
2559                           
2560                           DPRINTF (("Here we are: %s", extra));
2561
2562                           if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2563                             {
2564                               DPRINTF (("Set value flag: %s", extra));
2565                               setValueFlag (opt, extra);
2566                             }
2567                           else if (opt == FLG_OPTF)
2568                             {
2569                               (void) readOptionsFile (extra, passThroughArgs, TRUE);
2570                             }
2571                           else if (opt == FLG_INIT)
2572                             {
2573 # ifndef NOLCL
2574                               llassert (inputStream_isUndefined (initFile));
2575                               
2576                               initFile = inputStream_create 
2577                                 (cstring_copy (extra), 
2578                                  cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2579                                  FALSE);
2580 # endif
2581                             }
2582                           else if (flagcode_hasString (opt))
2583                             {
2584                               DPRINTF (("Here: %s", extra));
2585
2586                               /*
2587                               ** If it has "'s, we need to remove them.
2588                               */
2589
2590                               if (cstring_firstChar (extra) == '\"')
2591                                 {
2592                                   if (cstring_lastChar (extra) == '\"')
2593                                     {
2594                                       cstring unquoted = cstring_copyLength 
2595                                         (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2596                                          cstring_length (extra) - 2);
2597
2598                                       DPRINTF (("string flag: %s -> %s", extra, unquoted));
2599                                       setStringFlag (opt, unquoted);
2600                                       cstring_free (extra);
2601                                     }
2602                                   else
2603                                     {
2604                                       voptgenerror
2605                                         (FLG_BADFLAG, 
2606                                          message ("Unmatched \" in option string: %s", 
2607                                                   extra),
2608                                          g_currentloc);
2609                                       setStringFlag (opt, extra);
2610                                     }
2611                                 }
2612                               else
2613                                 {
2614                                   DPRINTF (("No quotes: %s", extra));
2615                                   setStringFlag (opt, extra);
2616                                 }
2617
2618                               extra = cstring_undefined;
2619                             }
2620                           else
2621                             {
2622                               BADEXIT;
2623                             }
2624                         }
2625
2626                       cstring_free (extra); 
2627                     }
2628                   else
2629                     {
2630                       BADEXIT;
2631                     }
2632                 }
2633             }
2634           
2635           *s = c;
2636           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2637           while ((c == ' ') || (c == '\t'))
2638             {
2639               c = *(++s);
2640               incColumn ();
2641             } 
2642         }
2643       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2644       s = os;
2645     }
2646
2647   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2648   sfree (os); 
2649   check (fileTable_closeFile (context_fileTable (), rcfile));
2650 }
2651
2652 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2653   /*@modifies fileSystem@*/
2654 {
2655   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2656   int skip = (fileIdList_size (fl) / 5);
2657   int filesprocessed = 0;
2658   fileIdList dfiles = fileIdList_create ();
2659
2660   fileloc_free (g_currentloc);
2661   g_currentloc = fileloc_createBuiltin ();
2662
2663   fileIdList_elements (fl, fid)
2664     {
2665       cstring ppfname = fileTable_fileName (fid);
2666
2667       if (!(osd_fileIsReadable (ppfname)))
2668         {
2669           lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2670           ppfname = cstring_undefined;
2671         }
2672
2673       if (cstring_isDefined (ppfname))
2674         {
2675           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2676
2677           if (xhfiles)
2678             {
2679               llassert (fileTable_isXHFile (context_fileTable (), dfile));
2680             }
2681
2682           llassert (cstring_isNonEmpty (ppfname));
2683           
2684           if (msg)
2685             {
2686               if ((filesprocessed % skip) == 0) 
2687                 {
2688                   if (filesprocessed == 0) {
2689                     fprintf (stderr, " ");
2690                   }
2691                   else {
2692                     fprintf (stderr, ".");
2693                   }
2694                   
2695                   (void) fflush (stderr);
2696                 }
2697               filesprocessed++;
2698             }
2699
2700           DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2701
2702           if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) 
2703             {
2704               llfatalerror (message ("Preprocessing error for file: %s", 
2705                                      fileTable_rootFileName (fid)));
2706             }
2707           
2708           fileIdList_add (dfiles, dfile);
2709         }
2710     } end_fileIdList_elements; 
2711     
2712     return dfiles;
2713 }
2714
2715 /* This should be in an lclUtils.c file... */
2716 # ifndef NOLCL
2717 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2718 {
2719   /* extract the path and the specname associated with the given file */
2720   char *specname = (char *) dmalloc (sizeof (*specname) 
2721                                      * (strlen (specfile) + 9));
2722   char *ospecname = specname;
2723   char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2724   size_t size;
2725   long int i, j;
2726   
2727   /* initialized path to empty string or may have accidental garbage */
2728   *path = '\0';
2729
2730   /*@-mayaliasunique@*/ 
2731   strcpy (specname, specfile);
2732   /*@=mayaliasunique@*/ 
2733
2734   /* trim off pathnames in specfile */
2735   size = strlen (specname);
2736
2737   for (i = size_toInt (size) - 1; i >= 0; i--)
2738     {
2739       if (specname[i] == CONNECTCHAR)
2740         {
2741           /* strcpy (specname, (char *)specname+i+1); */
2742           for (j = 0; j <= i; j++)      /* include '/'  */
2743             {
2744               path[j] = specname[j];
2745             }
2746
2747           path[i + 1] = '\0';
2748           specname += i + 1;
2749           break;
2750         }
2751     }
2752
2753   /* 
2754   ** also remove .lcl file extension, assume it's the last extension
2755   ** of the file name 
2756   */
2757
2758   size = strlen (specname);
2759
2760   for (i = size_toInt (size) - 1; i >= 0; i--)
2761     {
2762       if (specname[i] == '.')
2763         {
2764           specname[i] = '\0';
2765           break;
2766         }
2767     }
2768   
2769   *inpath = path;
2770
2771   /*
2772   ** If specname no longer points to the original char,
2773   ** we need to allocate a new pointer and copy the string.
2774   */
2775
2776   if (specname != ospecname) {
2777     char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2778     strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2779     sfree (ospecname);
2780     return rspecname;
2781   } 
2782
2783   return specname;
2784 }
2785 # endif
2786
2787 void warnSysFiles(fileIdList files)
2788 {
2789   fileIdList_elements (files, file)
2790     {
2791       
2792       if (fileTable_isSystemFile (context_fileTable (), file) )
2793         {
2794           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);
2795         }
2796     } 
2797   end_fileIdList_elements;
2798 }
This page took 0.253074 seconds and 5 git commands to generate.