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