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