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