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