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