]> andersk Git - splint.git/blame - src/flags.c
Put manual in CVS
[splint.git] / src / flags.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
77d37419 3** Copyright (C) 1994-2002 University of Virginia,
616915dd 4** Massachusetts Institute of Technology
5**
6** This program is free software; you can redistribute it and/or modify it
7** under the terms of the GNU General Public License as published by the
8** Free Software Foundation; either version 2 of the License, or (at your
9** option) any later version.
10**
11** This program is distributed in the hope that it will be useful, but
12** WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14** General Public License for more details.
15**
16** The GNU General Public License is available from http://www.gnu.org/ or
17** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18** MA 02111-1307, USA.
19**
1b8ae690 20** For information on splint: splint@cs.virginia.edu
21** To report a bug: splint-bug@cs.virginia.edu
11db3170 22** For more information: http://www.splint.org
616915dd 23*/
24/*
25** flags.c
26*/
27
1b8ae690 28# include "splintMacros.nf"
616915dd 29# include "basic.h"
30# include "portab.h"
31
32/*
33** from the CC man page:
34**
35** -Idir Search for #include files whose names do not begin with a
36** slash (/) in the following order: (1) in the directory of
37** the dir argument, (2) in the directories specified by -I
38** options, (3) in the standard directory (/usr/include).
39*/
40
41/* needed for string literals literals */
42
43typedef struct {
44 flagkind kind;
45 /*@null@*/ /*@observer@*/ char *name;
46 /*@null@*/ /*@observer@*/ char *describe;
47} flagcatinfo;
48
49static flagcatinfo categories[] =
50{
51 { FK_ABSTRACT, "abstract", "abstraction violations, representation access" } ,
52 { FK_ALIAS, "aliasing", "unexpected or dangerous aliasing" } ,
53 { FK_USE, "alluse", "all declarations are used" } ,
54 { FK_ANSI, "ansi", "violations of constraints imposed by ANSI/ISO standard" } ,
55 { FK_ARRAY, "arrays", "special checking involving arrays" } ,
56 { FK_BOOL, "booleans", "checking and naming of boolean types" } ,
bb7c2085 57 { FK_COMMENTS, "comments", "warnings about (normal) comments" } ,
58 { FK_SYNCOMMENTS, "syncomments", "interpretation of annotation comments" } ,
616915dd 59 { FK_COMPLETE, "complete", "completely defined, used, or specified system" } ,
60 { FK_CONTROL, "controlflow", "suspicious control structures" } ,
1b8ae690 61 { FK_DEBUG, "debug", "flags for debugging splint" } ,
616915dd 62 { FK_DECL, "declarations", "consistency of declarations" } ,
63 { FK_DEF, "definition", "undefined storage errors" } ,
64 { FK_DIRECT, "directories", "set directores" } ,
65 { FK_DISPLAY, "display", "control what is displayed" } ,
66 { FK_EFFECT, "effect", "statements with no effects" } ,
67 { FK_ERRORS, "errors", "control expected errors, summary reporting" } ,
68 { FK_EXPORT, "export", "control what may be exported" } ,
69 { FK_EXPOSURE, "exposure", "representation exposure" } ,
bb7c2085 70 { FK_EXTENSIBLE, "extensible", "user-defined checks and annotations" },
616915dd 71 { FK_FILES, "files", "control system files" } ,
72 { FK_FORMAT, "format", "control format of warning messages" } ,
73 { FK_GLOBALS, "globals", "use of global and file static variables" },
74 { FK_HEADERS, "headers", "control inclusion and generation of header files" },
75 { FK_HELP, "help", "on-line help" },
bb7c2085 76 { FK_BOUNDS, "memorybounds", "out-of-bounds memory accesses" },
77 { FK_HINTS, "hints", "control display of warning hints" },
78 { FK_SYSTEMFUNCTIONS, "systemfunctions", "special properties of exit and main" },
616915dd 79 { FK_IMPLICIT, "implicit", "control implicit annotations and interpretations" } ,
80 { FK_INIT, "initializations", "initialization files" } ,
81 { FK_ITER, "iterators", "checking iterator definitions and uses" } ,
82 { FK_LEAK, "leaks", "memory leaks" } ,
83 { FK_LIBS, "libraries", "loading and dumping of user and standard libraries" } ,
84 { FK_LIMITS, "limits", "violations of set limits" } ,
85 { FK_MACROS, "macros", "expansion, definition and use of macros" },
86 { FK_MEMORY, "memory", "memory management" } ,
87 { FK_MODIFIES, "modification", "modification errors" } ,
88 { FK_NAMES, "names", "naming conventions and limits" } ,
89 { FK_NULL, "null", "misuses of null pointers" } ,
90 { FK_NUMBERS, "numbers", "control type-checking of numeric types" } ,
91 { FK_OPS, "operations", "checking of primitive operations" } ,
92 { FK_PARAMS, "parameters", "function and macro parameters" } ,
93 { FK_SPEED, "performance", "speeding up checking" } ,
94 { FK_POINTER, "pointers", "pointers" } ,
95 { FK_PRED, "predicates", "condition test expressions" } ,
96 { FK_PREFIX, "prefixes", "set naming prefixes and control checking" } ,
97 { FK_PREPROC, "preproc", "defines and undefines for the preprocessor" } ,
98 { FK_PROTOS, "prototypes", "function prototypes" } ,
99 { FK_DEAD, "released", "using storage that has been deallocated" } ,
100 { FK_IGNORERET, "returnvals", "ignored return values" },
28bf4b0b 101 { FK_SECURITY, "security", "possible security vulnerability" },
616915dd 102 { FK_SPEC, "specifications", "checks involving .lcl specifications" } ,
103 { FK_SUPPRESS, "suppress", "local and global suppression of messages" } ,
104 { FK_TYPEEQ, "typeequivalence", "control what types are equivalent" } ,
105 { FK_BEHAVIOR, "undefined", "code with undefined or implementation-defined behavior" } ,
106 { FK_UNRECOG, "unrecognized", "unrecognized identifiers" } ,
107 { FK_UNSPEC, "unconstrained", "checking in the presence of unconstrained functions" } ,
28bf4b0b 108 { FK_WARNUSE, "warnuse", "use of possibly problematic function" } ,
bb7c2085 109 { FK_ITS4, "its4", "its4 compatibility flags (report warnings for uses of possibly insecure functions)" } ,
616915dd 110 { FK_SYNTAX, NULL, NULL } ,
111 { FK_TYPE, NULL, NULL } ,
112 { FK_SECRET, NULL, NULL } ,
113 { FK_OBSOLETE, NULL, NULL } ,
114 { FK_NONE, NULL, NULL } /* must be last */
115} ;
116
117typedef enum {
118 ARG_NONE,
4f43223c 119 ARG_NUMBER, /* number */
120 ARG_CHAR, /* char */
121 ARG_STRING, /* string */
122 ARG_FILE, /* filename (also a string) */
123 ARG_DIRECTORY, /* directory (also a string) */
124 ARG_PATH, /* path */
125 ARG_SPECIAL /* ? */
616915dd 126} argcode;
127
4f43223c 128static /*@observer@*/ cstring argcode_unparse (argcode arg)
129{
130 switch (arg)
131 {
132 case ARG_STRING: return cstring_makeLiteralTemp ("string");
133 case ARG_FILE: return cstring_makeLiteralTemp ("filename");
134 case ARG_DIRECTORY: return cstring_makeLiteralTemp ("directory");
135 case ARG_PATH: return cstring_makeLiteralTemp ("path");
136 case ARG_NUMBER: return cstring_makeLiteralTemp ("number");
137 case ARG_CHAR: return cstring_makeLiteralTemp ("character");
138 case ARG_NONE:
139 BADBRANCH;
140 case ARG_SPECIAL:
141 BADBRANCH;
142 }
143}
144
616915dd 145typedef struct {
146 flagkind main;
147 flagkind sub;
148 bool isSpecial; /* setting this flag may set other flags (or values) */
149 bool isIdem; /* idempotent - always sets to TRUE */
150 bool isGlobal; /* cannot be set locally (using control comments) */
151 bool isModeFlag; /* set by modes */
152 argcode argtype;
153 /*@observer@*/ char *flag;
154 flagcode code;
155 /*@observer@*/ /*@null@*/ char *desc;
156 bn_mstring hint;
157 int nreported;
158 int nsuppressed;
159} fflag;
160
161typedef fflag flaglist[];
162
163# include "flags.def"
164
165/*@iter allFlags (yield observer fflag f); @*/
166# define allFlags(m_f) \
167 { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
168# define end_allFlags }}
169
170static bn_mstring mode_names[] =
171{
172 "weak", "standard", "checks", "strict", NULL,
173};
174
175/*@iter allModes (yield bn_mstring modename)@*/
176# define allModes(m_m) \
177 { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
178 { bn_mstring m_m = mode_names[m_ii]; m_ii++;
179
180# define end_allModes }}
181
182/*@+enumint@*/
183
4f43223c 184static cstring getFlagModeSettings (flagcode p_flag) /*@modifies internalState@*/ ;
616915dd 185static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
186static cstringSList sortedFlags (void) /*@*/ ;
187static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
8250fa4a 188
a956d444 189static flagcode flags_identifyFlagAux (cstring p_s, bool p_quiet) /*@modifies g_msgstream@*/ ;
190
8250fa4a 191# if 0
616915dd 192static /*@unused@*/ cstring listModes (void) /*@*/ ;
8250fa4a 193# endif
616915dd 194
195bool flagcode_isSpecialFlag (flagcode f)
196{
197 return (flags[f].isSpecial);
198}
199
200bool flagcode_isGlobalFlag (flagcode f)
201{
202 return (flags[f].isGlobal);
203}
204
205bool flagcode_isIdemFlag (flagcode f)
206{
207 return (flags[f].isIdem);
208}
209
210bool flagcode_isModeFlag (flagcode f)
211{
212 return (flags[f].isModeFlag);
213}
214
215bool flagcode_isNameChecksFlag (flagcode f)
216{
217 return (flags[f].main == FK_NAMES);
218}
219
220/*
221** Internal consistency check on the flags.
222*/
223
224void flags_initMod ()
225{
226 allFlagCodes (code)
227 {
228 /*@+enumint@*/
229 if (flags[code].code != code)
230 {
28bf4b0b 231 fprintf (stderr,
232 "*** ERROR: inconsistent flag %s / %d / %d",
233 flags[code].flag,
234 flags[code].code, code);
235
616915dd 236 llbug (message ("*** ERROR: inconsistent flag %s / %d / %d",
237 cstring_fromChars (flags[code].flag),
238 flags[code].code, code));
239 }
240 /*@=enumint@*/
241 } end_allFlagCodes;
242}
243
244void
245summarizeErrors ()
246{
247 bool hadOne = FALSE;
248 int sumrep = 0;
249 int sumsup = 0;
250
251 char *buf = mstring_create (128);
252
253 allFlags (f)
254 {
255 if (f.nreported > 0 || f.nsuppressed > 0)
256 {
257 int nrep = f.nreported;
258 int nsup = f.nsuppressed;
259 cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
260
261 if (!hadOne)
262 {
263 llmsgplain (cstring_makeLiteral
264 ("\nError Type Reported Suppressed\n"
265 "=================== ======== ========="));
266 hadOne = TRUE;
267 }
268
269 sprintf (buf, "%s%7d %9d", cstring_toCharsSafe (fs), nrep, nsup);
270
271 sumrep += nrep;
272 sumsup += nsup;
273
274 cstring_free (fs);
275 llmsg (cstring_copy (cstring_fromChars (buf)));
276 }
277 } end_allFlags;
278
279 if (hadOne)
280 {
281 cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
282
283 llmsglit (" ======== =========");
284
285 sprintf (buf, "%s%7d %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
286 cstring_free (ts);
287 llmsgplain (cstring_copy (cstring_fromChars (buf)));
288 }
289
290 sfree (buf);
291}
292
293/*@+enumindex@*/
294
295void
296flagcode_recordError (flagcode f)
297{
298 if (f != INVALID_FLAG)
299 {
300 if (f == FLG_WARNFLAGS)
301 {
302 ; /* don't count these */
303 }
304 else
305 {
306 flags[f].nreported = flags[f].nreported + 1;
307 }
308 }
309 else
310 {
311 llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
312 }
313}
314
315void
316flagcode_recordSuppressed (flagcode f)
317{
318 llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
319
320 flags[f].nsuppressed = flags[f].nsuppressed + 1;
321}
322
323int
324flagcode_numReported (flagcode f)
325{
326 llassert (f != INVALID_FLAG);
327
328 return (flags[f].nreported);
329}
330
331/*@observer@*/ cstring
332flagcodeHint (flagcode f)
333{
334 llassert (f != INVALID_FLAG);
335
336 if (mstring_isDefined (flags[f].hint))
337 {
338 return (cstring_fromChars (flags[f].hint));
339 }
340 else
341 {
342 return (cstring_fromChars (flags[f].desc));
343 }
344}
345
346static int categorySize (flagkind kind) /*@*/
347{
348 int n = 0;
349
350
351 allFlags (f)
352 {
353 if (f.main == kind || f.sub == kind)
354 {
355 n++;
356 }
357 } end_allFlags;
358
359 return n;
360}
361
362flagkind identifyCategory (cstring s)
363{
364 int i;
365
366 for (i = 0; categories[i].kind != FK_NONE; i++)
367 {
368 if (mstring_isDefined (categories[i].name))
369 {
370 if (cstring_equalLit (s, categories[i].name))
371 {
372 return categories[i].kind;
373 }
374 }
375 }
376
377 return FK_NONE;
378}
379
380static /*@observer@*/ cstring categoryName (flagkind kind)
381{
382 int i;
383
384 for (i = 0; categories[i].kind != FK_NONE; i++)
385 {
386 if (categories[i].kind == kind)
387 {
388 return (cstring_fromChars (categories[i].name));
389 }
390 }
391
392 return (cstring_makeLiteralTemp ("<No Category>"));
393}
394
395static int categoryIndex (flagkind kind)
396{
397 int i;
398
399 for (i = 0; categories[i].kind != FK_NONE; i++)
400 {
401 if (categories[i].kind == kind)
402 {
403 return i;
404 }
405 }
406
407 return -1;
408}
409
410void printCategory (flagkind kind)
411{
412 int index = categoryIndex (kind);
413
414 llassert (index >= 0);
415
416 llmsg (message ("%s (%d flags)\n\3%s\n\n",
417 cstring_fromChars (categories[index].name),
418 categorySize (kind),
419 cstring_fromChars (categories[index].describe)));
420
421 allFlags (f)
422 {
423 if (f.main == kind || f.sub == kind)
424 {
425 llmsg (message (" %s\n\6%q", cstring_fromChars (f.flag),
426 describeFlagCode (f.code)));
427 }
428 } end_allFlags;
429}
430
431void
432listAllCategories (void)
433{
434 int i;
435
436 for (i = 0; categories[i].kind != FK_NONE; i++)
437 {
438 flagkind kind = categories[i].kind ;
439
440 if (categories[i].describe != NULL)
441 {
442 llmsg (message ("%s (%d flags)\n\3%s",
443 categoryName (kind),
444 categorySize (kind),
445 cstring_fromChars (categories[i].describe)));
446 }
447 }
448}
449
450void
451printAllFlags (bool desc, bool full)
452{
453 if (full)
454 {
455 cstringSList fl = sortedFlags ();
456
457 cstringSList_elements (fl, el)
458 {
459 llmsg (message ("%q\n\n", describeFlag (el)));
460 } end_cstringSList_elements ;
461
462 cstringSList_free (fl);
463 }
464 else
465 {
466 allFlags (f)
467 {
468 if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
469 {
470 if (mstring_isDefined (f.desc))
471 {
472 if (desc)
473 {
474 llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
475 cstring_fromChars (f.desc)));
476 }
477 }
478 }
479 } end_allFlags;
480 }
481}
482
4f43223c 483void
45569d72 484printFlagManual (bool html)
4f43223c 485{
486 /*
487 ** Prints all flags by category, in order they appear in flags.def
488 */
489
490 flagkind lastCategory = FK_NONE;
491
492 allFlags (f) {
493 cstring flagname;
494 cstring flagtype = cstring_undefined;
495
496 if (f.main != lastCategory)
497 {
45569d72 498 if (html)
499 {
500 llmsg (message ("\n<h4>%s</h4>\n", categoryName (f.main)));
501 }
502 else
503 {
504 llmsg (message ("\n%s\n%s\n",
505 categoryName (f.main),
506 cstring_makeLiteralTemp ("===================================")));
507 }
4f43223c 508
509 lastCategory = f.main;
510 }
511
512 if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
513 {
45569d72 514 if (html)
515 {
516 flagname = message ("<tt>%s</tt>", cstring_fromChars (f.flag));
517 }
518 else
519 {
520 flagname = cstring_fromCharsNew (f.flag);
521 }
4f43223c 522 }
523 else
524 {
525 if (flagcode_hasString (f.code))
526 {
45569d72 527 if (html)
528 {
529 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt>",
530 cstring_fromChars (f.flag), argcode_unparse (f.argtype));
531 }
532 else
533 {
534 flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
535 }
536
982cc10b 537 if (cstring_isDefined (context_getString (f.code)))
538 {
45569d72 539 if (html)
540 {
541 flagname = message ("%q <font color=\"blue\">[%s]</font>", flagname,
542 context_getString (f.code));
543 }
544 else
545 {
546 flagname = message ("%q [%s]", flagname,
547 context_getString (f.code));
548 }
982cc10b 549 }
4f43223c 550 }
551 else if (f.argtype == ARG_CHAR)
552 {
45569d72 553 if (html)
554 {
555 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt> <font color=\"blue\">[%c]</font>",
556 cstring_fromChars (f.flag), argcode_unparse (f.argtype),
557 (char) context_getValue (f.code));
558 }
559 else
560 {
561 flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
562 (char) context_getValue (f.code));
563 }
4f43223c 564 }
565 else
566 {
567 llassert (f.argtype == ARG_NUMBER);
45569d72 568
569 if (html)
570 {
571 flagname = message ("<tt>%s <em>&lt;%s&gt;</em> <font color=\"blue\">[%d]</font>",
572 cstring_fromChars (f.flag), argcode_unparse (f.argtype),
573 context_getValue (f.code));
574 }
575 else
576 {
577 flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
578 context_getValue (f.code));
579 }
4f43223c 580 }
581 }
582
583 if (f.isIdem)
584 {
45569d72 585 if (html)
586 {
587 flagtype = message("%q<font color=\"green\">-</font>", flagtype);
588 }
589 else
590 {
591 flagtype = message("%q<->", flagtype);
592 }
4f43223c 593 }
4f43223c 594
595 if (f.isGlobal)
596 {
45569d72 597 if (html)
598 {
599 flagtype = message ("%q<font color=\"green\"><em>global</em></font>", flagtype);
600 }
601 else
602 {
603 flagtype = message ("%q<G>", flagtype);
604 }
4f43223c 605 }
606
607 if (f.isSpecial)
608 {
45569d72 609 if (html)
610 {
611 flagtype = message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype);
612 }
613 else
614 {
615 flagtype = message("%q<S>", flagtype);
616 }
4f43223c 617 }
618
619 if (f.isModeFlag)
620 {
45569d72 621 if (html)
622 {
623 flagtype = message ("%q mode:<tt>%q</tt>>", flagtype, getFlagModeSettings (f.code));
624 }
625 else
626 {
627 flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
628 }
4f43223c 629 }
630 else /* its a plain flag */
631 {
45569d72 632 if (html)
633 {
634 flagtype = message ("%q plain:<tt>%s</tt>", flagtype,
635 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
636 }
637 else
638 {
639 flagtype = message ("%q<P:%s>", flagtype,
640 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
641 }
4f43223c 642 }
bb7c2085 643
4f43223c 644 llmsg (message ("%s: %s", flagname, flagtype));
bb7c2085 645
45569d72 646 if (html)
647 {
648 llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
649 }
650
bb7c2085 651 if (mstring_isDefined (f.hint))
652 {
653 llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
654 }
655 else
656 {
657 llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
658 }
45569d72 659
660 if (html)
661 {
662 llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
663 }
4f43223c 664 } end_allFlags ;
665}
666
616915dd 667cstring
668describeFlagCode (flagcode flag)
669{
670 cstring ret = cstring_undefined;
671 fflag f;
4f43223c 672
616915dd 673 if (flagcode_isInvalid (flag))
674 {
675 return (cstring_makeLiteral ("<invalid>"));
676 }
677
678 context_resetAllFlags ();
679
680 f = flags[flag];
681 ret = cstring_copy (cstring_fromChars (f.desc));
616915dd 682
683 if (f.sub != FK_NONE)
684 {
685 ret = message ("%q\nCategories: %s, %s",
686 ret,
687 categoryName (f.main),
688 categoryName (f.sub));
689 }
690 else
691 {
692 if (f.main != FK_NONE)
693 {
694 cstring cname = categoryName (f.main);
695
696 if (cstring_isDefined (cname))
697 {
698 ret = message ("%q\nCategory: %s",
699 ret, cname);
700 }
701 }
702 }
4f43223c 703
616915dd 704 if (f.isModeFlag)
705 {
4f43223c 706 ret = message ("%q\nMode Settings: %q",
707 ret, getFlagModeSettings (flag));
616915dd 708 }
709 else
710 {
711 ret = message ("%q\nDefault Setting: %s",
712 ret,
4f43223c 713 cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
616915dd 714 }
4f43223c 715
616915dd 716 if (f.isGlobal)
717 {
718 ret = message("%q\nSet globally only", ret);
719 }
720 else
721 {
722 ret = message("%q\nSet locally", ret);
723 }
4f43223c 724
616915dd 725 switch (f.argtype)
726 {
727 case ARG_NONE:
728 case ARG_SPECIAL:
729 break;
4f43223c 730 case ARG_NUMBER:
731 ret = message("%q\nNumeric Argument. Default: %d",
732 ret,
733 context_getValue (flag));
734 break;
735 case ARG_CHAR:
736 ret = message("%q\nCharacter Argument. Default: %h",
737 ret, (char) context_getValue (flag));
616915dd 738 break;
739 case ARG_STRING:
4f43223c 740 case ARG_FILE:
741 case ARG_PATH:
742 case ARG_DIRECTORY:
743 {
616915dd 744 if (cstring_isDefined (context_getString (flag)))
745 {
4f43223c 746 ret = message("%q\n%q argument. Default: %s",
616915dd 747 ret,
4f43223c 748 cstring_capitalize (argcode_unparse (f.argtype)),
616915dd 749 context_getString (flag));
750 }
751 else
752 {
4f43223c 753 ret = message("%q\n%s argument. No default.",
754 ret,
755 cstring_capitalize (argcode_unparse (f.argtype)));
616915dd 756 }
757 break;
4f43223c 758 }
616915dd 759 }
4f43223c 760
616915dd 761 if (mstring_isDefined (f.hint))
762 {
763 ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
764 }
4f43223c 765
616915dd 766 return ret;
767}
4f43223c 768
769static cstring getFlagModeSettings (flagcode flag)
770{
771 cstring res = cstring_undefined;
772
773 allModes (mname)
774 {
982cc10b 775 context_setModeNoWarn (cstring_fromChars (mname));
4f43223c 776
777 res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
778 } end_allModes;
779
780 return res;
781}
616915dd 782
783cstring
784describeFlag (cstring flagname)
785{
786 cstring oflagname = cstring_copy (flagname);
a956d444 787 flagcode f = flags_identifyFlag (flagname);
616915dd 788
789 if (flagcode_isSkip (f))
790 {
791 cstring_free (oflagname);
792 return cstring_undefined;
793 }
794 else if (flagcode_isValid (f))
795 {
796 if (cstring_equal (flagname, oflagname))
797 {
798 cstring_free (oflagname);
799 return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
800 }
801 else
802 {
803 return (message ("%q (standardized name: %s)\n\3%q",
804 oflagname, flagname, describeFlagCode (f)));
805 }
806 }
807 else
808 {
809 if (isMode (flagname))
810 {
811 cstring_free (oflagname);
812
813 return
4f43223c 814 (message ("%s: predefined mode (see Manual for information)",
616915dd 815 flagname));
816 }
817 else
818 {
819 return (message ("%q: <invalid flag>", oflagname));
820 }
821 }
822}
823
824static cstringSList
825sortedFlags (void)
826{
827 cstringSList s = cstringSList_new ();
828
829 allFlags (f)
830 {
831 if (f.desc != NULL)
832 {
833 s = cstringSList_add (s, cstring_fromChars (f.flag));
834 }
835 } end_allFlags;
836
837 cstringSList_alphabetize (s);
838
839 return s;
840}
841
842void printAlphaFlags ()
843{
844 cstringSList fl = sortedFlags ();
845
846 cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25);
847 cstringSList_free (fl);
848}
28bf4b0b 849
616915dd 850/*@observer@*/ cstring
28bf4b0b 851flagcode_unparse (flagcode code)
616915dd 852{
7272a1c1 853 if (code == INVALID_FLAG)
854 {
855 return cstring_makeLiteralTemp ("<invalid flag>");
856 }
857
616915dd 858 return cstring_fromChars (flags[code].flag);
859}
860
861/*
862** Transforms a flag into its cannonical form.
863**
864** The following transformations are made:
865**
866** function -> fcn
867** variable -> var
868** constant -> const
869** iterator -> iter
870** parameter -> param
871** unrecognized -> unrecog
872** qualifier -> qual
873** declaration -> decl
874** globalias -> (no change)
875** global -> glob
876** modifies -> mods
877** modify -> mod
878** pointer -> ptr
879** implies -> imp
880** implicit -> imp
881** implied -> imp
882** unconstrained -> unspec
883** unconst -> unspec
884** memory -> mem
885** length -> len
886*/
887
888static void
889canonicalizeFlag (cstring s)
890{
891 int i = 0;
892 static bn_mstring transform[] =
893 {
894 "function", "fcn",
895 "variable", "var",
896 "constant", "const",
897 "iterator", "iter",
898 "parameter", "param",
899 "unrecognized", "unrecog",
900 "qualifier", "qual",
901 "declaration", "decl",
902 "globals", "globs",
903 "modifies", "mods",
904 "modify", "mod",
905 "pointer", "ptr",
906 "implies", "imp",
907 "implicit", "imp",
908 "implied", "imp",
909 "unconstrained", "uncon",
910 "unconst", "uncon",
911 "memory", "mem",
912 "length", "len",
913 "return", "ret",
914 "system", "sys",
915 NULL
916 } ;
917 char *current;
918
919 while ((current = transform[i]) != NULL)
920 {
921 if (cstring_containsLit (s, current))
922 {
923 cstring_replaceLit (s, current, transform[i+1]);
924 }
925 i += 2;
926 }
927
928 /* remove whitespace, -'s, and _'s */
929 cstring_stripChars (s, " -_");
930}
931
932flagcode
a956d444 933flags_identifyFlag (cstring s)
934{
935 return flags_identifyFlagAux (s, FALSE);
936}
937
938flagcode
939flags_identifyFlagQuiet (cstring s)
940{
941 return flags_identifyFlagAux (s, TRUE);
942}
943
944static flagcode
945flags_identifyFlagAux (cstring s, bool quiet)
616915dd 946{
947 if (cstring_length (s) == 0) {
948 /* evs 2000-06-25: A malformed flag. */
949 return INVALID_FLAG;
950 }
951
952 if (cstring_firstChar (s) == 'I')
953 {
954 return FLG_INCLUDEPATH; /* no space after -I */
955 }
956
957 if (cstring_firstChar (s) == 'S')
958 {
959 return FLG_SPECPATH; /* no space after -S */
960 }
961
962 if (cstring_firstChar (s) == 'D')
963 {
964 return FLG_DEFINE; /* no space after -D */
965 }
966
967 if (cstring_firstChar (s) == 'U')
968 {
969 return FLG_UNDEFINE; /* no space after -D */
970 }
971
972 canonicalizeFlag (s);
973
974 allFlags (f)
975 {
976 if (cstring_equal (cstring_fromChars (f.flag), s))
977 {
978 return (f.code);
979 }
980 } end_allFlags;
981
982 /*
983 ** Synonyms
984 */
985
986 if (cstring_equalLit (s, "pred"))
987 {
988 return FLG_PREDBOOL;
989 }
990
991 if (cstring_equalLit (s, "modobserverstrict"))
992 {
993 return FLG_MODOBSERVERUNCON;
994 }
995
996 if (cstring_equalLit (s, "czechnames"))
997 {
998 return FLG_CZECH;
999 }
1000
1001 if (cstring_equalLit (s, "slovaknames"))
1002 {
1003 return FLG_SLOVAK;
1004 }
1005
1006 if (cstring_equalLit (s, "czechoslovaknames"))
1007 {
1008 return FLG_CZECHOSLOVAK;
1009 }
1010
1011 if (cstring_equalLit (s, "globunspec")
1012 || cstring_equalLit (s, "globuncon"))
1013 {
1014 return FLG_GLOBUNSPEC;
1015 }
1016
1017 if (cstring_equalLit (s, "modglobsunspec")
1018 || cstring_equalLit (s, "modglobsuncon")
1019 || cstring_equalLit (s, "modglobsnomods"))
1020 {
1021 return FLG_MODGLOBSUNSPEC;
1022 }
1023
1024 if (cstring_equalLit (s, "export"))
1025 {
1026 return FLG_EXPORTANY;
1027 }
1028
1029 if (cstring_equalLit (s, "macrospec"))
1030 {
1031 return FLG_MACRODECL;
1032 }
1033
1034 if (cstring_equalLit (s, "ansireservedlocal"))
1035 {
1036 return FLG_ANSIRESERVEDLOCAL;
1037 }
1038
1039 if (cstring_equalLit (s, "warnposix"))
1040 {
1041 return FLG_WARNPOSIX;
1042 }
1043
1044 if (cstring_equalLit (s, "defuse"))
1045 {
1046 return FLG_USEDEF;
1047 }
1048
1049 if (cstring_equalLit (s, "macroundef"))
1050 {
1051 return FLG_MACROUNDEF;
1052 }
1053
1054 if (cstring_equalLit (s, "showcol"))
1055 {
1056 return FLG_SHOWCOL;
1057 }
1058
1059 if (cstring_equalLit (s, "intbool"))
1060 {
1061 return FLG_BOOLINT;
1062 }
1063
1064 if (cstring_equalLit (s, "intchar"))
1065 {
1066 return FLG_CHARINT;
1067 }
1068
1069 if (cstring_equalLit (s, "intenum"))
1070 {
1071 return FLG_ENUMINT;
1072 }
1073
1074 /*
27c9e640 1075 ** Backwards compatibility for our American friends...
616915dd 1076 */
1077
27c9e640 1078 if (cstring_equalLit (s, "ansilib"))
616915dd 1079 {
1080 return FLG_ANSILIB;
1081 }
1082
616915dd 1083 if (cstring_equalLit (s, "ansistrictlib"))
1084 {
1085 return FLG_STRICTLIB;
1086 }
1087
27c9e640 1088 if (cstring_equalLit (s, "skipansiheaders"))
616915dd 1089 {
1090 return FLG_SKIPANSIHEADERS;
1091 }
1092
27c9e640 1093 if (cstring_equalLit (s, "ansireserved"))
616915dd 1094 {
1095 return FLG_ANSIRESERVED;
1096 }
1097
27c9e640 1098 if (cstring_equalLit (s, "ansireservedinternal"))
616915dd 1099 {
1100 return FLG_ANSIRESERVEDLOCAL;
1101 }
1102
616915dd 1103 /*
1104 ** Obsolete Flags
1105 */
1106
1107 if (cstring_equalLit (s, "accessunspec"))
1108 {
a956d444 1109 if (!quiet)
1110 {
1111 llerror_flagWarning
1112 (cstring_makeLiteral
1113 ("accessunspec flag is no longer supported. It has been replaced by accessmodule, accessfile and "
1114 "accessfunction to provide more precise control of accessibility "
1115 "of representations. For more information, "
1b8ae690 1116 "see splint -help accessmodule"));
a956d444 1117 }
616915dd 1118
27c9e640 1119 return SKIP_FLAG;
1120 }
1121 else if (cstring_equalLit (s, "ansilimits"))
1122 {
1123 llerror_flagWarning
1124 (cstring_makeLiteral
1125 ("ansilimits flag is no longer supported. It has been replaced by ansi89limits and "
1126 "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1127 "standard or the typically higher limits prescribed by ISO C99."));
1128
616915dd 1129 return SKIP_FLAG;
1130 }
a956d444 1131 else if (cstring_equalLit (s, "staticmods"))
1132 {
1133 if (!quiet)
1134 {
1135 llerror_flagWarning
1136 (cstring_makeLiteral
1137 ("staticmods flag is obsolete. You probably "
1138 "want impcheckmodstatics. For more information, "
1b8ae690 1139 "see splint -help impcheckmodstatics"));
a956d444 1140 }
616915dd 1141
a956d444 1142 return SKIP_FLAG;
1143 }
1144 else if (cstring_equalLit (s, "bool"))
616915dd 1145 {
a956d444 1146 if (!quiet)
1147 {
1148 llerror_flagWarning
1149 (cstring_makeLiteral ("bool flag is obsolete. It never really "
1150 "made sense in the first place."));
1151 }
616915dd 1152
1153 return SKIP_FLAG;
1154 }
a956d444 1155 else if (cstring_equalLit (s, "shiftsigned"))
616915dd 1156 {
a956d444 1157 if (!quiet)
1158 {
1159 llerror_flagWarning
1160 (cstring_makeLiteral ("shiftsigned flag is obsolete. You probably "
1161 "want bitwisesigned, shiftnegative or shiftsize."));
1162 }
616915dd 1163
1164 return SKIP_FLAG;
1165 }
a956d444 1166 else if (cstring_equalLit (s, "ansi"))
616915dd 1167 {
a956d444 1168 if (!quiet)
1169 {
1170 llerror_flagWarning
1171 (cstring_makeLiteral ("ansi flag is obsolete. You probably "
1172 "want noparams and/or oldstyle."));
1173 }
616915dd 1174
1175 return SKIP_FLAG;
1176 }
a956d444 1177 else if (cstring_equalLit (s, "stdio"))
1178 {
1179 if (!quiet)
1180 {
1181 llerror_flagWarning
1182 (cstring_makeLiteral
1183 ("stdio flag is obsolete. You may "
1184 "want strictlib or one of the gloabls "
1185 "checking flags. For more information, "
1b8ae690 1186 "see splint -help strictlib or splint -help flags globals"));
a956d444 1187 }
616915dd 1188
1189 return SKIP_FLAG;
1190 }
a956d444 1191 else
1192 {
1193 return INVALID_FLAG;
1194 }
616915dd 1195}
1196
1197void setValueFlag (flagcode opt, cstring arg)
1198{
1199 switch (opt)
1200 {
1201 case FLG_EXPECT:
1202 case FLG_LCLEXPECT:
1203 case FLG_LIMIT:
1204 case FLG_LINELEN:
28bf4b0b 1205 case FLG_INDENTSPACES:
1206 case FLG_BUGSLIMIT:
616915dd 1207 case FLG_EXTERNALNAMELEN:
1208 case FLG_INTERNALNAMELEN:
1209 case FLG_CONTROLNESTDEPTH:
1210 case FLG_STRINGLITERALLEN:
1211 case FLG_NUMSTRUCTFIELDS:
1212 case FLG_NUMENUMMEMBERS:
1213 case FLG_INCLUDENEST:
1214 {
1215 int val = cstring_toPosInt (arg);
1216
1217 if (val < 0)
1218 {
1219 llerror
1220 (FLG_BADFLAG,
1221 message
1222 ("Flag %s must be followed by a positive number number. "
1223 "Followed by %s",
1224 flagcode_unparse (opt), arg));
1225 }
1226 else
1227 {
28bf4b0b 1228 context_setValueAndFlag (opt, val);
616915dd 1229 }
1230 }
1231 break;
1232 case FLG_COMMENTCHAR:
1233 {
1234 if (cstring_length (arg) != 1)
1235 {
1236 llfatalerrorLoc
1237 (message
1238 ("Flag %s should be followed by a single character. Followed by %s",
1239 flagcode_unparse (opt), arg));
1240 }
1241 else
1242 {
1243 context_setCommentMarkerChar (cstring_firstChar (arg));
1244 }
1245 }
1246 break;
1247 BADDEFAULT;
1248 }
1249}
1250
1251void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1252{
1253 switch (opt)
1254 {
1255 case FLG_TMPDIR:
1256 {
1257 if (cstring_lastChar (arg) == CONNECTCHAR)
1258 {
1259 context_setString (opt, arg);
1260 }
1261 else
1262 {
1263 context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1264 }
1265 break;
1266 }
1267 default:
1268 {
1269 context_setString (opt, arg);
1270 break;
1271 }
1272 }
1273}
1274
1275cstring
1276describeModes ()
1277{
1278 cstring s = cstring_makeLiteral ("Flag ");
1279 cstringSList sflags = sortedFlags ();
1280
1281 allModes (modename)
1282 {
1283 s = message ("%q%9s", s, cstring_fromChars (modename));
1284 } end_allModes;
1285
1286 s = message ("%q\n", s);
1287
1288 cstringSList_elements (sflags, flagname)
1289 {
a956d444 1290 flagcode code = flags_identifyFlag (flagname);
616915dd 1291 fflag currentflag = flags[code];
1292
1293 if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1294 {
1295 s = message ("%q\n%27s", s,
1296 cstring_fromChars (currentflag.flag));
1297
1298 allModes (modename)
1299 {
1300 context_setMode (cstring_fromChars (modename));
1301
1302 if (context_getFlag (code))
1303 {
1304 s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1305 }
1306 else
1307 {
1308 s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1309 }
1310
1311 context_resetModeFlags ();
1312 } end_allModes;
1313 }
1314 } end_cstringSList_elements;
1315
1316 cstringSList_free (sflags);
1317
1318 s = cstring_appendChar (s, '\n');
1319
1320 return (s);
1321}
1322
8250fa4a 1323# if 0
ee229125 1324static /*@unused@*/ cstring
616915dd 1325listModes (void)
1326{
1327 cstring s = cstring_makeLiteral ("\t");
1328 int i = 0;
1329
1330 allModes (modename)
1331 {
1332 if (i != 0 && (i % 4 == 0))
1333 {
1334 s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1335 }
1336 else
1337 {
1338 s = message ("%q%15s", s, cstring_fromChars (modename));
1339 }
1340 i++;
1341 } end_allModes;
1342
1343 return s;
1344}
8250fa4a 1345# endif
616915dd 1346
1347bool
1348isMode (cstring s)
1349{
1350 allModes (modename)
1351 {
1352 if (mstring_isDefined (modename))
1353 {
1354 if (cstring_equalLit (s, modename))
1355 {
1356 return TRUE;
1357 }
1358 }
1359 } end_allModes;
1360
1361 return FALSE;
1362}
1363
1364extern bool flagcode_hasArgument (flagcode f)
1365{
1366 return (flags[f].argtype != ARG_NONE);
1367}
1368
4f43223c 1369extern bool flagcode_hasNumber (flagcode f)
1370{
1371 return (flags[f].argtype == ARG_NUMBER);
1372}
1373
1374extern bool flagcode_hasChar (flagcode f)
616915dd 1375{
4f43223c 1376 return (flags[f].argtype == ARG_CHAR);
616915dd 1377}
1378
1379extern bool flagcode_hasString (flagcode f)
1380{
4f43223c 1381 return (flags[f].argtype == ARG_STRING
1382 || flags[f].argtype == ARG_FILE
1383 || flags[f].argtype == ARG_DIRECTORY
1384 || flags[f].argtype == ARG_PATH);
616915dd 1385}
1386
1387extern int flagcode_valueIndex (flagcode f)
1388{
1389 /*@unchecked@*/ static bool initialized = FALSE;
1390 int i;
1391 /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
616915dd 1392
1393 if (!initialized)
1394 {
1395 int nv = 0;
1396
1397 allFlagCodes (code)
1398 {
4f43223c 1399 if (flagcode_hasNumber (code) || flagcode_hasChar (code))
616915dd 1400 {
1401 llassert (nv < NUMVALUEFLAGS);
28bf4b0b 1402 DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
616915dd 1403 valueFlags[nv] = code;
28bf4b0b 1404 nv++;
616915dd 1405 }
1406 } end_allFlagCodes;
1407
1408 llassertprint (nv == NUMVALUEFLAGS,
28bf4b0b 1409 ("Number of value flags: %d (expected %d)",
1410 nv, (int) NUMVALUEFLAGS));
616915dd 1411 initialized = TRUE;
1412 }
1413
1414 for (i = 0; i < NUMVALUEFLAGS; i++)
1415 {
1416 /* static valueFlags must be defined */
1417 /*@-usedef@*/ if (f == valueFlags[i]) /*@=usedef@*/
1418 {
1419 return i;
1420 }
1421 }
1422
28bf4b0b 1423 fprintf (stderr, "Cannot find value flag: %d", (int) f);
1424 exit (EXIT_FAILURE);
1425 /* Cannot do this...might call recursively...
1426 llfatalbug (message ("Cannot fine value flag: %d", (int) f));
616915dd 1427 BADEXIT;
28bf4b0b 1428 */
616915dd 1429}
1430
1431extern int flagcode_stringIndex (flagcode f)
1432{
1433 /*@unchecked@*/ static bool initialized = FALSE;
1434 /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1435 int i;
1436
1437
1438 if (!initialized)
1439 {
1440 int nv = 0;
1441
1442 allFlagCodes (code)
1443 {
1444 if (flagcode_hasString (code))
1445 {
1446 llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1447 stringFlags[nv] = code;
1448 nv++;
1449 }
1450 } end_allFlagCodes;
1451
1452 llassertprint (nv == NUMSTRINGFLAGS,
1453 ("number of string flags: %d (expected %d)",
1454 nv, NUMSTRINGFLAGS));
1455 initialized = TRUE;
1456 }
1457
1458 for (i = 0; i < NUMSTRINGFLAGS; i++)
1459 {
1460 /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1461 {
1462 return i;
1463 }
1464 }
1465
1466 llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1467 BADEXIT;
1468}
1469
1470bool flagcode_isNamePrefixFlag (flagcode f)
1471{
1472 switch (f)
1473 {
1474 case FLG_MACROVARPREFIX:
1475 case FLG_TAGPREFIX:
1476 case FLG_ENUMPREFIX:
1477 case FLG_FILESTATICPREFIX:
1478 case FLG_GLOBPREFIX:
1479 case FLG_TYPEPREFIX:
1480 case FLG_EXTERNALPREFIX:
1481 case FLG_LOCALPREFIX:
1482 case FLG_UNCHECKEDMACROPREFIX:
1483 case FLG_CONSTPREFIX:
1484 case FLG_ITERPREFIX:
1485 case FLG_DECLPARAMPREFIX:
1486 return TRUE;
1487 default:
1488 return FALSE;
1489 }
1490}
1491
This page took 0.257247 seconds and 5 git commands to generate.