Line data Source code
1 : /* This file is part of GNU cflow
2 : Copyright (C) 1997, 2005, 2007, 2009, 2010, 2011 Sergey Poznyakoff
3 :
4 : GNU cflow is free software; you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation; either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : GNU cflow is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public
15 : License along with GNU cflow; if not, write to the Free Software
16 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 : MA 02110-1301 USA */
18 :
19 : #include <cflow.h>
20 : #include <argp.h>
21 : #include <argp-version-etc.h>
22 : #include <progname.h>
23 : #include <stdarg.h>
24 : #include <parser.h>
25 : #include <version-etc.h>
26 :
27 : const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
28 : static char doc[] = N_("generate a program flowgraph")
29 : "\v"
30 : N_("* The effect of each option marked with an asterisk is reversed if the option's long name is prefixed with `no-'. For example, --no-cpp cancels --cpp.");
31 : const char *program_authors[] = {
32 : "Sergey Poznyakoff",
33 : NULL
34 : };
35 :
36 : enum option_code {
37 : OPT_DEFINES = 256,
38 : OPT_LEVEL_INDENT,
39 : OPT_DEBUG,
40 : OPT_PREPROCESS,
41 : OPT_NO_PREPROCESS,
42 : OPT_EMACS,
43 : OPT_NO_USE_INDENTATION,
44 : OPT_NO_ANSI,
45 : OPT_NO_TREE,
46 : OPT_NO_BRIEF,
47 : OPT_NO_EMACS,
48 : OPT_NO_VERBOSE,
49 : OPT_NO_NUMBER,
50 : OPT_NO_PRINT_LEVEL,
51 : OPT_NO_REVERSE,
52 : OPT_OMIT_ARGUMENTS,
53 : OPT_NO_OMIT_ARGUMENTS,
54 : OPT_OMIT_SYMBOL_NAMES,
55 : OPT_NO_OMIT_SYMBOL_NAMES
56 : };
57 :
58 : static struct argp_option options[] = {
59 : #define GROUP_ID 0
60 : { NULL, 0, NULL, 0,
61 : N_("General options:"), GROUP_ID },
62 : { "depth", 'd', N_("NUMBER"), 0,
63 : N_("Set the depth at which the flowgraph is cut off"), GROUP_ID+1 },
64 : { "include", 'i', N_("CLASSES"), 0,
65 : N_("Include specified classes of symbols (see below). Prepend CLASSES with ^ or - to exclude them from the output"), GROUP_ID+1 },
66 : { "format", 'f', N_("NAME"), 0,
67 : N_("Use given output format NAME. Valid names are `gnu' (default) and `posix'"),
68 : GROUP_ID+1 },
69 : { "reverse", 'r', NULL, 0,
70 : N_("* Print reverse call tree"), GROUP_ID+1 },
71 : { "xref", 'x', NULL, 0,
72 : N_("Produce cross-reference listing only"), GROUP_ID+1 },
73 : { "print", 'P', N_("OPT"), OPTION_HIDDEN,
74 : N_("Set printing option to OPT. Valid OPT values are: xref (or cross-ref), tree. Any unambiguous abbreviation of the above is also accepted"),
75 : GROUP_ID+1 },
76 : { "output", 'o', N_("FILE"), 0,
77 : N_("Set output file name (default -, meaning stdout)"),
78 : GROUP_ID+1 },
79 :
80 : { NULL, 0, NULL, 0, N_("Symbols classes for --include argument"), GROUP_ID+2 },
81 : {" x", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
82 : N_("all data symbols, both external and static"), GROUP_ID+3 },
83 : {" _", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
84 : N_("symbols whose names begin with an underscore"), GROUP_ID+3 },
85 : {" s", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
86 : N_("static symbols"), GROUP_ID+3 },
87 : {" t", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
88 : N_("typedefs (for cross-references only)"), GROUP_ID+3 },
89 :
90 :
91 : #undef GROUP_ID
92 : #define GROUP_ID 10
93 : { NULL, 0, NULL, 0,
94 : N_("Parser control:"), GROUP_ID },
95 : { "use-indentation", 'S', NULL, 0,
96 : N_("* Rely on indentation"), GROUP_ID+1 },
97 : { "no-use-indentation", OPT_NO_USE_INDENTATION, NULL, OPTION_HIDDEN,
98 : "", GROUP_ID+1 },
99 : { "ansi", 'a', NULL, 0,
100 : N_("* Accept only sources in ANSI C"), GROUP_ID+1 },
101 : { "no-ansi", OPT_NO_ANSI, NULL, OPTION_HIDDEN,
102 : "", GROUP_ID+1 },
103 : { "pushdown", 'p', N_("NUMBER"), 0,
104 : N_("Set initial token stack size to NUMBER"), GROUP_ID+1 },
105 : { "symbol", 's', N_("SYMBOL:[=]TYPE"), 0,
106 : N_("Register SYMBOL with given TYPE, or define an alias (if := is used). Valid types are: keyword (or kw), modifier, qualifier, identifier, type, wrapper. Any unambiguous abbreviation of the above is also accepted"), GROUP_ID+1 },
107 : { "main", 'm', N_("NAME"), 0,
108 : N_("Assume main function to be called NAME"), GROUP_ID+1 },
109 : { "define", 'D', N_("NAME[=DEFN]"), 0,
110 : N_("Predefine NAME as a macro"), GROUP_ID+1 },
111 : { "undefine", 'U', N_("NAME"), 0,
112 : N_("Cancel any previous definition of NAME"), GROUP_ID+1 },
113 : { "include-dir", 'I', N_("DIR"), 0,
114 : N_("Add the directory DIR to the list of directories to be searched for header files."), GROUP_ID+1 },
115 : { "preprocess", OPT_PREPROCESS, N_("COMMAND"), OPTION_ARG_OPTIONAL,
116 : N_("* Run the specified preprocessor command"), GROUP_ID+1 },
117 : { "cpp", 0, NULL, OPTION_ALIAS, NULL, GROUP_ID+1 },
118 : { "no-preprocess", OPT_NO_PREPROCESS, NULL, OPTION_HIDDEN,
119 : "", GROUP_ID+1 },
120 : { "no-cpp", 0, NULL, OPTION_ALIAS|OPTION_HIDDEN, NULL, GROUP_ID+1 },
121 : #undef GROUP_ID
122 : #define GROUP_ID 20
123 : { NULL, 0, NULL, 0,
124 : N_("Output control:"), GROUP_ID },
125 : { "number", 'n', NULL, 0,
126 : N_("* Print line numbers"), GROUP_ID+1 },
127 : { "no-number", OPT_NO_NUMBER, NULL, OPTION_HIDDEN,
128 : "", GROUP_ID+1 },
129 : { "print-level", 'l', NULL, 0,
130 : N_("* Print nesting level along with the call tree"), GROUP_ID+1 },
131 : { "no-print-level", OPT_NO_PRINT_LEVEL, NULL, OPTION_HIDDEN,
132 : "", GROUP_ID+1 },
133 : { "level-indent", OPT_LEVEL_INDENT, "ELEMENT", 0,
134 : N_("Control graph appearance"), GROUP_ID+1 },
135 : { "tree", 'T', NULL, 0,
136 : N_("* Draw ASCII art tree"), GROUP_ID+1 },
137 : { "no-tree", OPT_NO_TREE, NULL, OPTION_HIDDEN,
138 : "", GROUP_ID+1 },
139 : { "brief", 'b', NULL, 0,
140 : N_("* Brief output"), GROUP_ID+1 },
141 : { "no-brief", OPT_NO_BRIEF, NULL, OPTION_HIDDEN,
142 : "", GROUP_ID+1 },
143 : { "emacs", OPT_EMACS, NULL, 0,
144 : N_("* Additionally format output for use with GNU Emacs"), GROUP_ID+1 },
145 : { "no-emacs", OPT_NO_EMACS, NULL, OPTION_HIDDEN,
146 : "", GROUP_ID+1 },
147 : { "omit-arguments", OPT_OMIT_ARGUMENTS, NULL, 0,
148 : N_("* Do not print argument lists in function declarations"), GROUP_ID+1 },
149 : { "no-ignore-arguments", OPT_NO_OMIT_ARGUMENTS, NULL, OPTION_HIDDEN,
150 : "", GROUP_ID+1 },
151 : { "omit-symbol-names", OPT_OMIT_SYMBOL_NAMES, NULL, 0,
152 : N_("* Do not print symbol names in declaration strings"), GROUP_ID+1 },
153 : { "no-omit-symbol-names", OPT_NO_OMIT_SYMBOL_NAMES, NULL, OPTION_HIDDEN,
154 : "", GROUP_ID+1 },
155 : #undef GROUP_ID
156 : #define GROUP_ID 30
157 : { NULL, 0, NULL, 0,
158 : N_("Informational options:"), GROUP_ID },
159 : { "verbose", 'v', NULL, 0,
160 : N_("* Verbose error diagnostics"), GROUP_ID+1 },
161 : { "no-verbose", OPT_NO_VERBOSE, NULL, OPTION_HIDDEN,
162 : "", GROUP_ID+1 },
163 : { "debug", OPT_DEBUG, "NUMBER", OPTION_ARG_OPTIONAL,
164 : N_("Set debugging level"), GROUP_ID+1 },
165 : #undef GROUP_ID
166 : { 0, }
167 : };
168 :
169 : /* Structure representing various arguments of command line options */
170 : struct option_type {
171 : char *str; /* optarg value */
172 : int min_match; /* minimal number of characters to match */
173 : int type; /* data associated with the arg */
174 : };
175 :
176 : int debug; /* debug level */
177 : char *outname = "-"; /* default output file name */
178 : int print_option = 0; /* what to print. */
179 : int verbose; /* be verbose on output */
180 : int use_indentation; /* Rely on indentation,
181 : * i.e. suppose the function body
182 : * is necessarily surrounded by the curly braces
183 : * in the first column
184 : */
185 : int record_defines; /* Record macro definitions */
186 : int strict_ansi; /* Assume sources to be written in ANSI C */
187 : int print_line_numbers; /* Print line numbers */
188 : int print_levels; /* Print level number near every branch */
189 : int print_as_tree; /* Print as tree */
190 : int brief_listing; /* Produce short listing */
191 : int reverse_tree; /* Generate reverse tree */
192 : int max_depth; /* The depth at which the flowgraph is cut off */
193 : int emacs_option; /* Format and check for use with Emacs cflow-mode */
194 : int omit_arguments_option; /* Omit arguments from function declaration string */
195 : int omit_symbol_names_option; /* Omit symbol name from symbol declaration string */
196 :
197 : #define SM_FUNCTIONS 0x0001
198 : #define SM_DATA 0x0002
199 : #define SM_STATIC 0x0004
200 : #define SM_UNDERSCORE 0x0008
201 : #define SM_TYPEDEF 0x0010
202 : #define SM_UNDEFINED 0x0020
203 :
204 : #define CHAR_TO_SM(c) ((c)=='x' ? SM_DATA : \
205 : (c)=='_' ? SM_UNDERSCORE : \
206 : (c)=='s' ? SM_STATIC : \
207 : (c)=='t' ? SM_TYPEDEF : \
208 : (c)=='u' ? SM_UNDEFINED : 0)
209 : #define SYMBOL_INCLUDE(c) (symbol_map |= CHAR_TO_SM(c))
210 : #define SYMBOL_EXCLUDE(c) (symbol_map &= ~CHAR_TO_SM(c))
211 : int symbol_map; /* A bitmap of symbols included in the graph. */
212 :
213 : char *level_indent[] = { NULL, NULL };
214 : char *level_end[] = { "", "" };
215 : char *level_begin = "";
216 :
217 : int preprocess_option = 0; /* Do they want to preprocess sources? */
218 :
219 : char *start_name = "main"; /* Name of start symbol */
220 :
221 : struct linked_list *arglist; /* List of command line arguments */
222 :
223 : /* Given the option_type array and (possibly abbreviated) option argument
224 : * find the type corresponding to that argument.
225 : * Return 0 if the argument does not match any one of OPTYPE entries
226 : */
227 : static int
228 25 : find_option_type(struct option_type *optype, const char *str, int len)
229 : {
230 25 : if (len == 0)
231 5 : len = strlen(str);
232 95 : for ( ; optype->str; optype++) {
233 190 : if (len >= optype->min_match &&
234 95 : memcmp(str, optype->str, len) == 0) {
235 25 : return optype->type;
236 : }
237 : }
238 0 : return 0;
239 : }
240 :
241 : /* Args for --symbol option */
242 : static struct option_type symbol_optype[] = {
243 : { "keyword", 2, WORD },
244 : { "kw", 2, WORD },
245 : { "modifier", 1, MODIFIER },
246 : { "identifier", 1, IDENTIFIER },
247 : { "type", 1, TYPE },
248 : { "wrapper", 1, PARM_WRAPPER },
249 : { "qualifier", 1, QUALIFIER },
250 : { 0 },
251 : };
252 :
253 : /* Parse the string STR and store the symbol in the temporary symbol table.
254 : * STR is the string of form: NAME:TYPE
255 : * NAME means symbol name, TYPE means symbol type (possibly abbreviated)
256 : */
257 : static void
258 5 : symbol_override(const char *str)
259 : {
260 : const char *ptr;
261 : char *name;
262 : Symbol *sp;
263 :
264 5 : ptr = strchr(str, ':');
265 5 : if (!ptr) {
266 0 : error(0, 0, _("%s: no symbol type supplied"), str);
267 0 : return;
268 : } else {
269 5 : name = strndup(str, ptr - str);
270 5 : if (ptr[1] == '=') {
271 0 : Symbol *alias = lookup(ptr+2);
272 0 : if (!alias) {
273 0 : alias = install(xstrdup(ptr+2), INSTALL_OVERWRITE);
274 0 : alias->type = SymToken;
275 0 : alias->token_type = 0;
276 0 : alias->source = NULL;
277 0 : alias->def_line = -1;
278 0 : alias->ref_line = NULL;
279 : }
280 0 : sp = install(name, INSTALL_OVERWRITE);
281 0 : sp->type = SymToken;
282 0 : sp->alias = alias;
283 0 : sp->flag = symbol_alias;
284 : } else {
285 5 : int type = find_option_type(symbol_optype, ptr+1, 0);
286 5 : if (type == 0) {
287 0 : error(0, 0, _("unknown symbol type: %s"), ptr+1);
288 0 : return;
289 : }
290 5 : sp = install(name, INSTALL_OVERWRITE);
291 5 : sp->type = SymToken;
292 5 : sp->token_type = type;
293 : }
294 5 : sp->source = NULL;
295 5 : sp->def_line = -1;
296 5 : sp->ref_line = NULL;
297 : }
298 : }
299 :
300 : /* Args for --print option */
301 : static struct option_type print_optype[] = {
302 : { "xref", 1, PRINT_XREF },
303 : { "cross-ref", 1, PRINT_XREF },
304 : { "tree", 1, PRINT_TREE },
305 : { 0 },
306 : };
307 :
308 : static void
309 0 : set_print_option(char *str)
310 : {
311 : int opt;
312 :
313 0 : opt = find_option_type(print_optype, str, 0);
314 0 : if (opt == 0) {
315 0 : error(0, 0, _("unknown print option: %s"), str);
316 0 : return;
317 : }
318 0 : print_option |= opt;
319 : }
320 :
321 : /* Convert first COUNT bytes of the string pointed to by STR_PTR
322 : * to integer using BASE. Move STR_PTR to the point where the
323 : * conversion stopped.
324 : * Return the number obtained.
325 : */
326 : static int
327 0 : number(const char **str_ptr, int base, int count)
328 : {
329 : int c, n;
330 : unsigned i;
331 0 : const char *str = *str_ptr;
332 :
333 0 : for (n = 0; *str && count; count--) {
334 0 : c = *str++;
335 0 : if (isdigit(c))
336 0 : i = c - '0';
337 : else
338 0 : i = toupper(c) - 'A' + 10;
339 0 : if (i > base) {
340 0 : break;
341 : }
342 0 : n = n * base + i;
343 : }
344 0 : *str_ptr = str - 1;
345 0 : return n;
346 : }
347 :
348 : /* Processing for --level option
349 : * The option syntax is
350 : * --level NUMBER
351 : * or
352 : * --level KEYWORD=STR
353 : * where
354 : * KEYWORD is one of "begin", "0", ", "1", "end0", "end1",
355 : * or an abbreviation thereof,
356 : * STR is the value to be assigned to the parameter.
357 : *
358 : * STR can contain usual C escape sequences plus \e meaning '\033'.
359 : * Apart from this any character followed by xN suffix (where N is
360 : * a decimal number) is expanded to the sequence of N such characters.
361 : * 'x' looses its special meaning at the start of the string.
362 : */
363 : #define MAXLEVELINDENT 216
364 : #define LEVEL_BEGIN 1
365 : #define LEVEL_INDENT0 2
366 : #define LEVEL_INDENT1 3
367 : #define LEVEL_END0 4
368 : #define LEVEL_END1 5
369 :
370 : static struct option_type level_indent_optype[] = {
371 : { "begin", 1, LEVEL_BEGIN },
372 : { "start", 1, LEVEL_BEGIN },
373 : { "0", 1, LEVEL_INDENT0 },
374 : { "1", 1, LEVEL_INDENT1 },
375 : { "end0", 4, LEVEL_END0 },
376 : { "end1", 4, LEVEL_END1 },
377 : };
378 :
379 : static void
380 20 : parse_level_string(const char *str, char **return_ptr)
381 : {
382 : static char text[MAXLEVELINDENT];
383 : char *p;
384 : int i, c, num;
385 :
386 20 : p = text;
387 20 : memset(text, ' ', sizeof(text));
388 20 : text[sizeof(text)-1] = 0;
389 :
390 80 : while (*str) {
391 40 : switch (*str) {
392 : case '\\':
393 5 : switch (*++str) {
394 : case 'a':
395 0 : *p++ = '\a';
396 0 : break;
397 : case 'b':
398 0 : *p++ = '\b';
399 0 : break;
400 : case 'e':
401 0 : *p++ = '\033';
402 0 : break;
403 : case 'f':
404 0 : *p++ = '\f';
405 0 : break;
406 : case 'n':
407 0 : *p++ = '\n';
408 0 : break;
409 : case 'r':
410 0 : *p++ = '\r';
411 0 : break;
412 : case 't':
413 0 : *p++ = '\t';
414 0 : break;
415 : case 'x':
416 : case 'X':
417 0 : ++str;
418 0 : *p++ = number(&str,16,2);
419 0 : break;
420 : case '0':
421 0 : ++str;
422 0 : *p++ = number(&str,8,3);
423 0 : break;
424 : default:
425 5 : *p++ = *str;
426 : }
427 5 : ++str;
428 5 : break;
429 : case 'x':
430 0 : if (p == text) {
431 0 : goto copy;
432 : }
433 0 : num = strtol(str+1, (char**)&str, 10);
434 0 : c = p[-1];
435 0 : for (i = 1; i < num; i++) {
436 0 : *p++ = c;
437 0 : if (*p == 0) {
438 0 : error(1, 0, _("level indent string is too long"));
439 0 : return;
440 : }
441 : }
442 0 : break;
443 : default:
444 : copy:
445 35 : *p++ = *str++;
446 35 : if (*p == 0) {
447 0 : error(1, 0, _("level indent string is too long"));
448 0 : return;
449 : }
450 : }
451 : }
452 20 : *p = 0;
453 20 : *return_ptr = strdup(text);
454 : }
455 :
456 : static void
457 35 : set_level_indent(const char *str)
458 : {
459 : long n;
460 : const char *p;
461 : char *q;
462 :
463 35 : n = strtol(str, &q, 0);
464 35 : if (*q == 0 && n > 0) {
465 15 : char *s = xmalloc(n+1);
466 15 : memset(s, ' ', n-1);
467 15 : s[n-1] = 0;
468 15 : level_indent[0] = level_indent[1] = s;
469 30 : return;
470 : }
471 :
472 20 : p = str;
473 90 : while (*p != '=') {
474 50 : if (*p == 0) {
475 0 : error(1, 0, _("level-indent syntax"));
476 0 : return;
477 : }
478 50 : p++;
479 : }
480 20 : ++p;
481 :
482 20 : switch (find_option_type(level_indent_optype, str, p - str - 1)) {
483 : case LEVEL_BEGIN:
484 0 : parse_level_string(p, &level_begin);
485 0 : break;
486 : case LEVEL_INDENT0:
487 5 : parse_level_string(p, &level_indent[0]);
488 5 : break;
489 : case LEVEL_INDENT1:
490 5 : parse_level_string(p, &level_indent[1]);
491 5 : break;
492 : case LEVEL_END0:
493 5 : parse_level_string(p, &level_end[0]);
494 5 : break;
495 : case LEVEL_END1:
496 5 : parse_level_string(p, &level_end[1]);
497 5 : break;
498 : default:
499 0 : error(1, 0, _("unknown level indent option: %s"), str);
500 : }
501 : }
502 :
503 : static void
504 227 : add_name(const char *name)
505 : {
506 227 : linked_list_append(&arglist, (void*) name);
507 227 : }
508 :
509 : static void
510 0 : add_preproc_option(int key, const char *arg)
511 : {
512 0 : char *opt = xmalloc(3 + strlen(arg));
513 0 : sprintf(opt, "-%c%s", key, arg);
514 0 : add_name(opt);
515 0 : preprocess_option = 1;
516 0 : }
517 :
518 : static error_t
519 538 : parse_opt (int key, char *arg, struct argp_state *state)
520 : {
521 : int num;
522 :
523 538 : switch (key) {
524 : case 'a':
525 15 : strict_ansi = 1;
526 15 : break;
527 : case OPT_NO_ANSI:
528 0 : strict_ansi = 0;
529 0 : break;
530 : case OPT_DEBUG:
531 15 : debug = arg ? atoi(arg) : 1;
532 15 : break;
533 : case 'P':
534 0 : set_print_option(arg);
535 0 : break;
536 : case 'S':
537 6 : use_indentation = 1;
538 6 : break;
539 : case OPT_NO_USE_INDENTATION:
540 0 : use_indentation = 0;
541 0 : break;
542 : case 'T':
543 5 : print_as_tree = 1;
544 5 : set_level_indent("0= "); /* two spaces */
545 5 : set_level_indent("1=| ");
546 5 : set_level_indent("end0=+-");
547 5 : set_level_indent("end1=\\\\-");
548 5 : break;
549 : case OPT_NO_TREE:
550 0 : print_as_tree = 0;
551 0 : level_indent[0] = level_indent[1] = NULL;
552 0 : level_end[0] = level_end[0] = NULL;
553 0 : break;
554 : case 'b':
555 15 : brief_listing = 1;
556 15 : break;
557 : case OPT_NO_BRIEF:
558 0 : brief_listing = 0;
559 0 : break;
560 : case 'd':
561 15 : max_depth = atoi(arg);
562 15 : if (max_depth < 0)
563 0 : max_depth = 0;
564 15 : break;
565 : case OPT_DEFINES: /* FIXME: Not used. */
566 0 : record_defines = 1;
567 0 : break;
568 : case OPT_EMACS:
569 1 : emacs_option = 1;
570 1 : break;
571 : case OPT_NO_EMACS:
572 0 : emacs_option = 0;
573 0 : break;
574 : case 'f':
575 15 : if (select_output_driver(arg))
576 0 : argp_error(state, _("%s: No such output driver"), optarg);
577 15 : output_init();
578 15 : break;
579 : case OPT_LEVEL_INDENT:
580 15 : set_level_indent(arg);
581 15 : break;
582 : case 'i':
583 52 : num = 1;
584 104 : for (; *arg; arg++)
585 52 : switch (*arg) {
586 : case '-':
587 : case '^':
588 0 : num = 0;
589 0 : break;
590 : case '+':
591 0 : num = 1;
592 0 : break;
593 : case 'x':
594 : case '_':
595 : case 's':
596 : case 't':
597 : case 'u':
598 52 : if (num)
599 52 : SYMBOL_INCLUDE(*arg);
600 : else
601 0 : SYMBOL_EXCLUDE(*arg);
602 52 : break;
603 : default:
604 0 : argp_error(state, _("Unknown symbol class: %c"), *arg);
605 : }
606 52 : break;
607 : case OPT_OMIT_ARGUMENTS:
608 9 : omit_arguments_option = 1;
609 9 : break;
610 : case OPT_NO_OMIT_ARGUMENTS:
611 0 : omit_arguments_option = 0;
612 0 : break;
613 : case OPT_OMIT_SYMBOL_NAMES:
614 8 : omit_symbol_names_option = 1;
615 8 : break;
616 : case OPT_NO_OMIT_SYMBOL_NAMES:
617 0 : omit_symbol_names_option = 0;
618 0 : break;
619 : case 'l':
620 4 : print_levels = 1;
621 4 : break;
622 : case OPT_NO_PRINT_LEVEL:
623 0 : print_levels = 0;
624 0 : break;
625 : case 'm':
626 11 : start_name = strdup(arg);
627 11 : break;
628 : case 'n':
629 10 : print_line_numbers = 1;
630 10 : break;
631 : case OPT_NO_NUMBER:
632 0 : print_line_numbers = 0;
633 0 : break;
634 : case 'o':
635 18 : outname = strdup(arg);
636 18 : break;
637 : case 'p':
638 7 : num = atoi(arg);
639 7 : if (num > 0)
640 7 : token_stack_length = num;
641 7 : break;
642 : case 'r':
643 0 : reverse_tree = 1;
644 0 : break;
645 : case OPT_NO_REVERSE:
646 0 : reverse_tree = 0;
647 0 : break;
648 : case 's':
649 5 : symbol_override(arg);
650 5 : break;
651 : case 'v':
652 2 : verbose = 1;
653 2 : break;
654 : case OPT_NO_VERBOSE:
655 0 : verbose = 0;
656 0 : break;
657 : case 'x':
658 5 : print_option = PRINT_XREF;
659 5 : break;
660 : case OPT_PREPROCESS:
661 0 : preprocess_option = 1;
662 0 : set_preprocessor(arg ? arg : CFLOW_PREPROC);
663 0 : break;
664 : case OPT_NO_PREPROCESS:
665 0 : preprocess_option = 0;
666 0 : break;
667 : case ARGP_KEY_ARG:
668 227 : add_name(arg);
669 227 : break;
670 : case 'I':
671 : case 'D':
672 : case 'U':
673 0 : add_preproc_option(key, arg);
674 0 : break;
675 : default:
676 78 : return ARGP_ERR_UNKNOWN;
677 : }
678 460 : return 0;
679 : }
680 :
681 : static struct argp argp = {
682 : options,
683 : parse_opt,
684 : N_("[FILE]..."),
685 : doc,
686 : NULL,
687 : NULL,
688 : NULL
689 : };
690 :
691 : int
692 5333 : globals_only()
693 : {
694 5333 : return !(symbol_map & SM_STATIC);
695 : }
696 :
697 : int
698 75331 : include_symbol(Symbol *sym)
699 : {
700 75331 : int type = 0;
701 :
702 75331 : if (!sym)
703 0 : return 0;
704 :
705 75331 : if (sym->type == SymIdentifier) {
706 74254 : if (sym->name[0] == '_' && !(symbol_map & SM_UNDERSCORE))
707 1235 : return 0;
708 :
709 73019 : if (sym->storage == StaticStorage)
710 4167 : type |= SM_STATIC;
711 73019 : if (sym->arity == -1 && sym->storage != AutoStorage)
712 48218 : type |= SM_DATA;
713 24801 : else if (sym->arity >= 0)
714 24801 : type |= SM_FUNCTIONS;
715 :
716 73019 : if (!sym->source)
717 48085 : type |= SM_UNDEFINED;
718 :
719 1077 : } else if (sym->type == SymToken) {
720 1077 : if (sym->token_type == TYPE && sym->source)
721 0 : type |= SM_TYPEDEF;
722 : else
723 1077 : return 0;
724 : }
725 73019 : return (symbol_map & type) == type;
726 : }
727 :
728 : void
729 0 : xalloc_die(void)
730 : {
731 0 : error(1, ENOMEM, _("Exiting"));
732 0 : }
733 :
734 : void
735 19 : init()
736 : {
737 19 : if (level_indent[0] == NULL)
738 3 : level_indent[0] = " "; /* 4 spaces */
739 19 : if (level_indent[1] == NULL)
740 3 : level_indent[1] = level_indent[0];
741 19 : if (level_end[0] == NULL)
742 0 : level_end[0] = "";
743 19 : if (level_end[1] == NULL)
744 0 : level_end[1] = "";
745 :
746 19 : init_lex(debug > 1);
747 19 : init_parse();
748 19 : }
749 :
750 : const char version_etc_copyright[] =
751 : /* Do *not* mark this string for translation. %s is a copyright
752 : symbol suitable for this locale, and %d is the copyright
753 : year. */
754 : "Copyright %s 2005, 2006, 2009, 2010, 2011 %d Sergey Poznyakoff";
755 :
756 : int
757 21 : main(int argc, char **argv)
758 : {
759 : int index;
760 :
761 21 : set_program_name(argv[0]);
762 21 : argp_version_setup("cflow", program_authors);
763 :
764 21 : setlocale(LC_ALL, "");
765 21 : bindtextdomain(PACKAGE, LOCALEDIR);
766 21 : textdomain(PACKAGE);
767 :
768 21 : register_output("gnu", gnu_output_handler, NULL);
769 21 : register_output("posix", posix_output_handler, NULL);
770 :
771 21 : symbol_map = SM_FUNCTIONS|SM_STATIC|SM_UNDEFINED;
772 :
773 21 : if (getenv("POSIXLY_CORRECT")) {
774 0 : if (select_output_driver("posix"))
775 0 : error(1, 0, _("%s: No such output driver"), "posix");
776 0 : output_init();
777 : }
778 :
779 21 : sourcerc(&argc, &argv);
780 21 : if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
781 0 : exit(1);
782 :
783 19 : if (print_option == 0)
784 14 : print_option = PRINT_TREE;
785 :
786 19 : init();
787 :
788 19 : if (arglist) {
789 : struct linked_list_entry *p;
790 :
791 246 : for (p = arglist->head; p; p = p->next) {
792 227 : char *s = (char*)p->data;
793 227 : if (s[0] == '-')
794 0 : pp_option(s);
795 227 : else if (source(s) == 0)
796 227 : yyparse();
797 : }
798 : }
799 :
800 19 : argc -= index;
801 19 : argv += index;
802 :
803 38 : while (argc--) {
804 0 : if (source(*argv++) == 0)
805 0 : yyparse();
806 : }
807 :
808 19 : if (input_file_count == 0)
809 0 : error(1, 0, _("no input files"));
810 :
811 19 : output();
812 1 : return 0;
813 : }
814 :
815 :
816 :
817 :
818 :
819 :
820 :
|