]> andersk Git - splint.git/blob - src/llmain.c
Fixed handling of octal constants.
[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 /*
2181 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2182 */
2183
2184 void
2185 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2186    /*@ensures closed rcfile@*/
2187 {
2188   char *s = mstring_create (MAX_LINE_LENGTH);
2189   char *os = s;
2190
2191   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2192
2193   s = os;
2194
2195   while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2196     {
2197       char c;
2198       bool set = FALSE;     
2199       char *thisflag;
2200       flagcode opt;
2201
2202       DPRINTF (("Line: %s", s));
2203       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2204             
2205       while (*s == ' ' || *s == '\t')
2206         {
2207           s++;
2208           incColumn ();
2209         }
2210       
2211       while (*s != '\0')
2212         {
2213           bool escaped = FALSE;
2214           bool quoted = FALSE;
2215           c = *s;
2216
2217           DPRINTF (("Process: %s", s));
2218           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2219           /* comment characters */
2220           if (c == '#' || c == ';' || c == '\n') 
2221             {
2222               /*@innerbreak@*/
2223               break;
2224             }
2225           
2226           if (c == '-' || c == '+')
2227             {
2228               set = (c == '+');
2229             }
2230           else
2231             {
2232               showHerald ();
2233               voptgenerror (FLG_BADFLAG, 
2234                             message ("Bad flag syntax (+ or - expected, "
2235                                      "+ is assumed): %s", 
2236                                      cstring_fromChars (s)),
2237                             g_currentloc);
2238               s--;
2239               set = TRUE;
2240             }
2241           
2242           s++;
2243           incColumn ();
2244           
2245           thisflag = s;
2246           
2247           while ((c = *s) != '\0')
2248             { /* remember to handle spaces and quotes in -D and -U ... */
2249               if (escaped)
2250                 {
2251                   escaped = FALSE;
2252                 }
2253               else if (quoted)
2254                 {
2255                   if (c == '\\')
2256                     {
2257                       escaped = TRUE;
2258                     }
2259                   else if (c == '\"')
2260                     {
2261                       quoted = FALSE;
2262                     }
2263                   else
2264                     {
2265                       ;
2266                     }
2267                 }
2268               else if (c == '\"')
2269                 {
2270                   quoted = TRUE;
2271                 }
2272               else
2273                 {
2274                  if (c == ' ' || c == '\t' || c == '\n')
2275                    {
2276                      /*@innerbreak@*/ break;
2277                    }
2278                }
2279                   
2280               s++; 
2281               incColumn ();
2282             }
2283
2284           DPRINTF (("Nulling: %c", *s));
2285           *s = '\0';
2286
2287           if (mstring_isEmpty (thisflag))
2288             {
2289               llfatalerror (message ("Missing flag: %s",
2290                                      cstring_fromChars (os)));
2291             }
2292
2293           DPRINTF (("Flag: %s", thisflag));
2294
2295           opt = identifyFlag (cstring_fromChars (thisflag));
2296           
2297           if (flagcode_isSkip (opt))
2298             {
2299               ;
2300             }
2301           else if (flagcode_isInvalid (opt))
2302             {
2303               DPRINTF (("Invalid: %s", thisflag));
2304
2305               if (isMode (cstring_fromChars (thisflag)))
2306                 {
2307                   context_setMode (cstring_fromChars (thisflag));
2308                 }
2309               else
2310                 {
2311                   voptgenerror (FLG_BADFLAG,
2312                                 message ("Unrecognized option: %s", 
2313                                          cstring_fromChars (thisflag)),
2314                                 g_currentloc);
2315                 }
2316             }
2317           else
2318             {
2319               context_userSetFlag (opt, set);
2320
2321               if (flagcode_hasArgument (opt))
2322                 {
2323                   if (opt == FLG_HELP)
2324                     {
2325                       showHerald ();
2326                       voptgenerror (FLG_BADFLAG,
2327                                     message ("Cannot use help in rc files"),
2328                                     g_currentloc);
2329                     }
2330                   else if (flagcode_isPassThrough (opt)) /* -D or -U */
2331                     {
2332                       cstring arg = cstring_fromCharsNew (thisflag);
2333                       cstring_markOwned (arg);
2334                       *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2335                       DPRINTF (("Pass through: %s",
2336                                 cstringSList_unparse (*passThroughArgs)));
2337                     }
2338                   else if (opt == FLG_INCLUDEPATH 
2339                            || opt == FLG_SPECPATH)
2340                     {
2341                       cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2342                                       
2343                       switch (opt)
2344                         {
2345                         case FLG_INCLUDEPATH:
2346                           cppAddIncludeDir (dir);
2347                           /*@switchbreak@*/ break;
2348                         case FLG_SPECPATH:
2349                           /*@-mustfree@*/
2350                           g_localSpecPath = cstring_toCharsSafe
2351                             (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2352                           /*@=mustfree@*/
2353                           /*@switchbreak@*/ break;
2354                           BADDEFAULT;
2355                         }
2356                     }
2357                   else if (flagcode_hasString (opt)
2358                            || flagcode_hasValue (opt)
2359                            || opt == FLG_INIT || opt == FLG_OPTF)
2360                     {
2361                       cstring extra = cstring_undefined;
2362                       char *rest, *orest;
2363                       char rchar;
2364                       
2365                       *s = c;
2366                       rest = mstring_copy (s);
2367                       DPRINTF (("Here: rest = %s", rest));
2368                       orest = rest;
2369                       *s = '\0';
2370                       
2371                       while ((rchar = *rest) != '\0'
2372                              && (isspace ((int) rchar)))
2373                         {
2374                           rest++;
2375                           s++;
2376                         }
2377                       
2378                       DPRINTF (("Yo: %s", rest));
2379
2380                       while ((rchar = *rest) != '\0' 
2381                              && !isspace ((int) rchar))
2382                         {
2383                           extra = cstring_appendChar (extra, rchar);
2384                           rest++; 
2385                           s++;
2386                         }
2387                       
2388                       DPRINTF (("Yo: %s", extra));
2389                       sfree (orest);
2390
2391                       if (cstring_isUndefined (extra))
2392                         {
2393                           showHerald ();
2394                           voptgenerror 
2395                             (FLG_BADFLAG,
2396                              message
2397                              ("Flag %s must be followed by an argument",
2398                               flagcode_unparse (opt)),
2399                              g_currentloc);
2400                         }
2401                       else
2402                         {
2403                           s--;
2404                           
2405                           DPRINTF (("Here we are: %s", extra));
2406
2407                           if (flagcode_hasValue (opt))
2408                             {
2409                               DPRINTF (("Set value flag: %s", extra));
2410                               setValueFlag (opt, extra);
2411                               cstring_free (extra);
2412                             }
2413                           else if (opt == FLG_OPTF)
2414                             {
2415                               FILE *innerf = fileTable_openFile (context_fileTable (), extra, "r");
2416                               cstring_markOwned (extra);
2417                               
2418                               if (innerf != NULL)
2419                                 {
2420                                   fileloc fc = g_currentloc;
2421                                   g_currentloc = fileloc_createRc (extra);
2422                                   loadrc (innerf, passThroughArgs);
2423                                   fileloc_reallyFree (g_currentloc);
2424                                   g_currentloc = fc;
2425                                 }
2426                               else 
2427                                 {
2428                                   showHerald ();
2429                                   voptgenerror
2430                                     (FLG_BADFLAG, 
2431                                      message ("Options file not found: %s", 
2432                                               extra),
2433                                      g_currentloc);
2434                                 }
2435                             }
2436                           else if (opt == FLG_INIT)
2437                             {
2438 # ifndef NOLCL
2439                               llassert (inputStream_isUndefined (initFile));
2440                               
2441                               initFile = inputStream_create 
2442                                 (extra, 
2443                                  cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2444                                  FALSE);
2445 # else
2446                               cstring_free (extra);
2447 # endif
2448                             }
2449                           else if (flagcode_hasString (opt))
2450                             {
2451                               if (cstring_firstChar (extra) == '\"')
2452                                 {
2453                                   if (cstring_lastChar (extra) == '\"')
2454                                     {
2455                                       char *extras = cstring_toCharsSafe (extra);
2456                                       
2457                                       llassert (extras[strlen(extras) - 1] == '\"');
2458                                       extras[strlen(extras) - 1] = '\0';
2459                                       extra = cstring_fromChars (extras + 1); 
2460                                       DPRINTF (("Remove quotes: %s", extra));
2461                                     }
2462                                   else
2463                                     {
2464                                       voptgenerror
2465                                         (FLG_BADFLAG, 
2466                                          message ("Unmatched \" in option string: %s", 
2467                                                   extra),
2468                                          g_currentloc);
2469                                     }
2470                                 }
2471                               
2472                               setStringFlag (opt, extra);
2473                             }
2474                           else
2475                             {
2476                               cstring_free (extra);
2477                               BADEXIT;
2478                             }
2479                         }
2480                     }
2481                   else
2482                     {
2483                       BADEXIT;
2484                     }
2485                 }
2486             }
2487           
2488           *s = c;
2489           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2490           while ((c == ' ') || (c == '\t'))
2491             {
2492               c = *(++s);
2493               incColumn ();
2494             } 
2495         }
2496       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2497       s = os;
2498     }
2499
2500   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2501   sfree (os); 
2502   check (fileTable_closeFile (context_fileTable (), rcfile));
2503 }
2504
2505 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2506   /*@modifies fileSystem@*/
2507 {
2508   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2509   int skip = (fileIdList_size (fl) / 5);
2510   int filesprocessed = 0;
2511   fileIdList dfiles = fileIdList_create ();
2512
2513   fileloc_free (g_currentloc);
2514   g_currentloc = fileloc_createBuiltin ();
2515
2516   fileIdList_elements (fl, fid)
2517     {
2518       cstring ppfname = fileName (fid);
2519
2520       if (xhfiles)
2521         {
2522           cstring fpath;
2523           
2524           if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2525             {
2526               if (cstring_equal (ppfname, fpath))
2527                 {
2528                   ;
2529                 }
2530               else
2531                 {
2532                   DPRINTF (("xh file: %s", fpath));
2533                   ppfname = fpath;
2534                   fileTable_setFilePath (context_fileTable (), fid, fpath);
2535                 }
2536             }
2537           else
2538             {
2539               lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2540               lldiagmsg (cstring_makeLiteral ("     Check LARCH_PATH environment variable."));
2541               ppfname = cstring_undefined;
2542             }
2543         }
2544       else
2545         {
2546           if (!(osd_fileIsReadable (ppfname)))
2547             {
2548               lldiagmsg (message ("Cannot open file: %s", ppfname));
2549               ppfname = cstring_undefined;
2550             }
2551         }
2552
2553       if (cstring_isDefined (ppfname))
2554         {
2555           fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2556           
2557           llassert (cstring_isNonEmpty (ppfname));
2558           
2559           if (msg)
2560             {
2561               if ((filesprocessed % skip) == 0) 
2562                 {
2563                   if (filesprocessed == 0) {
2564                     fprintf (stderr, " ");
2565                   }
2566                   else {
2567                     fprintf (stderr, ".");
2568                   }
2569                   
2570                   (void) fflush (stderr);
2571                 }
2572               filesprocessed++;
2573             }
2574
2575           if (cppProcess (ppfname, fileName (dfile)) != 0) 
2576             {
2577               llfatalerror (message ("Preprocessing error for file: %s", 
2578                                      rootFileName (fid)));
2579             }
2580           
2581           fileIdList_add (dfiles, dfile);
2582         }
2583     } end_fileIdList_elements; 
2584     
2585     return dfiles;
2586 }
2587
2588 /* This should be in an lclUtils.c file... */
2589 # ifndef NOLCL
2590 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2591 {
2592   /* extract the path and the specname associated with the given file */
2593   char *specname = (char *) dmalloc (sizeof (*specname) 
2594                                      * (strlen (specfile) + 9));
2595   char *ospecname = specname;
2596   char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2597   size_t size;
2598   long int i, j;
2599   
2600   /* initialized path to empty string or may have accidental garbage */
2601   *path = '\0';
2602
2603   /*@-mayaliasunique@*/ 
2604   strcpy (specname, specfile);
2605   /*@=mayaliasunique@*/ 
2606
2607   /* trim off pathnames in specfile */
2608   size = strlen (specname);
2609
2610   for (i = size_toInt (size) - 1; i >= 0; i--)
2611     {
2612       if (specname[i] == CONNECTCHAR)
2613         {
2614           /* strcpy (specname, (char *)specname+i+1); */
2615           for (j = 0; j <= i; j++)      /* include '/'  */
2616             {
2617               path[j] = specname[j];
2618             }
2619
2620           path[i + 1] = '\0';
2621           specname += i + 1;
2622           break;
2623         }
2624     }
2625
2626   /* 
2627   ** also remove .lcl file extension, assume it's the last extension
2628   ** of the file name 
2629   */
2630
2631   size = strlen (specname);
2632
2633   for (i = size_toInt (size) - 1; i >= 0; i--)
2634     {
2635       if (specname[i] == '.')
2636         {
2637           specname[i] = '\0';
2638           break;
2639         }
2640     }
2641   
2642   *inpath = path;
2643
2644   /*
2645   ** If specname no longer points to the original char,
2646   ** we need to allocate a new pointer and copy the string.
2647   */
2648
2649   if (specname != ospecname) {
2650     char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2651     strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2652     sfree (ospecname);
2653     return rspecname;
2654   } 
2655
2656   return specname;
2657 }
2658 # endif
This page took 0.24571 seconds and 5 git commands to generate.