Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

llmain.c

Go to the documentation of this file.
00001 /*
00002 ** LCLint - annotation-assisted static program checker
00003 ** Copyright (C) 1994-2000 University of Virginia,
00004 **         Massachusetts Institute of Technology
00005 **
00006 ** This program is free software; you can redistribute it and/or modify it
00007 ** under the terms of the GNU General Public License as published by the
00008 ** Free Software Foundation; either version 2 of the License, or (at your
00009 ** option) any later version.
00010 ** 
00011 ** This program is distributed in the hope that it will be useful, but
00012 ** WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 ** General Public License for more details.
00015 ** 
00016 ** The GNU General Public License is available from http://www.gnu.org/ or
00017 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018 ** MA 02111-1307, USA.
00019 **
00020 ** For information on lclint: lclint-request@cs.virginia.edu
00021 ** To report a bug: lclint-bug@cs.virginia.edu
00022 ** For more information: http://lclint.cs.virginia.edu
00023 */
00024 /*
00025 ** llmain.c
00026 **
00027 ** Main module for LCLint checker
00028 */
00029 
00030 # include <signal.h>
00031 
00032 /*
00033 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
00034 */
00035 
00036 # ifdef WIN32
00037 # ifndef _WIN32
00038 # error "Inconsistent definitions."
00039 # endif
00040 # else
00041 # ifdef _WIN32
00042 # error "Inconsistent definitions."
00043 # endif
00044 # endif
00045 
00046 # ifdef WIN32
00047 # include <windows.h>
00048 # include <process.h>
00049 # endif
00050 
00051 # include "lclintMacros.nf"
00052 # include "llbasic.h"
00053 # include "osd.h"
00054 
00055 # ifndef NOLCL
00056 # include "gram.h"
00057 # include "lclscan.h"
00058 # include "scanline.h"
00059 # include "lclscanline.h"
00060 # include "lclsyntable.h"
00061 # include "lcltokentable.h"
00062 # include "lslparse.h"
00063 # include "scan.h"
00064 # include "syntable.h"
00065 # include "tokentable.h"
00066 # include "lslinit.h"
00067 # include "lclinit.h"
00068 # include "lh.h"
00069 # include "imports.h"
00070 # endif
00071 
00072 # include "version.h"
00073 # include "herald.h"
00074 # include "fileIdList.h"
00075 # include "lcllib.h"
00076 # include "cgrammar.h"
00077 # include "llmain.h"
00078 # include "portab.h"
00079 # include "cpp.h"
00080 # include <time.h>
00081 
00082 extern /*@external@*/ int yydebug;
00083 
00084 static void printMail (void);
00085 static void printMaintainer (void);
00086 static void printReferences (void);
00087 static void printFlags (void);
00088 static void printAnnotations (void);
00089 static void printParseErrors (void);
00090 static void printComments (void);
00091 static void describePrefixCodes (void);
00092 static void cleanupFiles (void);
00093 static void showHelp (void);
00094 static void interrupt (int p_i);
00095 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs);
00096 static void describeVars (void);
00097 static bool specialFlagsHelp (char *p_next);
00098 static bool hasShownHerald = FALSE;
00099 
00100 static bool anylcl = FALSE;
00101 static clock_t inittime;
00102 
00103 static /*@only@*/ /*@null@*/ tsource *initFile = (tsource *) 0;
00104 
00105 static fileIdList preprocessFiles (fileIdList)
00106   /*@modifies fileSystem@*/ ;
00107 
00108 # ifndef NOLCL
00109 
00110 static
00111 void lslCleanup (void)
00112    /*@globals killed g_symtab@*/
00113    /*@modifies internalState, g_symtab@*/
00114 {
00115   /*
00116   ** Cleanup all the LCL/LSL.
00117   */
00118 
00119   static bool didCleanup = FALSE;
00120 
00121   llassert (!didCleanup);
00122   llassert (anylcl);
00123 
00124   didCleanup = TRUE;
00125 
00126   lsymbol_destroyMod ();
00127   LCLSynTableCleanup ();
00128   LCLTokenTableCleanup ();
00129   LCLScanLineCleanup ();
00130   LCLScanCleanup ();
00131 
00132   /* clean up LSL parsing */
00133 
00134   lsynTableCleanup ();
00135   ltokenTableCleanup ();
00136   lscanLineCleanup ();
00137   LSLScanCleanup ();
00138 
00139   symtable_free (g_symtab);
00140   sort_destroyMod (); 
00141 }
00142 
00143 static
00144   void lslInit (void)
00145   /*@globals undef g_symtab; @*/
00146   /*@modifies g_symtab, internalState, fileSystem; @*/
00147 {
00148   /*
00149   ** Open init file provided by user, or use the default LCL init file 
00150   */
00151   
00152   cstring larchpath = context_getLarchPath ();
00153   tsource *LSLinitFile = (tsource *) 0;
00154 
00155   setCodePoint ();
00156 
00157   if (initFile == (tsource *) 0)
00158     {
00159       initFile = tsource_create (INITFILENAME, LCLINIT_SUFFIX, FALSE);
00160       
00161       if (!tsource_getPath (cstring_toCharsSafe (larchpath), initFile))
00162         {
00163           lldiagmsg (message ("Continuing without LCL init file: %s",
00164                               cstring_fromChars (tsource_fileName (initFile))));
00165         }
00166       else 
00167         {
00168           if (!tsource_open (initFile))
00169             {
00170               lldiagmsg (message ("Continuing without LCL init file: %s",
00171                                   cstring_fromChars (tsource_fileName (initFile))));
00172             }
00173         }
00174     }
00175   else 
00176     {
00177       if (!tsource_open (initFile))
00178         {
00179           lldiagmsg (message ("Continuing without LCL init file: %s",
00180                               cstring_fromChars (tsource_fileName (initFile))));
00181         }
00182     }
00183 
00184   /* Initialize checker */
00185 
00186   lsymbol_initMod ();
00187   LCLSynTableInit ();
00188 
00189   setCodePoint ();
00190 
00191   LCLSynTableReset ();
00192   LCLTokenTableInit ();
00193 
00194   setCodePoint ();
00195 
00196   LCLScanLineInit ();
00197   setCodePoint ();
00198   LCLScanLineReset ();
00199   setCodePoint ();
00200   LCLScanInit ();
00201 
00202   setCodePoint ();
00203 
00204   /* need this to initialize LCL checker */
00205   llassert (initFile != NULL);
00206       
00207   if (tsource_isOpen (initFile))
00208     {
00209       setCodePoint ();
00210 
00211       LCLScanReset (initFile);
00212       LCLProcessInitFileInit ();
00213       LCLProcessInitFileReset ();
00214 
00215       setCodePoint ();
00216       LCLProcessInitFile ();
00217       LCLProcessInitFileCleanup ();
00218 
00219       setCodePoint ();
00220       check (tsource_close (initFile));
00221     }
00222   
00223   /* Initialize LSL init files, for parsing LSL signatures from LSL */
00224   
00225   LSLinitFile = tsource_create ("lslinit.lsi", ".lsi", FALSE);
00226   
00227   if (!tsource_getPath (cstring_toCharsSafe (larchpath), LSLinitFile))
00228     {
00229       lldiagmsg (message ("Continuing without LSL init file: %s",
00230                           cstring_fromChars (tsource_fileName (LSLinitFile))));
00231     }
00232   else 
00233     {
00234       if (!tsource_open (LSLinitFile))
00235         {
00236           lldiagmsg (message ("Continuing without LSL init file: %s",
00237                               cstring_fromChars (tsource_fileName (LSLinitFile))));
00238         }
00239     }
00240       
00241   setCodePoint ();
00242   lsynTableInit ();
00243   lsynTableReset ();
00244 
00245   setCodePoint ();
00246   ltokenTableInit ();
00247 
00248   setCodePoint ();
00249   lscanLineInit ();
00250   lscanLineReset ();
00251   LSLScanInit ();
00252 
00253   if (tsource_isOpen (LSLinitFile))
00254     {
00255       setCodePoint ();
00256       LSLScanReset (LSLinitFile);
00257       LSLProcessInitFileInit ();
00258       setCodePoint ();
00259       LSLProcessInitFile ();
00260       setCodePoint ();
00261       check (tsource_close (LSLinitFile));
00262     }
00263       
00264   tsource_free (LSLinitFile);
00265   
00266   if (lclHadError ())
00267     {
00268       lclplainerror 
00269         (cstring_makeLiteral ("LSL init file error.  Attempting to continue."));
00270     }
00271   
00272   setCodePoint ();
00273   g_symtab = symtable_new ();
00274   
00275   /* 
00276   ** sort_init must come after symtab has been initialized 
00277   */
00278   sort_init ();
00279   abstract_init ();
00280   setCodePoint ();
00281   
00282   inittime = clock ();
00283   
00284   /* 
00285   ** Equivalent to importing old spec_csupport.lcl
00286   ** define immutable LCL type "bool" and bool constants TRUE and FALSE
00287   ** and initialized them to be equal to LSL's "true" and "false".
00288   **
00289   ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
00290   */
00291       
00292   LCLBuiltins (); 
00293   LCLReportEolTokens (FALSE);
00294 }
00295 
00296 static void
00297 lslProcess (fileIdList lclfiles)
00298    /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
00299               undef killed g_symtab; @*/
00300    /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
00301 {
00302   char *path = NULL;
00303   bool parser_status = FALSE;
00304   bool overallStatus = FALSE;
00305   
00306   lslInit ();
00307   
00308   context_resetSpecLines ();
00309 
00310   fileIdList_elements (lclfiles, fid)
00311     {
00312       char *actualName = (char *) dmalloc (sizeof (*actualName));
00313       char *oactualName = actualName;
00314       char *fname = cstring_toCharsSafe (fileName (fid));
00315       
00316       if (osd_getPath (g_localSpecPath, fname, &actualName) == OSD_FILENOTFOUND)
00317         {
00318           if (mstring_equal (g_localSpecPath, "."))
00319             {
00320               lldiagmsg (message ("Spec file not found: %s",
00321                                   cstring_fromChars (fname)));
00322             }
00323           else
00324             {
00325               lldiagmsg (message ("Spec file not found: %s (on %s)", 
00326                                   cstring_fromChars (fname), 
00327                                   cstring_fromChars (g_localSpecPath)));
00328             }
00329         }
00330       else
00331         {
00332           tsource *specFile;
00333           
00334           while (*actualName == '.' && *(actualName + 1) == CONNECTCHAR) 
00335             {
00336               actualName += 2;
00337             }
00338           
00339           specFile = tsource_create (actualName, LCL_SUFFIX, TRUE);
00340           llassert (specFile != (tsource *) 0);
00341           
00342           g_currentSpec = cstring_fromChars (mstring_copy (actualName));
00343 
00344           g_currentSpecName = specFullName 
00345             (cstring_toCharsSafe (g_currentSpec),
00346              &path);
00347 
00348           setSpecFileId (fid);
00349                   
00350           if (context_getFlag (FLG_SHOWSCAN))
00351             {
00352               lldiagmsg (message ("< reading spec %s >", g_currentSpec));
00353             }
00354           
00355           /* Open source file */
00356           
00357           if (!tsource_open (specFile))
00358             {
00359               lldiagmsg (message ("Cannot open file: %s",
00360                                   cstring_fromChars (tsource_fileName (specFile))));
00361               tsource_free (specFile);
00362             }
00363           else
00364             {
00365               scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
00366               dummy_scope->kind = SPE_INVALID;
00367               
00368               lhInit (specFile);
00369               LCLScanReset (specFile);
00370               
00371               /* 
00372               ** Minor hacks to allow more than one LCL file to
00373               ** be scanned, while keeping initializations
00374               */
00375               
00376               symtable_enterScope (g_symtab, dummy_scope);
00377               resetImports (cstring_fromChars (g_currentSpecName));
00378               context_enterLCLfile ();
00379               (void) lclHadNewError ();
00380               
00381               parser_status = (ylparse () != 0);
00382               context_exitLCLfile ();
00383               lhCleanup ();
00384               overallStatus = parser_status || lclHadNewError (); 
00385 
00386               if (context_getFlag (FLG_DOLCS))
00387                 {
00388                   if (overallStatus)
00389                     {
00390                       outputLCSFile (path, "%%FAILED Output from ",
00391                                      g_currentSpecName);
00392                     }
00393                   else
00394                     {
00395                       outputLCSFile (path, "%%PASSED Output from ", 
00396                                      g_currentSpecName);
00397                     }
00398                 }
00399 
00400               (void) tsource_close (specFile);
00401               tsource_free (specFile);
00402 
00403               symtable_exitScope (g_symtab);
00404             }
00405         }
00406       
00407       sfree (oactualName);
00408     } end_fileIdList_elements; 
00409   
00410     /* Can cleanup lsl stuff right away */
00411 
00412       lslCleanup ();
00413   
00414   g_currentSpec = cstring_undefined;
00415   g_currentSpecName = NULL;
00416 }
00417 # endif
00418 
00419 static void handlePassThroughFlag (char *arg)
00420 {
00421   char *curarg = arg;
00422   char *quotechar = strchr (curarg, '\"');
00423   int offset = 0;
00424   bool open = FALSE;
00425 
00426   while (quotechar != NULL)
00427     {
00428       if (*(quotechar - 1) == '\\')
00429         {
00430           char *tp = quotechar - 2;
00431           bool escape = TRUE;
00432 
00433           while (*tp == '\\')
00434             {
00435               escape = !escape;
00436               tp--;
00437             }
00438           
00439           if (escape)
00440             {
00441               curarg = quotechar + 1;
00442               quotechar = strchr (curarg, '\"');
00443               continue;
00444             }
00445         }
00446       
00447       *quotechar = '\0';
00448       offset = (quotechar - arg) + 2;
00449       
00450       if (open)
00451         {
00452           arg = cstring_toCharsSafe
00453             (message ("%s\"\'%s", 
00454                       cstring_fromChars (arg), 
00455                       cstring_fromChars (quotechar + 1))); 
00456           open = FALSE;
00457         }
00458       else
00459         {
00460           arg = cstring_toCharsSafe
00461             (message ("%s\'\"%s", 
00462                       cstring_fromChars (arg), 
00463                       cstring_fromChars (quotechar + 1)));
00464           open = TRUE;
00465         }
00466       
00467       curarg = arg + offset;
00468       quotechar = strchr (curarg, '\"');
00469     }
00470 
00471   if (open)
00472     {
00473       showHerald ();
00474       llerror (FLG_BADFLAG,
00475                message ("Unclosed quote in flag: %s",
00476                         cstring_fromChars (arg)));
00477     }
00478   else
00479     {
00480       if (arg[0] == 'D') {
00481         cstring def;
00482         
00483         /* 
00484         ** If the value is surrounded by single quotes ('), remove
00485         ** them.  This is an artifact of UNIX command line?
00486         */
00487 
00488         def = osd_fixDefine (arg + 1);
00489         DPRINTF (("Do define: %s", def));
00490         cppDoDefine (def);
00491         DPRINTF (("After define"));
00492         cstring_free (def);
00493       } else if (arg[0] == 'U') {
00494         cppDoUndefine (cstring_fromChars (arg + 1));
00495       } else {
00496         BADBRANCH;
00497       }
00498     }
00499 }
00500 
00501 void showHerald (void)
00502 {
00503   if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
00504 
00505   else
00506     {
00507       fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
00508       hasShownHerald = TRUE;
00509       llflush ();
00510     }
00511 }
00512 
00513 static void addFile (fileIdList files, /*@only@*/ cstring s)
00514 {
00515   if (fileTable_exists (context_fileTable (), s))
00516     {
00517       showHerald ();
00518       lldiagmsg (message ("File listed multiple times: %s", s));
00519       cstring_free (s);
00520     }
00521   else
00522     {
00523       fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
00524     }
00525 }
00526 
00527 /*
00528 ** Disable MSVC++ warning about return value.  Methinks humbly lclint control
00529 ** comments are a mite more legible.
00530 */
00531 
00532 # ifdef WIN32
00533 # pragma warning (disable:4035) 
00534 # endif
00535 
00536 int main (int argc, char *argv[])
00537 # ifdef NOLCL
00538   /*@globals killed undef g_currentloc,
00539              killed undef yyin,
00540                     undef g_msgstream;
00541    @*/
00542   /*@modifies g_currentloc, fileSystem,
00543               yyin; 
00544   @*/
00545 # else
00546   /*@globals killed undef g_currentloc,
00547              killed undef initFile,
00548              killed       g_localSpecPath,  
00549              killed undef g_currentSpec,
00550              killed undef g_currentSpecName,
00551              killed undef yyin,
00552                     undef g_msgstream;
00553    @*/
00554   /*@modifies g_currentloc, initFile, 
00555               g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
00556               yyin; 
00557   @*/
00558 # endif
00559 {
00560   bool first_time = TRUE;
00561   bool showhelp = FALSE;
00562   bool allhelp = TRUE;
00563   bool expsuccess;
00564   tsource *sourceFile = (tsource *) 0;
00565  
00566   fileIdList dercfiles;
00567   cstringSList fl = cstringSList_undefined;
00568   cstringSList passThroughArgs = cstringSList_undefined;
00569   fileIdList cfiles;
00570   fileIdList lclfiles;
00571   clock_t before, lcltime, libtime, pptime, cptime, rstime;
00572   int i = 0;
00573 
00574   g_msgstream = stdout;
00575 
00576   (void) signal (SIGINT, interrupt);
00577   (void) signal (SIGSEGV, interrupt); 
00578 
00579   cfiles = fileIdList_create ();
00580   lclfiles = fileIdList_create ();
00581 
00582   flags_initMod ();
00583   typeIdSet_initMod ();
00584   cppReader_initMod ();
00585 
00586   setCodePoint ();
00587 
00588   g_currentloc = fileloc_createBuiltin ();
00589 
00590   before = clock ();
00591   context_initMod ();
00592   context_setInCommandLine ();
00593 
00594   if (argc <= 1)
00595     {
00596       showHelp ();
00597       llexit (LLGIVEUP);
00598     }
00599 
00600   setCodePoint ();
00601   yydebug = 0;
00602 
00603   /*
00604   ** Add include directories from environment.
00605   */
00606 
00607   {
00608     char *incval = mstring_copy (osd_getEnvironmentVariable (INCLUDE_VAR));
00609 
00610     if (incval != NULL)
00611       {
00612         /*
00613         ** Each directory on the include path is a system include directory.
00614         */
00615 
00616         DPRINTF (("include: %s", incval));
00617         context_setString (FLG_SYSTEMDIRS, cstring_fromCharsNew (incval));
00618 
00619         while (incval != NULL)
00620           {
00621             char *nextsep = strchr (incval, SEPCHAR);
00622 
00623             if (nextsep != NULL)
00624               {
00625                 cstring dir;
00626                 *nextsep = '\0';
00627                 dir = cstring_fromCharsNew (incval);
00628 
00629                 if (cstring_length (dir) == 0
00630                     || !isalpha ((int) cstring_firstChar (dir)))
00631                   {
00632                     /* 
00633                     ** win32 environment values can have special values,
00634                     ** ignore them
00635                     */
00636                   }
00637                 else
00638                   {
00639                     DPRINTF (("Add include: %s", dir));
00640                     cppAddIncludeDir (dir);
00641                   }
00642 
00643                 *nextsep = SEPCHAR;
00644                 incval = nextsep + 1;
00645                 cstring_free (dir);
00646               }
00647             else
00648               {
00649                 break;
00650               }
00651           }
00652       }
00653   }
00654 
00655   /*
00656   ** check RCFILE for default flags
00657   */
00658 
00659   {
00660     cstring home = cstring_fromChars (osd_getHomeDir ());
00661     char *fname  = NULL;
00662     FILE *rcfile;
00663     bool defaultf = TRUE;
00664     bool nof = FALSE;
00665 
00666     for (i = 1; i < argc; i++)
00667       {
00668         char *thisarg;
00669         thisarg = argv[i];
00670         
00671         if (*thisarg == '-' || *thisarg == '+')
00672           {
00673             thisarg++;
00674 
00675             if (mstring_equal (thisarg, "nof"))
00676               {
00677                 nof = TRUE;
00678               }
00679             else if (mstring_equal (thisarg, "f"))
00680               {
00681                 if (++i < argc)
00682                   {
00683                     defaultf = FALSE;
00684                     fname = argv[i];
00685                     rcfile = fopen (fname, "r");
00686 
00687                     if (rcfile != NULL)
00688                       {
00689                         fileloc oloc = g_currentloc;
00690                         
00691                         g_currentloc = fileloc_createRc (cstring_fromChars (fname));
00692                         loadrc (rcfile, &passThroughArgs);
00693                         fileloc_reallyFree (g_currentloc); 
00694                         g_currentloc = oloc;
00695                       }
00696                     else 
00697                       {
00698                         showHerald ();
00699                         lldiagmsg (message ("Options file not found: %s", 
00700                                             cstring_fromChars (fname)));
00701                       }
00702                   }
00703                 else
00704                   llfatalerror
00705                     (cstring_makeLiteral ("Flag f to select options file "
00706                                           "requires an argument"));
00707               }
00708             else
00709               {
00710                 ; /* wait to process later */
00711               }
00712           }
00713       }
00714     
00715     if (fname == NULL)
00716       {
00717         if (!cstring_isEmpty (home)) {
00718           fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
00719                                                 cstring_fromChars (RCFILE)));
00720           mstring_markFree (fname);
00721         }
00722       }
00723 
00724     setCodePoint ();
00725 
00726     if (!nof && defaultf)
00727       {
00728         if (!mstring_isEmpty (fname)) {
00729           rcfile = fopen (fname, "r");
00730           
00731           if (rcfile != NULL)
00732             {
00733               fileloc oloc = g_currentloc;
00734               
00735               g_currentloc = fileloc_createRc (cstring_fromChars (fname));
00736               loadrc (rcfile, &passThroughArgs);
00737               fileloc_reallyFree (g_currentloc);
00738               g_currentloc = oloc;
00739             }
00740         }
00741 
00742 # if defined(MSDOS) || defined(OS2)
00743         fname = cstring_toCharsSafe (message ("%s",
00744                                               cstring_fromChars (RCFILE)));
00745 # else
00746         fname = cstring_toCharsSafe (message ("./%s", 
00747                                               cstring_fromChars (RCFILE)));
00748 # endif
00749 
00750         rcfile = fopen (fname, "r");
00751 
00752         if (rcfile != NULL)
00753           {
00754             fileloc oloc = g_currentloc;
00755 
00756             g_currentloc = fileloc_createRc (cstring_fromChars (fname));
00757             loadrc (rcfile, &passThroughArgs);
00758             fileloc_reallyFree (g_currentloc);
00759             g_currentloc = oloc;
00760           }
00761 
00762         sfree (fname); 
00763       }
00764   }
00765   
00766   setCodePoint ();
00767   
00768   for (i = 1; i < argc; i++)
00769     {
00770       char *thisarg;
00771       flagcode opt;
00772       
00773       thisarg = argv[i];
00774       
00775       if (showhelp)
00776         {
00777           if (allhelp)
00778             {
00779               showHerald ();
00780             }
00781           
00782           allhelp = FALSE;
00783           
00784           if (*thisarg == '-' || *thisarg == '+')
00785             {
00786               thisarg++;        /* skip '-' */
00787             }
00788           if (mstring_equal (thisarg, "modes"))
00789             {
00790               llmsg (describeModes ());
00791             }
00792           else if (mstring_equal (thisarg, "vars")
00793                    || mstring_equal (thisarg, "env"))
00794             {
00795               describeVars ();
00796             }
00797           else if (mstring_equal (thisarg, "annotations"))
00798             {
00799               printAnnotations ();
00800             }
00801           else if (mstring_equal (thisarg, "parseerrors"))
00802             {
00803               printParseErrors ();
00804             }
00805           else if (mstring_equal (thisarg, "comments"))
00806             {
00807               printComments ();
00808             }
00809           else if (mstring_equal (thisarg, "prefixcodes"))
00810             {
00811               describePrefixCodes ();
00812             }
00813           else if (mstring_equal (thisarg, "references") 
00814                    || mstring_equal (thisarg, "refs"))
00815             {
00816               printReferences ();
00817             }
00818           else if (mstring_equal (thisarg, "mail"))
00819             {
00820               printMail ();
00821             }
00822           else if (mstring_equal (thisarg, "maintainer")
00823                    || mstring_equal (thisarg, "version"))
00824             {
00825               printMaintainer ();
00826             }
00827           else if (mstring_equal (thisarg, "flags"))
00828             {
00829               if (i + 1 < argc)
00830                 {
00831                   char *next = argv[i + 1];
00832                   
00833                   if (specialFlagsHelp (next))
00834                     {
00835                       i++;
00836                     }
00837                   else
00838                     {
00839                       flagkind k = identifyCategory (cstring_fromChars (next));
00840                       
00841                       if (k != FK_NONE)
00842                         {
00843                           printCategory (k);
00844                           i++;
00845                         }
00846                     }
00847                 }
00848               else
00849                 {
00850                   printFlags ();
00851                 }
00852             }
00853           else
00854             {
00855               cstring s = describeFlag (cstring_fromChars (thisarg));
00856               
00857               if (cstring_isDefined (s))
00858                 {
00859                   llmsg (s);
00860                 }
00861             }
00862         }
00863       else
00864         {
00865           if (*thisarg == '-' || *thisarg == '+')
00866             {
00867               bool set = (*thisarg == '+');
00868               cstring flagname;
00869               
00870               thisarg++;        /* skip '-' */
00871               flagname = cstring_fromChars (thisarg);
00872               
00873               opt = identifyFlag (flagname);
00874               
00875               if (flagcode_isSkip (opt))
00876                 {
00877                   ;
00878                 }
00879               else if (flagcode_isInvalid (opt))
00880                 {
00881                   if (isMode (flagname))
00882                     {
00883                       context_setMode (flagname);
00884                     }
00885                   else
00886                     {
00887                       llgloberror (message ("Unrecognized option: %s", 
00888                                             cstring_fromChars (thisarg)));
00889                     }
00890                 }
00891               else
00892                 {
00893                   context_userSetFlag (opt, set);
00894                   
00895                   if (flagcode_hasArgument (opt))
00896                     {
00897                       if (opt == FLG_HELP)
00898                         {
00899                           showhelp = TRUE;
00900                         }
00901                       else if (flagcode_isPassThrough (opt)) /* -D or -U */
00902                         { 
00903                           passThroughArgs = cstringSList_add 
00904                             (passThroughArgs, cstring_fromChars (thisarg));
00905                         }
00906                       else if (flagcode_hasValue (opt))
00907                         {
00908                           if (++i < argc)
00909                             {
00910                               setValueFlag (opt, cstring_fromChars (argv[i]));
00911                             }
00912                           else
00913                             {
00914                               llfatalerror 
00915                                 (message
00916                                  ("Flag %s must be followed by a number",
00917                                   flagcode_unparse (opt)));
00918                             }
00919                         } 
00920                       else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
00921                         {
00922                           cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
00923                           
00924                           switch (opt)
00925                             {
00926                             case FLG_INCLUDEPATH:
00927                               cppAddIncludeDir (dir);
00928                               /*@switchbreak@*/ break;
00929                             case FLG_SPECPATH:
00930                               /*@-mustfree@*/
00931                               g_localSpecPath = cstring_toCharsSafe
00932                                 (message ("%s%h%s", 
00933                                           cstring_fromChars (g_localSpecPath), 
00934                                           SEPCHAR,
00935                                           dir));
00936                               /*@=mustfree@*/
00937                               /*@switchbreak@*/ break;
00938                               BADDEFAULT;
00939                             }
00940                         }
00941                       else if (flagcode_hasString (opt)
00942                                || opt == FLG_INIT || opt == FLG_OPTF)
00943                         {
00944                           if (++i < argc)
00945                             {
00946                               cstring arg = cstring_fromChars (argv[i]);
00947                               
00948                               if (opt == FLG_OPTF)
00949                                 {
00950                                   ; /* -f already processed */
00951                                 }
00952                               else if (opt == FLG_INIT)
00953                                 {
00954 # ifndef NOLCL
00955                                   initFile = tsource_create 
00956                                     (cstring_toCharsSafe (arg), 
00957                                      LCLINIT_SUFFIX, FALSE);
00958 # endif
00959                                   break;
00960                                 }
00961                               else
00962                                 {
00963                                   setStringFlag (opt, arg);
00964                                 }
00965                             }
00966                           else
00967                             {
00968                               llfatalerror 
00969                                 (message
00970                                  ("Flag %s must be followed by a string",
00971                                   flagcode_unparse (opt)));
00972                             }
00973                         }
00974                       else
00975                         {
00976                           /* no argument */
00977                         }
00978                     }
00979                 }
00980             }
00981           else /* its a filename */
00982             {
00983               fl = cstringSList_add (fl, cstring_fromChars (thisarg));
00984             }
00985         }
00986     }
00987 
00988   setCodePoint ();  
00989 
00990   /*
00991   ** create lists of C and LCL files
00992   */
00993 
00994   cstringSList_elements (fl, current)
00995     {
00996       char *fname = cstring_toCharsSafe (current);
00997       char *ext = strrchr (fname, '.');
00998 
00999       if (ext == NULL)
01000         {
01001           /* no extension --- both C and LCL with default extensions */
01002           
01003           addFile (cfiles, message ("%s.c", cstring_fromChars (fname)));
01004           addFile (lclfiles, message ("%s.lcl", cstring_fromChars (fname)));
01005         }
01006       else if (isCext (ext))
01007         {
01008           addFile (cfiles, cstring_fromCharsNew (fname));
01009         }
01010       else 
01011         {
01012           if (!mstring_equal (ext, ".lcl"))
01013             {
01014               lldiagmsg (message ("Unrecognized file extension: %s (assuming lcl)", 
01015                                   cstring_fromChars (ext)));
01016             }
01017 
01018           addFile (lclfiles, cstring_fromCharsNew (fname));
01019         }
01020     } end_cstringSList_elements;
01021   
01022   
01023   showHerald ();
01024 
01025   
01026   if (showhelp)
01027     {
01028       if (allhelp)
01029         {
01030           showHelp ();
01031         }
01032       fprintf (g_msgstream, "\n");
01033 
01034       fileIdList_free (cfiles);
01035       fileIdList_free (lclfiles);
01036       
01037       llexit (LLSUCCESS);
01038     }
01039 
01040 # ifdef DOANNOTS
01041   initAnnots ();
01042 # endif
01043 
01044   inittime = clock ();
01045 
01046   context_resetErrors ();
01047   context_clearInCommandLine ();
01048 
01049   anylcl = !fileIdList_isEmpty (lclfiles);
01050 
01051   if (context_doMerge ())
01052     {
01053       cstring m = context_getMerge ();
01054 
01055       if (context_getFlag (FLG_SHOWSCAN))
01056         {
01057           fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
01058         }
01059 
01060       loadState (m);
01061 
01062       if (context_getFlag (FLG_SHOWSCAN))
01063         {
01064           fprintf (g_msgstream, " >\n");
01065         }
01066 
01067       if (!usymtab_existsType (context_getBoolName ()))
01068         {
01069           usymtab_initBool (); 
01070         }
01071     }
01072   else
01073     {
01074       if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
01075         {
01076           ;
01077         }
01078       else
01079         {
01080           ctype_initTable ();
01081         }
01082 
01083       /* setup bool type and constants */
01084       usymtab_initBool (); 
01085     }
01086 
01087   fileloc_free (g_currentloc);
01088   g_currentloc = fileloc_createBuiltin ();
01089 
01090   libtime = clock ();
01091   
01092   if (anylcl)
01093     {
01094 # ifdef NOLCL
01095       llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
01096 # else
01097       lslProcess (lclfiles);
01098 # endif
01099     }
01100 
01101   /*
01102   ** pre-processing
01103   **
01104   ** call the pre-preprocessor and /lib/cpp to generate appropriate
01105   ** files
01106   **
01107   */
01108 
01109   context_setInCommandLine ();
01110 
01111   cppReader_initialize ();
01112 
01113   DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
01114   
01115   cstringSList_elements (passThroughArgs, thisarg) {
01116     handlePassThroughFlag (cstring_toCharsSafe (thisarg));
01117   } end_cstringSList_elements;
01118 
01119   cstringSList_free (passThroughArgs);
01120 
01121   cleanupMessages ();
01122 
01123   cppReader_saveDefinitions ();
01124   
01125   context_clearInCommandLine ();
01126 
01127   if (!context_getFlag (FLG_NOPP))
01128     {
01129       llflush ();
01130 
01131       if (context_getFlag (FLG_SHOWSCAN))
01132         {
01133           fprintf (stderr, "< preprocessing"); 
01134         }
01135       
01136       lcltime = clock ();
01137 
01138       context_setPreprocessing ();
01139       dercfiles = preprocessFiles (cfiles);
01140       context_clearPreprocessing ();
01141 
01142       fileIdList_free (cfiles);
01143 
01144       if (context_getFlag (FLG_SHOWSCAN))
01145         {
01146           fprintf (stderr, " >\n");
01147         }
01148       
01149       pptime = clock ();
01150     }
01151   else
01152     {
01153       lcltime = clock ();
01154       dercfiles = cfiles;
01155       pptime = clock ();
01156     }
01157   
01158   /*
01159   ** now, check all the corresponding C files
01160   **
01161   ** (for now these are just <file>.c, but after pre-processing
01162   **  will be <tmpprefix>.<file>.c)
01163   */
01164 
01165   {
01166 # ifdef WIN32
01167     int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
01168 
01169     if (nfiles != 0) 
01170       {
01171         llbug (message ("Files unclosed: %d", nfiles));
01172       }
01173 # endif
01174   }
01175 
01176   exprNode_initMod ();
01177 
01178   fileIdList_elements (dercfiles, fid)
01179     {
01180       sourceFile = tsource_create (cstring_toCharsSafe (fileName (fid)),
01181                                    C_SUFFIX, TRUE);
01182       context_setFileId (fid);
01183       
01184       /* Open source file  */
01185       
01186       if (sourceFile == (tsource *) 0 || (!tsource_open (sourceFile)))
01187         {
01188           /* previously, this was ignored  ?! */
01189           llbug (message ("Could not open temp file: %s", fileName (fid)));
01190         }
01191       else
01192         {
01193           yyin = sourceFile->file; /*< shared <- only */
01194         
01195           llassert (yyin != NULL);
01196 
01197           if (context_getFlag (FLG_SHOWSCAN))
01198             {
01199                       lldiagmsg (message ("< checking %s >", rootFileName (fid)));
01200             }
01201           
01202           /*
01203           ** Every time, except the first time, through the loop,
01204           ** need to call yyrestart to clean up the parse buffer.
01205           */
01206 
01207           if (!first_time)
01208             {
01209               (void) yyrestart (yyin);  
01210             }
01211           else
01212             {
01213               first_time = FALSE;
01214             }
01215           
01216           context_enterFile ();
01217           (void) yyparse ();
01218           context_exitFile ();
01219                     
01220           (void) tsource_close (sourceFile);
01221         }
01222       
01223     } end_fileIdList_elements;
01224 
01225   cptime = clock ();
01226   
01227   /* process any leftover macros */
01228 
01229   context_processAllMacros ();
01230   
01231   /* check everything that was specified was defined */
01232   
01233   /* don't check if no c files were processed ?
01234   **   is this correct behaviour?
01235   */
01236   
01237   if (context_getFlag (FLG_SHOWSCAN))
01238     {
01239       lldiagmsg (cstring_makeLiteral ("< global checks >"));
01240     }
01241 
01242   cleanupMessages ();
01243   
01244   if (context_getLinesProcessed () > 0)
01245     {
01246       usymtab_allDefined ();
01247     }
01248 
01249   if (context_maybeSet (FLG_TOPUNUSED))
01250     {
01251       uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
01252 
01253       if (uentry_isValid (ue))
01254         {
01255           uentry_setUsed (ue, fileloc_observeBuiltin ());
01256         }
01257 
01258       usymtab_allUsed ();
01259     }
01260 
01261   if (context_maybeSet (FLG_EXPORTLOCAL))
01262     {
01263       usymtab_exportLocal ();
01264     }
01265 
01266   
01267   if (context_maybeSet (FLG_EXPORTHEADER))
01268     {
01269       usymtab_exportHeader ();
01270     }
01271 
01272   if (context_getFlag (FLG_SHOWUSES))
01273     {
01274       usymtab_displayAllUses ();
01275     }
01276 
01277   context_checkSuppressCounts ();
01278 
01279   if (context_doDump ())
01280     {
01281       cstring dump = context_getDump ();
01282 
01283       dumpState (dump);
01284     }
01285 
01286 # ifdef DOANNOTS
01287   printAnnots ();
01288 # endif
01289 
01290   cleanupFiles ();
01291 
01292   if (context_getFlag (FLG_SHOWSUMMARY))
01293     {
01294       summarizeErrors (); 
01295     }
01296 
01297   
01298   {
01299     bool isQuiet = context_getFlag (FLG_QUIET);
01300     cstring specErrors = cstring_undefined;
01301 # ifndef NOLCL
01302     int nspecErrors = lclNumberErrors ();
01303 # endif
01304     
01305     expsuccess = TRUE;
01306 
01307     if (context_neednl ())
01308       fprintf (g_msgstream, "\n");
01309     
01310 # ifndef NOLCL
01311     if (nspecErrors > 0)
01312       {
01313         if (nspecErrors == context_getLCLExpect ())
01314           {
01315             specErrors = 
01316               message ("%d spec error%p found, as expected\n       ", 
01317                        nspecErrors);
01318           }
01319         else
01320           {
01321             if (context_getLCLExpect () > 0)
01322               {
01323                 specErrors = 
01324                   message ("%d spec error%p found, expected %d\n       ", 
01325                            nspecErrors,
01326                            (int) context_getLCLExpect ());
01327               }
01328             else
01329               {
01330                 specErrors = message ("%d spec error%p found\n       ",
01331                                       nspecErrors);
01332                 expsuccess = FALSE;
01333               }
01334           }
01335       }
01336     else
01337         {
01338           if (context_getLCLExpect () > 0)
01339             {
01340               specErrors = message ("No spec errors found, expected %d\n       ", 
01341                                     (int) context_getLCLExpect ());
01342               expsuccess = FALSE;
01343             }
01344         }
01345 # endif
01346 
01347       if (context_anyErrors ())
01348         {
01349           if (context_numErrors () == context_getExpect ())
01350             {
01351               if (!isQuiet) {
01352                 llmsg (message ("Finished LCLint checking --- "
01353                                 "%s%d code error%p found, as expected",
01354                                 specErrors, context_numErrors ()));
01355               }
01356             }
01357           else
01358             {
01359               if (context_getExpect () > 0)
01360                 {
01361                   if (!isQuiet) {
01362                     llmsg (message 
01363                            ("Finished LCLint checking --- "
01364                             "%s%d code error%p found, expected %d",
01365                             specErrors, context_numErrors (), 
01366                             (int) context_getExpect ()));
01367                   }
01368 
01369                   expsuccess = FALSE;
01370                 }
01371               else
01372                 {
01373                   
01374                   if (!isQuiet) {
01375                     llmsg (message ("Finished LCLint checking --- "
01376                                     "%s%d code error%p found", 
01377                                     specErrors, context_numErrors ()));
01378                   }
01379 
01380                   expsuccess = FALSE;
01381                 }
01382             }
01383         }
01384       else
01385         {
01386           if (context_getExpect () > 0)
01387             {
01388               if (!isQuiet) {
01389                 llmsg (message
01390                        ("Finished LCLint checking --- "
01391                         "%sno code errors found, expected %d", 
01392                         specErrors,
01393                         (int) context_getExpect ()));
01394               }
01395 
01396               expsuccess = FALSE;
01397             }
01398           else
01399             {
01400               if (context_getLinesProcessed () > 0)
01401                 {
01402                   if (!isQuiet) {
01403                     llmsg (message ("Finished LCLint checking --- %sno code errors found", 
01404                                     specErrors));
01405                   }
01406                 }
01407               else
01408                 {
01409                   if (!isQuiet) {
01410                     llmsg (message ("Finished LCLint checking --- %sno code processed", 
01411                                     specErrors));
01412                   }
01413                 }
01414             }
01415         }
01416 
01417       cstring_free (specErrors);
01418   }
01419   
01420   if (context_getFlag (FLG_STATS))
01421     {
01422       clock_t ttime = clock () - before;
01423       int specLines = context_getSpecLinesProcessed ();
01424       
01425       rstime = clock ();
01426       
01427       if (specLines > 0)
01428         {
01429           fprintf (g_msgstream, "%d spec, ", specLines);
01430         }
01431       
01432 # ifndef CLOCKS_PER_SEC
01433       fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n", 
01434                context_getLinesProcessed (), 
01435                (long) ttime);
01436 # else
01437       fprintf (g_msgstream, "%d source lines in %.2f s.\n", 
01438                context_getLinesProcessed (), 
01439                (double) ttime / CLOCKS_PER_SEC);
01440 # endif
01441     }
01442   else
01443     {
01444       rstime = clock ();
01445     }
01446   
01447   if (context_getFlag (FLG_TIMEDIST))
01448     {
01449       clock_t ttime = clock () - before;
01450       
01451       if (ttime > 0)
01452         {
01453           char *msg = (char *) dmalloc (256 * sizeof (*msg));
01454           
01455           if (anylcl)
01456             {
01457               sprintf (msg, 
01458                        "Time distribution (percent): initialize %.2f / lcl %.2f / "
01459                        "pre-process %.2f / c check %.2f / finalize %.2f \n", 
01460                        (100.0 * (double) (libtime - before) / ttime),
01461                        (100.0 * (double) (lcltime - libtime) / ttime),
01462                        (100.0 * (double) (pptime - lcltime) / ttime),
01463                        (100.0 * (double) (cptime - pptime) / ttime),
01464                        (100.0 * (double) (rstime - cptime) / ttime));
01465             }
01466           else
01467             {
01468               sprintf (msg, 
01469                        "Time distribution (percent): initialize %.2f / "
01470                        "pre-process %.2f / c check %.2f / finalize %.2f \n", 
01471                        (100.0 * (double) (libtime - before) / ttime),
01472                        (100.0 * (double) (pptime - libtime) / ttime),
01473                        (100.0 * (double) (cptime - pptime) / ttime),
01474                        (100.0 * (double) (rstime - cptime) / ttime));
01475             }
01476           
01477           llgenindentmsgnoloc (cstring_fromCharsO (msg));
01478         }
01479     }
01480 
01481   llexit (expsuccess ? LLSUCCESS : LLFAILURE);
01482 }
01483 
01484 /*
01485 ** Reenable return value warnings.
01486 */
01487 
01488 #pragma warning (default:4035)
01489 
01490 void
01491 showHelp (void)
01492 {
01493   showHerald ();
01494   
01495   llmsglit ("Source files are .c, .h and .lcl files.  If there is no suffix,");
01496   llmsglit ("   LCLint will look for <file>.c and <file>.lcl.");
01497   llmsglit ("");
01498   llmsglit ("Use lclint -help <topic or flag name> for more information");
01499   llmsglit ("");
01500   llmsglit ("Topics:");
01501   llmsglit ("");
01502   llmsglit ("   annotations (describes source-code annotations)");
01503   llmsglit ("   comments (describes control comments)");
01504   llmsglit ("   flags (describes flag categories)");
01505   llmsglit ("   flags <category> (describes flags in category)");
01506   llmsglit ("   flags all (short description of all flags)");
01507   llmsglit ("   flags alpha (list all flags alphabetically)");
01508   llmsglit ("   flags full (full description of all flags)");
01509   llmsglit ("   mail (information on mailing lists)");
01510   llmsglit ("   modes (show mode settings)");
01511   llmsglit ("   parseerrors (help on handling parser errors)");
01512   llmsglit ("   prefixcodes (character codes in namespace prefixes)");
01513   llmsglit ("   references (sources for more information)");
01514   llmsglit ("   vars (environment variables)"); 
01515   llmsglit ("   version (information on compilation, maintainer)");
01516   llmsglit ("");
01517 }
01518 
01519 static bool
01520 specialFlagsHelp (char *next)
01521 {
01522   if ((next != NULL) && (*next != '-') && (*next != '+'))
01523     {
01524       if (mstring_equal (next, "alpha"))
01525         {
01526           printAlphaFlags ();
01527           return TRUE;
01528         }
01529       else if (mstring_equal (next, "all"))
01530         {
01531           printAllFlags (TRUE, FALSE);
01532           return TRUE;
01533         }
01534       else if (mstring_equal (next, "categories")
01535                || mstring_equal (next, "cats"))
01536         {
01537           listAllCategories ();
01538           return TRUE;
01539         }
01540       else if (mstring_equal (next, "full"))
01541         {
01542           printAllFlags (FALSE, TRUE);
01543           return TRUE;
01544         }
01545       else
01546         {
01547           return FALSE;
01548         }
01549     }
01550   else
01551     {
01552       return FALSE;
01553     }
01554 }
01555 
01556 void
01557 printParseErrors (void)
01558 {
01559   llmsglit ("Parse Errors");
01560   llmsglit ("------------");
01561   llmsglit ("");
01562   llmsglit ("LCLint will sometimes encounter a parse error for code that "
01563             "can be parsed with a local compiler. There are a few likely "
01564             "causes for this and a number of techniques that can be used "
01565             "to work around the problem.");
01566   llmsglit ("");
01567   llmsglit ("Compiler extensions --- compilers sometimes extend the C "
01568             "language with compiler-specific keywords and syntax. While "
01569             "it is not advisible to use these, oftentimes one has no choice "
01570             "when the system header files use compiler extensions. ");
01571   llmsglit ("");
01572   llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
01573             "if the +gnuextensions flag is set. You may be able to workaround "
01574             "other compiler extensions by using a pre-processor define. "
01575             "Alternately, you can surround the unparseable code with");
01576   llmsglit ("");
01577   llmsglit ("   # ifndef __LCLINT__");
01578   llmsglit ("   ...");
01579   llmsglit ("   # endif");
01580   llmsglit ("");
01581   llmsglit ("Missing type definitions --- an undefined type name will usually "
01582             "lead to a parse error. This ofter occurs when a standard header "
01583             "file defines some type that is not part of the standard library. ");
01584   llmsglit ("By default, LCLint does not process the local files corresponding "
01585             "to standard library headers, but uses a library specification "
01586             "instead so dependencies on local system headers can be detected. "
01587             "If another system header file that does not correspond to a "
01588             "standard library header uses one of these superfluous types, "
01589             "a parse error will result.");
01590   llmsglit ("");
01591   llmsglit ("If the parse error is inside a posix standard header file, the "
01592             "first thing to try is +posixlib. This make LCLint use "
01593             "the posix library specification instead of reading the posix "
01594             "header files.");
01595   llmsglit ("");
01596   llmsglit ("Otherwise, you may need to either manually define the problematic "
01597             "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
01598             "lclint to process the header file that defines it. This is done "
01599             "by setting -skipansiheaders or -skipposixheaders before "
01600             "the file that defines the type is #include'd.");
01601   llmsglit ("(See lclint -help "
01602             "skipansiheaders and lclint -help skipposixheaders for a list of "
01603             "standard headers.)  For example, if <sys/local.h> uses a type "
01604             "defined by posix header <sys/types.h> but not defined by the "
01605             "posix library, we might do: ");
01606   llmsglit ("");
01607   llmsglit ("   /*@-skipposixheaders@*/");
01608   llmsglit ("   # include <sys/types.h>");
01609   llmsglit ("   /*@=skipposixheaders@*/");
01610   llmsglit ("   # include <sys/local.h>");
01611   llmsglit ("");
01612   llmsglit ("to force LCLint to process <sys/types.h>.");
01613   llmsglit ("");
01614   llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
01615             "to continue after a parse error.  This is usually not successful "
01616             "and the author does not consider assertion failures when +trytorecover "
01617             "is used to be bugs.");
01618 }
01619 
01620 void
01621 printAnnotations (void)
01622 {
01623   llmsglit ("Annotations");
01624   llmsglit ("-----------");
01625   llmsglit ("");
01626   llmsglit ("Annotations are stylized comments that document certain "
01627             "assumptions about functions, variables, parameters, and types. ");
01628   llmsglit ("");
01629   llmsglit ("They may be used to indicate where the representation of a "
01630             "user-defined type is hidden, to limit where a global variable may "
01631             "be used or modified, to constrain what a function implementation "
01632             "may do to its parameters, and to express checked assumptions about "
01633             "variables, types, structure fields, function parameters, and "
01634             "function results.");
01635   llmsglit ("");
01636   llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
01637             "played by any printable character, selected using -commentchar <char>.");
01638   llmsglit ("");
01639   llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
01640   llmsglit ("");
01641   llmsglit ("Globals: (in function declarations)");
01642   llmsglit ("   /*@globals <globitem>,+ @*/");
01643   llmsglit ("      globitem is an identifier, internalState or fileSystem");
01644   llmsglit ("");
01645   llmsglit ("Modifies: (in function declarations)");
01646   llmsglit ("   /*@modifies <moditem>,+ @*/");
01647   llmsglit ("      moditem is an lvalue");
01648   llmsglit ("   /*@modifies nothing @*/");
01649   llmsglit ("   /*@*/   (Abbreviation for no globals and modifies nothing.)");
01650   llmsglit ("");
01651   llmsglit ("Iterators:");
01652   llmsglit ("   /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
01653   llmsglit ("");
01654   llmsglit ("Constants:");
01655   llmsglit ("   /*@constant <declaration> @*/ - declares a constant");
01656   llmsglit ("");
01657   llmsglit ("Alternate Types:");
01658   llmsglit ("   /*@alt <basic-type>,+ @*/");
01659   llmsglit ("   (e.g., int /*@alt char@*/ is a type matching either int or char)");
01660   llmsglit ("");
01661   llmsglit ("Declarator Annotations");
01662   llmsglit ("");
01663   llmsglit ("Type Definitions:");
01664   llmsglit ("   /*@abstract@*/ - representation is hidden from clients");
01665   llmsglit ("   /*@concrete@*/ - representation is visible to clients");
01666   llmsglit ("   /*@immutable@*/ - instances of the type cannot change value");
01667   llmsglit ("   /*@mutable@*/ - instances of the type can change value");
01668   llmsglit ("   /*@refcounted@*/ - reference counted type");
01669   llmsglit ("");
01670   llmsglit ("Global Variables:");
01671   llmsglit ("   /*@unchecked@*/ - weakest checking for global use");
01672   llmsglit ("   /*@checkmod@*/ - check modification by not use of global");
01673   llmsglit ("   /*@checked@*/ - check use and modification of global");
01674   llmsglit ("   /*@checkedstrict@*/ - check use of global strictly");
01675   llmsglit ("");
01676   llmsglit ("Memory Management:");
01677   llmsglit ("   /*@dependent@*/ - a reference to externally-owned storage");
01678   llmsglit ("   /*@keep@*/ - a parameter that is kept by the called function");
01679   llmsglit ("   /*@killref@*/ - a refcounted parameter, killed by the call");
01680   llmsglit ("   /*@only@*/ - an unshared reference");
01681   llmsglit ("   /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
01682   llmsglit ("   /*@shared@*/ - shared reference that is never deallocated");
01683   llmsglit ("   /*@temp@*/ - temporary parameter");
01684   llmsglit ("");
01685   llmsglit ("Aliasing:");
01686   llmsglit ("   /*@unique@*/ - may not be aliased by any other visible reference");
01687   llmsglit ("   /*@returned@*/ - may be aliased by the return value");
01688   llmsglit ("");
01689   llmsglit ("Exposure:");
01690   llmsglit ("   /*@observer@*/ - reference that cannot be modified");
01691   llmsglit ("   /*@exposed@*/ - exposed reference to storage in another object");
01692   llmsglit ("");
01693   llmsglit ("Definition State:");
01694   llmsglit ("   /*@out@*/ - storage reachable from reference need not be defined");
01695   llmsglit ("   /*@in@*/ - all storage reachable from reference must be defined");
01696   llmsglit ("   /*@partial@*/ - partially defined, may have undefined fields");
01697   llmsglit ("   /*@reldef@*/ - relax definition checking");
01698   llmsglit ("");
01699   llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
01700   llmsglit ("   undef - variable is undefined before the call");
01701   llmsglit ("   killed - variable is undefined after the call");
01702   llmsglit ("");
01703   llmsglit ("Null State:");
01704   llmsglit ("   /*@null@*/ - possibly null pointer");
01705   llmsglit ("   /*@notnull@*/ - non-null pointer");
01706   llmsglit ("   /*@relnull@*/ - relax null checking");
01707   llmsglit ("");
01708   llmsglit ("Null Predicates:");
01709   llmsglit ("   /*@truenull@*/ - if result is TRUE, first parameter is NULL");
01710   llmsglit ("   /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
01711   llmsglit ("");
01712   llmsglit ("Execution:");
01713   llmsglit ("   /*@exits@*/ - function never returns");
01714   llmsglit ("   /*@mayexit@*/ - function may or may not return");
01715   llmsglit ("   /*@trueexit@*/ - function does not return if first parameter is TRUE");
01716   llmsglit ("   /*@falseexit@*/ - function does not return if first parameter if FALSE");
01717   llmsglit ("   /*@neverexit@*/ - function always returns");
01718   llmsglit ("");
01719   llmsglit ("Side-Effects:");
01720   llmsglit ("   /*@sef@*/ - corresponding actual parameter has no side effects");
01721   llmsglit ("");
01722   llmsglit ("Declaration:");
01723   llmsglit ("   /*@unused@*/ - need not be used (no unused errors reported)");
01724   llmsglit ("   /*@external@*/ - defined externally (no undefined error reported)");
01725   llmsglit ("");
01726   llmsglit ("Case:");
01727   llmsglit ("   /*@fallthrough@*/ - fall-through case");
01728   llmsglit ("");
01729   llmsglit ("Break:");
01730   llmsglit ("   /*@innerbreak@*/ - break is breaking an inner loop or switch");
01731   llmsglit ("   /*@loopbreak@*/ - break is breaking a loop");
01732   llmsglit ("   /*@switchbreak@*/ - break is breaking a switch");
01733   llmsglit ("   /*@innercontinue@*/ - continue is continuing an inner loop");
01734   llmsglit ("");
01735   llmsglit ("Unreachable Code:");
01736   llmsglit ("   /*@notreached@*/ - statement may be unreachable.");
01737   llmsglit ("");
01738   llmsglit ("Special Functions:");
01739   llmsglit ("   /*@printflike@*/ - check variable arguments like printf");
01740   llmsglit ("   /*@scanflike@*/ - check variable arguments like scanf");
01741 }
01742 
01743 void
01744 printComments (void)
01745 {
01746   llmsglit ("Control Comments");
01747   llmsglit ("----------------");
01748   llmsglit ("");
01749   llmsglit ("Setting Flags");
01750   llmsglit ("");
01751   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.");
01752   llmsglit ("");
01753   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,");
01754   llmsglit ("   /*@+boolint -modifies =showfunc@*/");
01755   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).");
01756   llmsglit ("");
01757   llmsglit ("Error Suppression");
01758   llmsglit ("");
01759   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.");
01760   llmsglit ("");
01761   llmsglit ("/*@ignore@*/ ... /*@end@*/");
01762   llgenindentmsgnoloc
01763     (cstring_makeLiteral 
01764      ("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."));
01765   llmsglit ("/*@i@*/");
01766     llgenindentmsgnoloc
01767     (cstring_makeLiteral 
01768      ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
01769   llmsglit ("/*@i<n>@*/");
01770   llgenindentmsgnoloc
01771     (cstring_makeLiteral 
01772      ("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."));
01773   llmsglit ("/*@t@*/, /*@t<n>@*/");
01774   llgenindentmsgnoloc
01775     (cstring_makeLiteral 
01776      ("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."));
01777   llmsglit ("");
01778   llmsglit ("Type Access");
01779   llmsglit ("");
01780   llmsglit ("/*@access <type>@*/"); 
01781   llmsglit ("   Allows the following code to access the representation of <type>");
01782   llmsglit ("/*@noaccess <type>@*/");
01783   llmsglit ("   Hides the representation of <type>");
01784   llmsglit ("");
01785   llmsglit ("Macro Expansion");
01786   llmsglit ("");
01787   llmsglit ("/*@notfunction@*/");
01788   llgenindentmsgnoloc 
01789     (cstring_makeLiteral
01790      ("Indicates that the next macro definition is not intended to be a "
01791       "function, and should be expanded in line instead of checked as a "
01792       "macro function definition."));
01793 }
01794 
01795   
01796 void
01797 printFlags (void)
01798 {
01799   llmsglit ("Flag Categories");
01800   llmsglit ("---------------");
01801   listAllCategories ();
01802   llmsglit ("\nTo see the flags in a flag category, do\n   lclint -help flags <category>");
01803   llmsglit ("To see a list of all flags in alphabetical order, do\n   lclint -help flags alpha");
01804   llmsglit ("To see a full description of all flags, do\n   lclint -help flags full");
01805 }
01806 
01807 void
01808 printMaintainer (void)
01809 {
01810   llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
01811   llmsglit (LCL_COMPILE);
01812 }
01813 
01814 void
01815 printMail (void)
01816 {
01817   llmsglit ("Mailing Lists");
01818   llmsglit ("-------------");
01819   llmsglit ("");
01820   llmsglit ("There are two mailing lists associated with LCLint: ");
01821   llmsglit ("");
01822   llmsglit ("   lclint-announce@virginia.edu");
01823   llmsglit ("");
01824   llmsglit ("      Reserved for announcements of new releases and bug fixes.");
01825   llmsglit ("      To subscribe, send a message to majordomo@virginia.edu with body: ");
01826   llmsglit ("           subscribe lclint-announce");
01827   llmsglit ("");
01828   llmsglit ("   lclint-interest@virginia.edu");
01829   llmsglit ("");
01830   llmsglit ("      Informal discussions on the use and development of lclint.");
01831   llmsglit ("      To subscribe, send a message to majordomo@virginia.edu with body: ");
01832   llmsglit ("           subscribe lclint-interest");
01833 }
01834 
01835 void
01836 printReferences (void)
01837 {
01838   llmsglit ("References");
01839   llmsglit ("----------");
01840   llmsglit ("");
01841   llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
01842   llmsglit ("");
01843   llmsglit ("Technical papers relating to LCLint include:");
01844   llmsglit ("");
01845   llmsglit ("   David Evans. \"Static Detection of Dynamic Memory Errors\".");  
01846   llmsglit ("   SIGPLAN Conference on Programming Language Design and ");
01847   llmsglit ("   Implementation (PLDI '96), Philadelphia, PA, May 1996.");
01848   llmsglit ("");
01849   llmsglit ("   David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
01850   llmsglit ("   \"LCLint: A Tool for Using Specifications to Check Code\".");
01851   llmsglit ("   SIGSOFT Symposium on the Foundations of Software Engineering,");
01852   llmsglit ("   December 1994.");
01853   llmsglit ("");
01854   llmsglit ("A general book on Larch is:");
01855   llmsglit ("");
01856   llmsglit ("   Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
01857   llmsglit ("   K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
01858   llmsglit ("   for Formal Specification\", Springer-Verlag, 1993.");
01859 }
01860 
01861 void
01862 describePrefixCodes (void)
01863 {
01864   llmsglit ("Prefix Codes");
01865   llmsglit ("------------");
01866   llmsglit ("");
01867   llmsglit ("These characters have special meaning in name prefixes:");
01868   llmsglit ("");
01869   llmsg (message ("   %h  Any uppercase letter [A-Z]", PFX_UPPERCASE));
01870   llmsg (message ("   %h  Any lowercase letter [a-z]", PFX_LOWERCASE));
01871   llmsg (message ("   %h  Any character (valid in a C identifier)", PFX_ANY));
01872   llmsg (message ("   %h  Any digit [0-9]", PFX_DIGIT));
01873   llmsg (message ("   %h  Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
01874   llmsg (message ("   %h  Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
01875   llmsg (message ("   %h  Any letter [A-Za-z]", PFX_ANYLETTER));
01876   llmsg (message ("   %h  Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
01877   llmsglit ("   *  Zero or more repetitions of the previous character class until the end of the name");
01878 }
01879 
01880 void
01881 describeVars (void)
01882 {
01883   cstring eval;
01884   char *def;
01885 
01886   eval = context_getLarchPath ();
01887   def = osd_getEnvironmentVariable (LARCH_PATH);
01888 
01889   if (def != NULL || 
01890       !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
01891     {
01892       llmsg (message ("LARCH_PATH = %s", eval));
01893     }
01894   else
01895     {
01896       llmsg (message ("LARCH_PATH = <not set> (default = %s)",
01897                       cstring_fromChars (DEFAULT_LARCHPATH)));
01898     }
01899   
01900   llmsglit ("   --- path used to find larch initialization files and LSL traits");
01901 
01902   eval = context_getLCLImportDir ();
01903   def = osd_getEnvironmentVariable (LCLIMPORTDIR);
01904 
01905   if (def != NULL ||
01906       !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
01907     {
01908       llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
01909     }
01910   else
01911     {
01912       llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR), 
01913                       cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR))); 
01914     }
01915   
01916   llmsglit ("   --- directory containing lcl standard library files "
01917             "(import with < ... >)");;
01918 
01919   {
01920     cstring dirs = context_getString (FLG_SYSTEMDIRS);
01921     llmsg (message 
01922            ("systemdirs = %s (set by include envirnoment variable or -systemdirs)",
01923             dirs));
01924 
01925   }
01926 }
01927 
01928 void
01929 interrupt (int i)
01930 {
01931   switch (i)
01932     {
01933     case SIGINT:
01934       fprintf (stderr, "*** Interrupt\n");
01935       llexit (LLINTERRUPT);
01936     case SIGSEGV:
01937       {
01938         cstring loc;
01939         
01940         /* Cheat when there are parse errors */
01941         checkParseError (); 
01942         
01943         fprintf (stderr, "*** Segmentation Violation\n");
01944         
01945         /* Don't catch it if fileloc_unparse causes a signal */
01946         (void) signal (SIGSEGV, NULL);
01947 
01948         loc = fileloc_unparse (g_currentloc);
01949         
01950         fprintf (stderr, "*** Location (not trusted): %s\n", 
01951                  cstring_toCharsSafe (loc));
01952         cstring_free (loc);
01953         printCodePoint ();
01954         fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
01955         exit (LLGIVEUP);
01956       }
01957     default:
01958       fprintf (stderr, "*** Signal: %d\n", i);
01959       /*@-mustfree@*/
01960       fprintf (stderr, "*** Location (not trusted): %s\n", 
01961                cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
01962       /*@=mustfree@*/
01963       printCodePoint ();
01964       fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
01965       exit (LLGIVEUP);
01966     }
01967 }
01968 
01969 void
01970 cleanupFiles (void)
01971 {
01972   static bool doneCleanup = FALSE;
01973 
01974   /* make sure this is only called once! */
01975 
01976   if (doneCleanup) return;
01977 
01978   setCodePoint ();
01979 
01980   if (context_getFlag (FLG_KEEP))
01981     {
01982       check (fputs ("Temporary files kept:\n", stderr) != EOF);
01983       fileTable_printTemps (context_fileTable ());
01984     }
01985   else
01986     {
01987 # ifdef WIN32
01988       int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
01989       
01990       if (nfiles != 0) 
01991         {
01992           llbug (message ("Files unclosed: %d", nfiles));
01993         }
01994 # endif
01995       fileTable_cleanup (context_fileTable ());
01996     }
01997 
01998   doneCleanup = TRUE;
01999 }
02000 
02001 /*
02002 ** cleans up temp files (if necessary)
02003 ** exits lclint
02004 */
02005 
02006 /*@exits@*/ void
02007 llexit (int status)
02008 {
02009   DPRINTF (("llexit: %d", status));
02010 
02011 # ifdef WIN32
02012   if (status == LLFAILURE) 
02013     {
02014       _fcloseall ();
02015     }
02016 # endif
02017 
02018   cleanupFiles ();
02019 
02020   if (status != LLFAILURE)
02021     {
02022       context_destroyMod ();
02023       exprNode_destroyMod ();
02024       
02025       sRef_destroyMod ();
02026       uentry_destroyMod ();
02027       typeIdSet_destroyMod ();
02028       
02029 # ifdef USEDMALLOC
02030       dmalloc_shutdown ();
02031 # endif
02032     }
02033 
02034   exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
02035 }
02036 
02037 void
02038 loadrc (FILE *rcfile, cstringSList *passThroughArgs)
02039 {
02040   char *s = mstring_create (MAX_LINE_LENGTH);
02041   char *os = s;
02042 
02043   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02044 
02045   s = os;
02046 
02047   while (fgets (s, MAX_LINE_LENGTH, rcfile) != NULL)
02048     {
02049       char c;
02050       bool set = FALSE;     
02051       char *thisflag;
02052       flagcode opt;
02053 
02054       DPRINTF (("Line: %s", s));
02055       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02056       incLine ();
02057             
02058       while (*s == ' ' || *s == '\t' || *s == '\n') 
02059         {
02060           s++;
02061           incColumn ();
02062         }
02063       
02064       while (*s != '\0')
02065         {
02066           bool escaped = FALSE;
02067           bool quoted = FALSE;
02068           c = *s;
02069 
02070           DPRINTF (("Process: %s", s));
02071           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02072           /* comment characters */
02073           if (c == '#' || c == ';' || c == '\n') 
02074             {
02075               /*@innerbreak@*/
02076               break;
02077             }
02078           
02079           if (c == '-' || c == '+')
02080             {
02081               set = (c == '+');
02082             }
02083           else
02084             {
02085               showHerald ();
02086               llerror (FLG_SYNTAX, 
02087                        message ("Bad flag syntax (+ or - expected, "
02088                                 "+ is assumed): %s", 
02089                                 cstring_fromChars (s)));
02090               s--;
02091               set = TRUE;
02092             }
02093           
02094           s++;
02095           incColumn ();
02096           
02097           thisflag = s;
02098           
02099           while ((c = *s) != '\0')
02100             { /* remember to handle spaces and quotes in -D and -U ... */
02101               if (escaped)
02102                 {
02103                   escaped = FALSE;
02104                 }
02105               else if (quoted)
02106                 {
02107                   if (c == '\\')
02108                     {
02109                       escaped = TRUE;
02110                     }
02111                   else if (c == '\"')
02112                     {
02113                       quoted = FALSE;
02114                     }
02115                   else
02116                     {
02117                       ;
02118                     }
02119                 }
02120               else if (c == '\"')
02121                 {
02122                   quoted = TRUE;
02123                 }
02124               else
02125                 {
02126                  if (c == ' ' || c == '\t' || c == '\n')
02127                    {
02128                      /*@innerbreak@*/ break;
02129                    }
02130                }
02131                   
02132               s++; 
02133               incColumn ();
02134             }
02135 
02136           DPRINTF (("Nulling: %c", *s));
02137           *s = '\0';
02138 
02139           if (mstring_isEmpty (thisflag))
02140             {
02141               llfatalerror (message ("Missing flag: %s",
02142                                      cstring_fromChars (os)));
02143             }
02144 
02145           DPRINTF (("Flag: %s", thisflag));
02146 
02147           opt = identifyFlag (cstring_fromChars (thisflag));
02148           
02149           if (flagcode_isSkip (opt))
02150             {
02151               ;
02152             }
02153           else if (flagcode_isInvalid (opt))
02154             {
02155               if (isMode (cstring_fromChars (thisflag)))
02156                 {
02157                   context_setMode (cstring_fromChars (thisflag));
02158                 }
02159               else
02160                 {
02161                   llerror (FLG_BADFLAG,
02162                            message ("Unrecognized option: %s", 
02163                                     cstring_fromChars (thisflag)));
02164                 }
02165             }
02166           else
02167             {
02168               context_userSetFlag (opt, set);
02169 
02170               if (flagcode_hasArgument (opt))
02171                 {
02172                   if (opt == FLG_HELP)
02173                     {
02174                       showHerald ();
02175                       llerror (FLG_BADFLAG,
02176                                message ("Cannot use help in rc files"));
02177                     }
02178                   else if (flagcode_isPassThrough (opt)) /* -D or -U */
02179                     {
02180                       cstring arg = cstring_fromCharsNew (thisflag);
02181                       cstring_markOwned (arg);
02182                       *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
02183                       DPRINTF (("Pass through: %s",
02184                                 cstringSList_unparse (*passThroughArgs)));
02185                     }
02186                   else if (opt == FLG_INCLUDEPATH 
02187                            || opt == FLG_SPECPATH)
02188                     {
02189                       cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
02190                                       
02191                       switch (opt)
02192                         {
02193                         case FLG_INCLUDEPATH:
02194                           cppAddIncludeDir (dir);
02195                           /*@switchbreak@*/ break;
02196                         case FLG_SPECPATH:
02197                           /*@-mustfree@*/
02198                           g_localSpecPath = cstring_toCharsSafe
02199                             (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
02200                           /*@=mustfree@*/
02201                           /*@switchbreak@*/ break;
02202                           BADDEFAULT;
02203                         }
02204                     }
02205                   else if (flagcode_hasString (opt)
02206                            || flagcode_hasValue (opt)
02207                            || opt == FLG_INIT || opt == FLG_OPTF)
02208                     {
02209                       cstring extra = cstring_undefined;
02210                       char *rest, *orest;
02211                       char rchar;
02212                       
02213                       *s = c;
02214                       rest = mstring_copy (s);
02215                       DPRINTF (("Here: rest = %s", rest));
02216                       orest = rest;
02217                       *s = '\0';
02218                       
02219                       while ((rchar = *rest) != '\0'
02220                              && (isspace ((int) rchar)))
02221                         {
02222                           rest++;
02223                           s++;
02224                         }
02225                       
02226                       DPRINTF (("Yo: %s", rest));
02227 
02228                       while ((rchar = *rest) != '\0' 
02229                              && !isspace ((int) rchar))
02230                         {
02231                           extra = cstring_appendChar (extra, rchar);
02232                           rest++; 
02233                           s++;
02234                         }
02235                       
02236                       DPRINTF (("Yo: %s", extra));
02237                       sfree (orest);
02238 
02239                       if (cstring_isUndefined (extra))
02240                         {
02241                           showHerald ();
02242                           llerror 
02243                             (FLG_BADFLAG,
02244                              message
02245                              ("Flag %s must be followed by an argument",
02246                               flagcode_unparse (opt)));
02247                         }
02248                       else
02249                         {
02250                           s--;
02251                           
02252                           DPRINTF (("Here we are: %s", extra));
02253 
02254                           if (flagcode_hasValue (opt))
02255                             {
02256                               DPRINTF (("Set value flag: %s", extra));
02257                               setValueFlag (opt, extra);
02258                               cstring_free (extra);
02259                             }
02260                           else if (opt == FLG_OPTF)
02261                             {
02262                               FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
02263                               cstring_markOwned (extra);
02264                               
02265                               if (innerf != NULL)
02266                                 {
02267                                   fileloc fc = g_currentloc;
02268                                   g_currentloc = fileloc_createRc (extra);
02269                                   loadrc (innerf, passThroughArgs);
02270                                   fileloc_reallyFree (g_currentloc);
02271                                   g_currentloc = fc;
02272                                 }
02273                               else 
02274                                 {
02275                                   showHerald ();
02276                                   llerror
02277                                     (FLG_SYNTAX, 
02278                                      message ("Options file not found: %s", 
02279                                               extra));
02280                                 }
02281                             }
02282                           else if (opt == FLG_INIT)
02283                             {
02284 # ifndef NOLCL
02285                               llassert (initFile == NULL);
02286                               
02287                               initFile = tsource_create 
02288                                 (cstring_toCharsSafe (extra), 
02289                                  LCLINIT_SUFFIX, FALSE);
02290                               cstring_markOwned (extra);
02291 # else
02292                               cstring_free (extra);
02293 # endif
02294                             }
02295                           else if (flagcode_hasString (opt))
02296                             {
02297                               if (cstring_firstChar (extra) == '"')
02298                                 {
02299                                   if (cstring_lastChar (extra) == '"')
02300                                     {
02301                                       char *extras = cstring_toCharsSafe (extra);
02302                                       
02303                                       llassert (extras[strlen(extras) - 1] == '"');
02304                                       extras[strlen(extras) - 1] = '\0';
02305                                       extra = cstring_fromChars (extras + 1); 
02306                                       DPRINTF (("Remove quites: %s", extra));
02307                                     }
02308                                   else
02309                                     {
02310                                       llerror
02311                                         (FLG_SYNTAX, 
02312                                          message ("Unmatched \" in option string: %s", 
02313                                                   extra));
02314                                     }
02315                                 }
02316                               
02317                               setStringFlag (opt, extra);
02318                             }
02319                           else
02320                             {
02321                               cstring_free (extra);
02322                               BADEXIT;
02323                             }
02324                         }
02325                     }
02326                   else
02327                     {
02328                       BADEXIT;
02329                     }
02330                 }
02331             }
02332           
02333           *s = c;
02334           DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02335           while ((c == ' ') || (c == '\t'))
02336             {
02337               c = *(++s);
02338               incColumn ();
02339             } 
02340         }
02341       DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02342       s = os;
02343     }
02344 
02345   DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
02346   sfree (os); 
02347   check (fclose (rcfile) == 0);
02348 }
02349 
02350 static fileIdList preprocessFiles (fileIdList fl)
02351   /*@modifies fileSystem@*/
02352 {
02353   bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
02354   int skip = (fileIdList_size (fl) / 5);
02355   int filesprocessed = 0;
02356   fileIdList dfiles = fileIdList_create ();
02357 
02358   fileloc_free (g_currentloc);
02359   g_currentloc = fileloc_createBuiltin ();
02360 
02361   fileIdList_elements (fl, fid)
02362     {
02363       char *ppfname = cstring_toCharsSafe (fileName (fid));
02364 
02365       if (!(osd_fileIsReadable (ppfname)))
02366         {
02367           lldiagmsg (message ("Cannot open file: %s",
02368                               cstring_fromChars (ppfname)));
02369         }
02370       else
02371         {
02372           fileId  dfile = fileTable_addCTempFile (context_fileTable (), fid);
02373           
02374           llassert (!mstring_isEmpty (ppfname));
02375           
02376           if (msg)
02377             {
02378               if ((filesprocessed % skip) == 0) 
02379                 {
02380                   if (filesprocessed == 0) {
02381                     fprintf (stderr, " ");
02382                   }
02383                   else {
02384                     fprintf (stderr, ".");
02385                   }
02386                   
02387                   (void) fflush (stderr);
02388                 }
02389               filesprocessed++;
02390             }
02391 
02392           if (cppProcess (cstring_fromChars (ppfname), 
02393                           fileName (dfile)) != 0) 
02394             {
02395               llfatalerror (message ("Preprocessing error for file: %s", 
02396                                      rootFileName (fid)));
02397             }
02398           
02399           fileIdList_add (dfiles, dfile);
02400         }
02401     } end_fileIdList_elements; 
02402     
02403     return dfiles;
02404 }

Generated at Fri Nov 3 18:57:43 2000 for LCLint by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000