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