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