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