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