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