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