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