00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 # include <signal.h>
00031
00032
00033
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 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 tsource *initFile = (tsource *) 0;
00104
00105 static fileIdList preprocessFiles (fileIdList)
00106 ;
00107
00108 # ifndef NOLCL
00109
00110 static
00111 void lslCleanup (void)
00112
00113
00114 {
00115
00116
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
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
00146
00147 {
00148
00149
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
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
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
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
00277
00278 sort_init ();
00279 abstract_init ();
00280 setCodePoint ();
00281
00282 inittime = clock ();
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 LCLBuiltins ();
00293 LCLReportEolTokens (FALSE);
00294 }
00295
00296 static void
00297 lslProcess (fileIdList lclfiles)
00298
00299
00300
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
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
00373
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
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
00485
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, 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
00529
00530
00531
00532 # ifdef WIN32
00533 # pragma warning (disable:4035)
00534 # endif
00535
00536 int main (int argc, char *argv[])
00537 # ifdef NOLCL
00538
00539
00540
00541
00542
00543
00544
00545 # else
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
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
00605
00606
00607 {
00608 char *incval = mstring_copy (osd_getEnvironmentVariable (INCLUDE_VAR));
00609
00610 if (incval != NULL)
00611 {
00612
00613
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
00634
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
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 ;
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++;
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++;
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))
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);
00923
00924 switch (opt)
00925 {
00926 case FLG_INCLUDEPATH:
00927 cppAddIncludeDir (dir);
00928 break;
00929 case FLG_SPECPATH:
00930
00931 g_localSpecPath = cstring_toCharsSafe
00932 (message ("%s%h%s",
00933 cstring_fromChars (g_localSpecPath),
00934 SEPCHAR,
00935 dir));
00936
00937 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 ;
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
00977 }
00978 }
00979 }
00980 }
00981 else
00982 {
00983 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
00984 }
00985 }
00986 }
00987
00988 setCodePoint ();
00989
00990
00991
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
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
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
01103
01104
01105
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
01160
01161
01162
01163
01164
01165 {
01166 # ifdef WIN32
01167 int nfiles = _fcloseall ();
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
01185
01186 if (sourceFile == (tsource *) 0 || (!tsource_open (sourceFile)))
01187 {
01188
01189 llbug (message ("Could not open temp file: %s", fileName (fid)));
01190 }
01191 else
01192 {
01193 yyin = sourceFile->file;
01194
01195 llassert (yyin != NULL);
01196
01197 if (context_getFlag (FLG_SHOWSCAN))
01198 {
01199 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
01200 }
01201
01202
01203
01204
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
01228
01229 context_processAllMacros ();
01230
01231
01232
01233
01234
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
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
01941 checkParseError ();
01942
01943 fprintf (stderr, "*** Segmentation Violation\n");
01944
01945
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
01960 fprintf (stderr, "*** Location (not trusted): %s\n",
01961 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
01962
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
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 = _fcloseall ();
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
02003
02004
02005
02006 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
02073 if (c == '#' || c == ';' || c == '\n')
02074 {
02075
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 {
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 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))
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);
02190
02191 switch (opt)
02192 {
02193 case FLG_INCLUDEPATH:
02194 cppAddIncludeDir (dir);
02195 break;
02196 case FLG_SPECPATH:
02197
02198 g_localSpecPath = cstring_toCharsSafe
02199 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
02200
02201 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
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 }