|
|
|
@@ -30,47 +30,63 @@ const char *argp_program_version = "cflow (" PACKAGE_NAME ") " VERSION; |
30 | const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; |
30 | const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; |
31 | static char doc[] = ""; |
31 | static char doc[] = ""; |
32 | |
32 | |
| |
33 | #define OPT_DEFINES 256 |
| |
34 | #define OPT_LEVEL_INDENT 257 |
| |
35 | #define OPT_DEBUG 258 |
| |
36 | |
33 | static struct argp_option options[] = { |
37 | static struct argp_option options[] = { |
34 | { "verbose", 'v', NULL, 0, |
38 | { NULL, 0, NULL, 0, |
35 | "be verbose on output", 0 }, |
39 | "General options:", 0}, |
36 | { "ignore-indentation", 'S', NULL, 0, |
40 | { "depth", 'd', "NUMBER", 0, |
37 | "do not rely on indentation", 0 }, |
41 | "set the depth at which the flowgraph is cut off.", 1 }, |
38 | { "c++", 'C', NULL, 0, |
42 | { "include", 'i', "SPEC", 0, |
39 | "expect C++ input", 0 }, |
43 | "Increase the number of included symbols. SPEC is a string consisting of the following characters: x (include external and static data symbols), and _ (include names that begin with an underscore). If SPEC starts with ^, its meaning is reversed", 1 }, |
40 | { "defines" , 'd', NULL, 0, |
44 | { "format", 'f', "NAME", 0, |
41 | "record defines", 0 }, |
45 | "use given output format NAME. Valid names are gnu (default) and posix", |
| |
46 | 1 }, |
| |
47 | { "reverse", 'r', NULL, 0, |
| |
48 | "Print reverse call tree", 1 }, |
42 | { "xref", 'x', NULL, 0, |
49 | { "xref", 'x', NULL, 0, |
43 | "produce cross-reference listing only" }, |
50 | "produce cross-reference listing only", 1 }, |
44 | { "typedefs", 't', NULL, 0, |
51 | { "print", 'P', "OPT", 0, |
45 | "record typedefs" }, |
52 | "Set printing option to OPT. Valid OPT values are: xref (or cross-ref), tree. Any unambiguous abbreviation of the above is also accepted", 1 }, |
| |
53 | { "output", 'o', "FILE", 0, |
| |
54 | "set output file name (default -, meaning stdout)", 1 }, |
| |
55 | |
| |
56 | { NULL, 0, NULL, 0, |
| |
57 | "Parser control:", 10}, |
| |
58 | { "ignore-indentation", 'S', NULL, 0, |
| |
59 | "do not rely on indentation", 11 }, |
| |
60 | { "defines" , OPT_DEFINES, NULL, 0, |
| |
61 | "record defines", 11 }, |
| |
62 | { "ansi", 'a', NULL, 0, |
| |
63 | "Assume input to be written in ANSI C", 11 }, |
46 | { "pushdown", 'p', "VALUE", 0, |
64 | { "pushdown", 'p', "VALUE", 0, |
47 | "set initial token stack size to VALUE", 0 }, |
65 | "set initial token stack size to VALUE", 11 }, |
48 | { "symbol", 's', "SYM:TYPE", 0, |
66 | { "symbol", 's', "SYM:TYPE", 0, |
49 | "make cflow believe the symbol SYM is of type TYPE. Valid types are: keyword (or kw), modifier, identifier, type, wrapper. Any unambiguous abbreviation of the above is also accepted", 0 }, |
67 | "make cflow believe the symbol SYM is of type TYPE. Valid types are: keyword (or kw), modifier, identifier, type, wrapper. Any unambiguous abbreviation of the above is also accepted", 11 }, |
50 | { "ansi", 'a', NULL, 0, |
68 | { "main", 'm', "NAME", 0, |
51 | "Assume input to be written in ANSI C", 0 }, |
69 | "Assume main function to be called NAME", 11 }, |
52 | { "globals-only", 'g', NULL, 0, |
70 | |
53 | "Record only global symbols" }, |
71 | { NULL, 0, NULL, 0, |
| |
72 | "Output control:", 20}, |
54 | { "print-level", 'l', NULL, 0, |
73 | { "print-level", 'l', NULL, 0, |
55 | "Print nesting level along with the call tree", 0 }, |
74 | "Print nesting level along with the call tree", 21 }, |
| |
75 | { "level-indent", OPT_LEVEL_INDENT, "STRING", 0, |
| |
76 | "Use STRING when indenting to each new level", 21 }, |
56 | { "tree", 'T', NULL, 0, |
77 | { "tree", 'T', NULL, 0, |
57 | "Draw tree", 0 }, |
78 | "Draw tree", 21 }, |
58 | { "level-indent", 'i', "STRING", 0, |
79 | { "brief", 'b', "BOOL", OPTION_ARG_OPTIONAL, |
59 | "Use STRING when indenting to each new level", 0 }, |
80 | "brief output", 21 }, |
60 | { "print", 'P', "OPT", 0, |
81 | |
61 | "Set printing option to OPT. Valid OPT values are: xref (or cross-ref), tree. Any unambiguous abbreviation of the above is also accepted" }, |
82 | { NULL, 0, NULL, 0, |
62 | { "output", 'o', "FILE", 0, |
83 | "Informational options:", 30}, |
63 | "set output file name (default -, meaning stdout)" }, |
84 | { "verbose", 'v', NULL, 0, |
64 | { "main", 'm', "NAME", 0, |
85 | "be verbose on output", 31 }, |
65 | "Assume main function to be called NAME", 0 }, |
| |
66 | { "brief", 'b', NULL, 0, |
| |
67 | "brief output" }, |
| |
68 | { "reverse", 'r', NULL, 0, |
| |
69 | "Print reverse call tree", 0 }, |
| |
70 | { "format", 'f', "NAME", 0, |
| |
71 | "use given output format NAME. Valid names are gnu (default) and posix", 0}, |
| |
72 | { "license", 'L', 0, 0, |
86 | { "license", 'L', 0, 0, |
73 | "Print license and exit", 0 }, |
87 | "Print license and exit", 31 }, |
| |
88 | { "debug", OPT_DEBUG, "NUMBER", OPTION_ARG_OPTIONAL, |
| |
89 | "set debugging level", 31 }, |
74 | { 0, } |
90 | { 0, } |
75 | }; |
91 | }; |
76 | |
92 | |
@@ -89,6 +105,67 @@ char *cflow_license_text = |
89 | " along with GNU cflow; if not, write to the Free Software\n" |
105 | " along with GNU cflow; if not, write to the Free Software\n" |
90 | " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n"; |
106 | " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n"; |
91 | |
107 | |
| |
108 | /* Structure representing various arguments of command line options */ |
| |
109 | struct option_type { |
| |
110 | char *str; /* optarg value */ |
| |
111 | int min_match; /* minimal number of characters to match */ |
| |
112 | int type; /* data associated with the arg */ |
| |
113 | }; |
| |
114 | |
| |
115 | static int find_option_type(struct option_type *, char *); |
| |
116 | |
| |
117 | /* Args for --print option */ |
| |
118 | struct option_type print_optype[] = { |
| |
119 | { "xref", 1, PRINT_XREF }, |
| |
120 | { "cross-ref", 1, PRINT_XREF }, |
| |
121 | { "tree", 1, PRINT_TREE }, |
| |
122 | { 0 }, |
| |
123 | }; |
| |
124 | /* Args for --symbol option */ |
| |
125 | struct option_type symbol_optype[] = { |
| |
126 | { "keyword", 2, WORD }, |
| |
127 | { "kw", 2, WORD }, |
| |
128 | { "modifier", 1, MODIFIER }, |
| |
129 | { "identifier", 1, IDENTIFIER }, |
| |
130 | { "type", 1, TYPE }, |
| |
131 | { "wrapper", 1, PARM_WRAPPER }, |
| |
132 | { 0 }, |
| |
133 | }; |
| |
134 | |
| |
135 | int debug; /* debug level */ |
| |
136 | char *outname = "-"; /* default output file name */ |
| |
137 | int print_option = 0; /* what to print. */ |
| |
138 | int verbose; /* be verbose on output */ |
| |
139 | int ignore_indentation; /* Don't rely on indentation, |
| |
140 | * i.e. don't suppose the function body |
| |
141 | * is necessarily surrounded by the curly braces |
| |
142 | * in the first column |
| |
143 | */ |
| |
144 | int record_defines; /* Record macro definitions */ |
| |
145 | int strict_ansi; /* Assume sources to be written in ANSI C */ |
| |
146 | int print_levels; /* Print level number near every branch */ |
| |
147 | int print_as_tree; /* Print as tree */ |
| |
148 | int brief_listing; /* Produce short listing */ |
| |
149 | int reverse_tree; /* Generate reverse tree */ |
| |
150 | int max_depth; /* The depth at which the flowgraph is cut off */ |
| |
151 | char *included_symbols = "s"; |
| |
152 | /* A list of symbols included in the graph. |
| |
153 | Consists of the following letters: |
| |
154 | x Include (external and static) data symbols; |
| |
155 | _ Include names that begin with an underscore; |
| |
156 | s Include static functions; |
| |
157 | t Include typedefs (for cross-references only); |
| |
158 | */ |
| |
159 | char *excluded_symbols = ""; |
| |
160 | /* A list of symbols *not* included in the graph. |
| |
161 | Overrides included_symbols */ |
| |
162 | |
| |
163 | char *level_indent[] = { NULL, NULL }; |
| |
164 | char *level_end[] = { "", "" }; |
| |
165 | char *level_begin = ""; |
| |
166 | |
| |
167 | char *start_name = "main"; /* Name of start symbol */ |
| |
168 | |
92 | static error_t |
169 | static error_t |
93 | parse_opt (int key, char *arg, struct argp_state *state) |
170 | parse_opt (int key, char *arg, struct argp_state *state) |
94 | { |
171 | { |
@@ -98,11 +175,8 @@ parse_opt (int key, char *arg, struct argp_state *state) |
98 | case 'a': |
175 | case 'a': |
99 | strict_ansi = 1; |
176 | strict_ansi = 1; |
100 | break; |
177 | break; |
101 | case 'C': |
178 | case OPT_DEBUG: |
102 | assume_cplusplus = 1; |
179 | debug = arg ? atoi(arg) : 1; |
103 | break; |
| |
104 | case 'D': |
| |
105 | debug = 1; |
| |
106 | break; |
180 | break; |
107 | case 'L': |
181 | case 'L': |
108 | printf("License for %s:\n\n", argp_program_version); |
182 | printf("License for %s:\n\n", argp_program_version); |
@@ -122,20 +196,30 @@ parse_opt (int key, char *arg, struct argp_state *state) |
122 | level_end[1] = "\\-"; |
196 | level_end[1] = "\\-"; |
123 | break; |
197 | break; |
124 | case 'b': |
198 | case 'b': |
125 | brief_listing = 1; |
199 | brief_listing = arg ? (arg[0] == 'y' || arg[0] == 'Y') : 1; |
126 | break; |
200 | break; |
127 | case 'd': |
201 | case 'd': |
| |
202 | max_depth = atoi(arg); |
| |
203 | if (max_depth < 0) |
| |
204 | max_depth = 0; |
| |
205 | break; |
| |
206 | case OPT_DEFINES: |
128 | record_defines = 1; |
207 | record_defines = 1; |
129 | break; |
208 | break; |
130 | case 'f': |
209 | case 'f': |
131 | if (select_output_driver(arg)) |
210 | if (select_output_driver(arg)) |
132 | argp_error(state, "%s: No such output driver", optarg); |
211 | argp_error(state, "%s: No such output driver", optarg); |
| |
212 | else if (strcmp (arg, "posix") == 0) |
| |
213 | brief_listing = 1; |
133 | break; |
214 | break; |
134 | case 'g': |
215 | case OPT_LEVEL_INDENT: |
135 | globals_only = 1; |
216 | set_level_indent(arg); |
136 | break; |
217 | break; |
137 | case 'i': |
218 | case 'i': |
138 | set_level_indent(arg); |
219 | if (arg[0] == '^') |
| |
220 | excluded_symbols = arg+1; |
| |
221 | else |
| |
222 | included_symbols = arg; |
139 | break; |
223 | break; |
140 | case 'l': |
224 | case 'l': |
141 | print_levels = 1; |
225 | print_levels = 1; |
@@ -157,9 +241,6 @@ parse_opt (int key, char *arg, struct argp_state *state) |
157 | case 's': |
241 | case 's': |
158 | symbol_override(arg); |
242 | symbol_override(arg); |
159 | break; |
243 | break; |
160 | case 't': |
| |
161 | record_typedefs = 1; |
| |
162 | break; |
| |
163 | case 'v': |
244 | case 'v': |
164 | verbose = 1; |
245 | verbose = 1; |
165 | break; |
246 | break; |
@@ -182,109 +263,55 @@ static struct argp argp = { |
182 | NULL |
263 | NULL |
183 | }; |
264 | }; |
184 | |
265 | |
185 | /* Structure representing various arguments of command line options */ |
266 | int |
186 | struct option_type { |
267 | included_char(int c) |
187 | char *str; /* optarg value */ |
| |
188 | int min_match; /* minimal number of characters to match */ |
| |
189 | int type; /* data associated with the arg */ |
| |
190 | }; |
| |
191 | |
| |
192 | static int find_option_type(struct option_type *, char *); |
| |
193 | |
| |
194 | /* Args for --print option */ |
| |
195 | struct option_type print_optype[] = { |
| |
196 | "xref", 1, PRINT_XREF, |
| |
197 | "cross-ref", 1, PRINT_XREF, |
| |
198 | "tree", 1, PRINT_TREE, |
| |
199 | 0 |
| |
200 | }; |
| |
201 | /* Args for --symbol option */ |
| |
202 | struct option_type symbol_optype[] = { |
| |
203 | "keyword", 2, WORD, |
| |
204 | "kw", 2, WORD, |
| |
205 | "modifier", 1, MODIFIER, |
| |
206 | "identifier", 1, IDENTIFIER, |
| |
207 | "type", 1, TYPE, |
| |
208 | "wrapper", 1, PARM_WRAPPER, |
| |
209 | 0 |
| |
210 | }; |
| |
211 | |
| |
212 | char *progname; /* program name */ |
| |
213 | int debug; /* debug mode on */ |
| |
214 | char *outname = "-"; /* default output file name */ |
| |
215 | int print_option = 0; /* what to print. */ |
| |
216 | int verbose; /* be verbose on output */ |
| |
217 | int ignore_indentation; /* Don't rely on indentation, |
| |
218 | * i.e. don't suppose the function body |
| |
219 | * is necessarily surrounded by the curly braces |
| |
220 | * in the first column |
| |
221 | */ |
| |
222 | int assume_cplusplus; /* Assume C++ input always */ |
| |
223 | int record_defines; /* Record macro definitions */ |
| |
224 | int record_typedefs; /* Record typedefs */ |
| |
225 | int strict_ansi; /* Assume sources to be written in ANSI C */ |
| |
226 | int globals_only; /* List only global symbols */ |
| |
227 | int print_levels; /* Print level number near every branch */ |
| |
228 | int print_as_tree; /* Print as tree */ |
| |
229 | int brief_listing; /* Produce short listing */ |
| |
230 | int reverse_tree; /* Generate reverse tree */ |
| |
231 | |
| |
232 | char *level_indent[] = { NULL, NULL }; |
| |
233 | char *level_end[] = { "", "" }; |
| |
234 | char *level_begin = ""; |
| |
235 | |
| |
236 | char *start_name = "main"; /* Name of start symbol */ |
| |
237 | |
| |
238 | void |
| |
239 | xalloc_die(void) |
| |
240 | { |
268 | { |
241 | error(1, ENOMEM, ""); |
269 | return strchr (included_symbols, c) |
| |
270 | && !strchr (excluded_symbols, c); |
242 | } |
271 | } |
243 | |
272 | |
244 | int |
273 | int |
245 | main(int argc, char **argv) |
274 | globals_only() |
246 | { |
275 | { |
247 | int i; |
276 | return !included_char('s'); |
248 | int index; |
277 | } |
249 | |
| |
250 | progname = argv[0]; |
| |
251 | register_output("gnu", gnu_output_handler, NULL); |
| |
252 | register_output("posix", posix_output_handler, NULL); |
| |
253 | sourcerc(&argc, &argv); |
| |
254 | |
| |
255 | if (argp_parse (&argp, argc, argv, 0, &index, NULL)) |
| |
256 | exit (1); |
| |
257 | |
| |
258 | if (argv[optind] == NULL) |
| |
259 | error(1, 0, "No input files"); |
| |
260 | if (print_option == 0) |
| |
261 | print_option = PRINT_TREE; |
| |
262 | |
278 | |
263 | init(); |
279 | int |
| |
280 | include_symbol(Symbol *sym) |
| |
281 | { |
| |
282 | int type; |
264 | |
283 | |
265 | argc -= index; |
284 | if (sym->name[0] == '_') |
266 | argv += index; |
285 | type = '_'; |
267 | while (argc--) { |
286 | else if (sym->type == SymFunction && sym->v.func.storage == StaticStorage) |
268 | if (source(*argv++) == 0) |
287 | type = 's'; |
269 | yyparse(); |
288 | else if (sym->type == SymToken |
| |
289 | && sym->v.type.token_type == TYPE |
| |
290 | && sym->v.type.source) |
| |
291 | type = 't'; |
| |
292 | else /* FIXME: 'x' is not used */ |
| |
293 | type = 0; |
| |
294 | |
| |
295 | if (type == 0) |
| |
296 | return 1; |
| |
297 | return included_char(type); |
270 | } |
298 | } |
271 | cleanup(); |
| |
272 | |
299 | |
273 | output(); |
300 | void |
274 | return 0; |
301 | xalloc_die(void) |
| |
302 | { |
| |
303 | error(1, ENOMEM, ""); |
275 | } |
304 | } |
276 | |
305 | |
277 | void |
306 | void |
278 | init() |
307 | init() |
279 | { |
308 | { |
280 | int i; |
| |
281 | |
| |
282 | if (level_indent[0] == NULL) { |
309 | if (level_indent[0] == NULL) { |
283 | level_indent[0] = level_indent[1] = " "; /* 4 spaces */ |
310 | level_indent[0] = level_indent[1] = " "; /* 4 spaces */ |
284 | level_end[0] = level_end[1] = ""; |
311 | level_end[0] = level_end[1] = ""; |
285 | } |
312 | } |
286 | |
313 | |
287 | init_lex(); |
314 | init_lex(debug > 1); |
288 | init_parse(); |
315 | init_parse(); |
289 | } |
316 | } |
290 | |
317 | |
@@ -399,11 +426,11 @@ number(char **str_ptr, int base, int count) |
399 | #define LEVEL_END1 5 |
426 | #define LEVEL_END1 5 |
400 | |
427 | |
401 | struct option_type level_indent_optype[] = { |
428 | struct option_type level_indent_optype[] = { |
402 | "begin", 1, LEVEL_BEGIN, |
429 | { "begin", 1, LEVEL_BEGIN }, |
403 | "0", 1, LEVEL_INDENT0, |
430 | { "0", 1, LEVEL_INDENT0 }, |
404 | "1", 1, LEVEL_INDENT1, |
431 | { "1", 1, LEVEL_INDENT1 }, |
405 | "end0", 4, LEVEL_END0, |
432 | { "end0", 4, LEVEL_END0 }, |
406 | "end1", 4, LEVEL_END1, |
433 | { "end1", 4, LEVEL_END1 }, |
407 | }; |
434 | }; |
408 | |
435 | |
409 | void |
436 | void |
@@ -519,6 +546,37 @@ parse_level_string(char *str, char **return_ptr) |
519 | *return_ptr = strdup(text); |
546 | *return_ptr = strdup(text); |
520 | } |
547 | } |
521 | |
548 | |
| |
549 | int |
| |
550 | main(int argc, char **argv) |
| |
551 | { |
| |
552 | int index; |
| |
553 | |
| |
554 | register_output("gnu", gnu_output_handler, NULL); |
| |
555 | register_output("posix", posix_output_handler, NULL); |
| |
556 | sourcerc(&argc, &argv); |
| |
557 | |
| |
558 | if (argp_parse (&argp, argc, argv, 0, &index, NULL)) |
| |
559 | exit (1); |
| |
560 | |
| |
561 | if (argv[optind] == NULL) |
| |
562 | error(1, 0, "No input files"); |
| |
563 | if (print_option == 0) |
| |
564 | print_option = PRINT_TREE; |
| |
565 | |
| |
566 | init(); |
| |
567 | |
| |
568 | argc -= index; |
| |
569 | argv += index; |
| |
570 | while (argc--) { |
| |
571 | if (source(*argv++) == 0) |
| |
572 | yyparse(); |
| |
573 | } |
| |
574 | cleanup(); |
| |
575 | |
| |
576 | output(); |
| |
577 | return 0; |
| |
578 | } |
| |
579 | |
522 | |
580 | |
523 | |
581 | |
524 | |
582 | |
|