aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am13
-rw-r--r--src/c.l10
-rw-r--r--src/cflow.h62
-rw-r--r--src/cflow.rc3
-rw-r--r--src/depmap.c2
-rw-r--r--src/dot.c78
-rw-r--r--src/gnu.c2
-rw-r--r--src/linked-list.c2
-rw-r--r--src/main.c242
-rw-r--r--src/output.c22
-rw-r--r--src/parser.c85
-rw-r--r--src/parser.h2
-rw-r--r--src/posix.c2
-rw-r--r--src/rc.c2
-rw-r--r--src/symbol.c153
m---------src/wordsplit0
16 files changed, 495 insertions, 185 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7f86599..cbd8a4e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GNU cflow
-# Copyright (C) 2005, 2007, 2009, 2016 Free Software Foundation, Inc.
+# Copyright (C) 2005-2022 Free Software Foundation, Inc.
#
# Written by Sergey Poznyakoff
#
@@ -21,6 +21,7 @@ cflow_SOURCES = \
c.l\
cflow.h\
depmap.c\
+ dot.c\
gnu.c\
linked-list.c\
main.c\
@@ -29,18 +30,16 @@ cflow_SOURCES = \
parser.h\
posix.c\
rc.c\
- symbol.c
-
-nodist_cflow_SOURCES = wordsplit.c
-
-VPATH += $(top_srcdir)/wordsplit
+ symbol.c\
+ wordsplit/wordsplit.c\
+ wordsplit/wordsplit.h
localedir = $(datadir)/locale
LDADD=../gnu/libgnu.a @LIBINTL@
AM_CPPFLAGS=\
-I$(top_srcdir)/gnu -I../ -I../gnu\
- -I$(top_srcdir)/wordsplit\
+ -I$(srcdir)/wordsplit\
-DLOCALEDIR=\"$(localedir)\"
AM_LFLAGS=-dvp
EXTRA_DIST = cflow.rc
diff --git a/src/c.l b/src/c.l
index 60f74f8..e3c2e5c 100644
--- a/src/c.l
+++ b/src/c.l
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -76,9 +76,7 @@ typedef return TYPEDEF;
struct {yylval.str = "struct"; return STRUCT;}
union {yylval.str = "union"; return STRUCT;}
enum {yylval.str = "enum"; return STRUCT;}
-\* { yylval.str = "*";
- return MODIFIER;
- }
+\* {yylval.str = "*"; return MODIFIER;}
/* Operators
*
*/
@@ -302,7 +300,9 @@ pp_option(const char *arg)
void
pp_finalize()
{
- char *s = obstack_finish(opt_stack);
+ char *s;
+ obstack_1grow(opt_stack, 0);
+ s = obstack_finish(opt_stack);
if (!pp_opts)
pp_opts = xstrdup(s);
else {
diff --git a/src/cflow.h b/src/cflow.h
index 7728ab7..48cca5b 100644
--- a/src/cflow.h
+++ b/src/cflow.h
@@ -1,11 +1,11 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
-
+ Copyright (C) 1997-2022 Sergey Poznyakoff
+
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
GNU cflow is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -34,12 +34,7 @@
#define _(c) gettext(c)
#define N_(c) c
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#if !HAVE_SETLOCALE
-# define setlocale(category, locale) /* empty */
-#endif
+#include <locale.h>
/* Exit codes */
#define EX_OK 0 /* Success */
@@ -85,10 +80,12 @@ typedef struct {
enum symbol_flag {
symbol_none,
+ symbol_start, /* Starter (main, et al.) */
+ symbol_target,
symbol_local, /* Unit-local symbol. Must be deleted after
processing current compilation unit */
symbol_parm, /* Parameter */
- symbol_alias /* Alias to another symbol */
+ symbol_alias, /* Alias to another symbol */
};
typedef struct symbol Symbol;
@@ -97,7 +94,7 @@ struct symbol {
struct table_entry *owner;
Symbol *next; /* Next symbol with the same hash */
struct linked_list_entry *entry;
-
+
enum symtype type; /* Type of the symbol */
char *name; /* Identifier */
enum symbol_flag flag; /* Specific flag */
@@ -105,26 +102,30 @@ struct symbol {
type==SymToken and flag==symbol_alias.
In this case, the rest of the structure
is ignored */
-
+
int active; /* Set to 1 when the symbol's subtree is
being processed, prevent recursion */
- int expand_line; /* Output line when this symbol was first
- expanded */
+ int expand_line; /* Number of the output line where this
+ symbol was first expanded */
+
+ int visible; /* Visibility marker. Symbol will be
+ shown on output only if its value equals
+ that of the output_visible global. */
int token_type; /* Type of the token */
char *source; /* Source file */
int def_line; /* Source line */
struct linked_list *ref_line; /* Referenced in */
-
+
int level; /* Block nesting level (for local vars),
Parameter nesting level (for params) */
-
- char *decl; /* Declaration */
+
+ char *decl; /* Declaration */
enum storage storage; /* Storage type */
-
+
int arity; /* Number of parameters or -1 for
- variables */
-
+ variables */
+
int recursive; /* Is the function recursive */
size_t ord; /* ordinal number */
struct linked_list *caller; /* List of callers */
@@ -175,6 +176,8 @@ extern int token_stack_increase;
extern int symbol_count;
extern unsigned input_file_count;
+extern int output_visible;
+
#define INSTALL_DEFAULT 0x00
#define INSTALL_OVERWRITE 0x01
#define INSTALL_CHECK_LOCAL 0x02
@@ -183,6 +186,17 @@ extern unsigned input_file_count;
Symbol *lookup(const char*);
Symbol *install(char*, int);
Symbol *install_ident(char *name, enum storage storage);
+void init_ident(Symbol *sp, enum storage storage);
+
+Symbol *install_starter(char *name);
+void set_default_starter(void);
+void clear_starters(void);
+Symbol *first_starter(void *itr);
+Symbol *next_starter(void *itr);
+
+Symbol *install_target(char *name);
+void eliminate_non_targets(void);
+
void ident_change_storage(Symbol *sp, enum storage storage);
void delete_autos(int level);
void delete_statics(void);
@@ -194,7 +208,7 @@ struct linked_list *linked_list_create(linked_list_free_data_fp fun);
void linked_list_destroy(struct linked_list **plist);
void linked_list_append(struct linked_list **plist, void *data);
void linked_list_prepend(struct linked_list **plist, void *data);
-void linked_list_iterate(struct linked_list **plist,
+void linked_list_iterate(struct linked_list **plist,
int (*itr) (void *, void *), void *data);
void linked_list_unlink(struct linked_list *list,
struct linked_list_entry *ent);
@@ -206,10 +220,11 @@ int get_token(void);
int source(char *name);
void init_lex(int debug_level);
void set_preprocessor(const char *arg);
-void pp_option(const char *arg);
+void pp_option(const char *arg);
void init_parse(void);
int yyparse(void);
+void reset_static_caller(void);
void output(void);
void newline(void);
@@ -251,6 +266,9 @@ int gnu_output_handler(cflow_output_command cmd,
int posix_output_handler(cflow_output_command cmd,
FILE *outfile, int line,
void *data, void *handler_data);
+int dot_output_handler(cflow_output_command cmd,
+ FILE *outfile, int line,
+ void *data, void *handler_data);
typedef struct cflow_depmap *cflow_depmap_t;
diff --git a/src/cflow.rc b/src/cflow.rc
index 768fae9..4ce09fd 100644
--- a/src/cflow.rc
+++ b/src/cflow.rc
@@ -5,6 +5,9 @@
--symbol __const:=const
--symbol __restrict:=restrict
--symbol __extension__:qualifier
+--symbol typeof:wrapper
+--symbol __typeof:=typeof
+--symbol __typeof__:=typeof
--symbol __attribute__:wrapper
--symbol __asm__:wrapper
--symbol __nonnull:wrapper
diff --git a/src/depmap.c b/src/depmap.c
index ca4f062..6a48c5f 100644
--- a/src/depmap.c
+++ b/src/depmap.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow.
- Copyright (C) 2008-2019 Sergey Poznyakoff
+ Copyright (C) 2008-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/dot.c b/src/dot.c
new file mode 100644
index 0000000..4f2c865
--- /dev/null
+++ b/src/dot.c
@@ -0,0 +1,78 @@
+/* This file is part of GNU cflow
+ Copyright (C) 2021-2022 Sergey Poznyakoff
+
+ GNU cflow is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GNU cflow is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include <cflow.h>
+
+static void
+dot_begin(FILE *fp)
+{
+ fprintf(fp, "digraph cflow {\n");
+ fprintf(fp, " node [shape=\"box\"]\n");
+}
+
+static void
+declare_node(FILE *fp, Symbol *sym)
+{
+ fprintf(fp, " %s [label=\"", sym->name);
+ if (sym->decl)
+ fprintf(fp, "%s\n%s:%d",
+ sym->decl, sym->source, sym->def_line);
+ else
+ fprintf(fp, "%s()", sym->name);
+ fprintf(fp, "\"]\n");
+}
+
+
+static void
+dot_print_symbol(FILE *fp, int line, struct output_symbol *s)
+{
+ struct linked_list *lp;
+ struct linked_list_entry *ep;
+
+ if (s->sym->active)
+ return;
+ if (s->sym->expand_line)
+ return;
+ else {
+ declare_node(fp, s->sym);
+ s->sym->expand_line = line;
+ }
+ lp = s->direct ? s->sym->callee : s->sym->caller;
+ for (ep = linked_list_head(lp); ep; ep = ep->next) {
+ Symbol *sym = ep->data;
+ if (include_symbol(sym))
+ fprintf(fp, " %s -> %s\n", s->sym->name, sym->name);
+ }
+}
+
+int
+dot_output_handler(cflow_output_command cmd,
+ FILE *outfile, int line,
+ void *data, void *handler_data)
+{
+ switch (cmd) {
+ case cflow_output_begin:
+ dot_begin(outfile);
+ break;
+ case cflow_output_end:
+ fprintf(outfile, "}\n");
+ break;
+ case cflow_output_symbol:
+ dot_print_symbol(outfile, line, data);
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/src/gnu.c b/src/gnu.c
index 6389b96..a05e401 100644
--- a/src/gnu.c
+++ b/src/gnu.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/linked-list.c b/src/linked-list.c
index 856ee42..d3a97a7 100644
--- a/src/linked-list.c
+++ b/src/linked-list.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/main.c b/src/main.c
index bdfddb0..9b15167 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,18 +22,14 @@
#include <parser.h>
#include <version-etc.h>
-const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
-static char doc[] = N_("generate a program flowgraph")
-"\v"
-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.");
+static char doc[] = N_("generate a program flowgraph");
const char *program_authors[] = {
"Sergey Poznyakoff",
NULL
};
enum option_code {
- OPT_DEFINES = 256,
- OPT_LEVEL_INDENT,
+ OPT_LEVEL_INDENT = 256,
OPT_DEBUG,
OPT_PREPROCESS,
OPT_NO_PREPROCESS,
@@ -51,7 +47,8 @@ enum option_code {
OPT_OMIT_ARGUMENTS,
OPT_NO_OMIT_ARGUMENTS,
OPT_OMIT_SYMBOL_NAMES,
- OPT_NO_OMIT_SYMBOL_NAMES
+ OPT_NO_OMIT_SYMBOL_NAMES,
+ OPT_TARGET,
};
static struct argp_option options[] = {
@@ -59,24 +56,21 @@ static struct argp_option options[] = {
{ NULL, 0, NULL, 0,
N_("General options:"), GROUP_ID },
{ "depth", 'd', N_("NUMBER"), 0,
- N_("Set the depth at which the flowgraph is cut off"), GROUP_ID+1 },
+ N_("set the depth at which the flowgraph is cut off"), GROUP_ID+1 },
{ "include", 'i', N_("CLASSES"), 0,
- N_("Include specified classes of symbols (see below). Prepend CLASSES with ^ or - to exclude them from the output"), GROUP_ID+1 },
+ N_("include specified classes of symbols (see below); prepend CLASSES with ^ or - to exclude them from the output"), GROUP_ID+1 },
{ "format", 'f', N_("NAME"), 0,
- N_("Use given output format NAME. Valid names are `gnu' (default) and `posix'"),
+ N_("use given output format NAME; valid names are `gnu' (default), `posix', and `dot'"),
GROUP_ID+1 },
{ "reverse", 'r', NULL, 0,
- N_("* Print reverse call tree"), GROUP_ID+1 },
+ N_("print reverse call tree"), GROUP_ID+1 },
{ "xref", 'x', NULL, 0,
- N_("Produce cross-reference listing only"), GROUP_ID+1 },
- { "print", 'P', N_("OPT"), OPTION_HIDDEN,
- N_("Set printing option to OPT. Valid OPT values are: xref (or cross-ref), tree. Any unambiguous abbreviation of the above is also accepted"),
- GROUP_ID+1 },
+ N_("produce cross-reference listing only"), GROUP_ID+1 },
{ "output", 'o', N_("FILE"), 0,
- N_("Set output file name (default -, meaning stdout)"),
+ N_("set output file name (default -, meaning stdout)"),
GROUP_ID+1 },
- { NULL, 0, NULL, 0, N_("Symbols classes for --include argument"), GROUP_ID+2 },
+ { NULL, 0, NULL, 0, N_("Symbol classes for --include argument"), GROUP_ID+2 },
{" x", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
N_("all data symbols, both external and static"), GROUP_ID+3 },
{" _", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
@@ -92,81 +86,90 @@ static struct argp_option options[] = {
{ NULL, 0, NULL, 0,
N_("Parser control:"), GROUP_ID },
{ "use-indentation", 'S', NULL, 0,
- N_("* Rely on indentation"), GROUP_ID+1 },
- { "no-use-indentation", OPT_NO_USE_INDENTATION, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("rely on indentation"), GROUP_ID+1 },
+ { "no-use-indentation", OPT_NO_USE_INDENTATION, NULL, 0,
+ N_("don't rely on indentation (default)"), GROUP_ID+1 },
{ "ansi", 'a', NULL, 0,
- N_("* Accept only sources in ANSI C"), GROUP_ID+1 },
- { "no-ansi", OPT_NO_ANSI, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("accept only sources in ANSI C"), GROUP_ID+1 },
+ { "no-ansi", OPT_NO_ANSI, NULL, 0,
+ N_("accept both ANSI and K&R C (default)"), GROUP_ID+1 },
{ "pushdown", 'p', N_("NUMBER"), 0,
- N_("Set initial token stack size to NUMBER"), GROUP_ID+1 },
+ N_("set initial token stack size to NUMBER"), GROUP_ID+1 },
{ "symbol", 's', N_("SYMBOL:[=]TYPE"), 0,
- 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 },
- { "main", 'm', N_("NAME"), 0,
- N_("Assume main function to be called NAME"), GROUP_ID+1 },
- { "no-main", OPT_NO_MAIN, NULL, 0,
- N_("There's no main function; print graphs for all functions in the program") },
+ /* TRANSLATORS: Don't translate type names. */
+ N_("register SYMBOL with given TYPE, or define an alias (if := is used); valid types are: keyword (or kw), modifier, qualifier, identifier, type, wrapper, or any unambiguous abbreviation thereof"), GROUP_ID+1 },
{ "define", 'D', N_("NAME[=DEFN]"), 0,
- N_("Predefine NAME as a macro"), GROUP_ID+1 },
+ N_("predefine NAME as a macro"), GROUP_ID+1 },
{ "undefine", 'U', N_("NAME"), 0,
- N_("Cancel any previous definition of NAME"), GROUP_ID+1 },
+ N_("cancel any previous definition of NAME"), GROUP_ID+1 },
{ "include-dir", 'I', N_("DIR"), 0,
- N_("Add the directory DIR to the list of directories to be searched for header files."), GROUP_ID+1 },
+ N_("add the directory DIR to the list of directories to be searched for header files"), GROUP_ID+1 },
{ "preprocess", OPT_PREPROCESS, N_("COMMAND"), OPTION_ARG_OPTIONAL,
- N_("* Run the specified preprocessor command"), GROUP_ID+1 },
+ N_("run the specified preprocessor command"), GROUP_ID+1 },
{ "cpp", 0, NULL, OPTION_ALIAS, NULL, GROUP_ID+1 },
- { "no-preprocess", OPT_NO_PREPROCESS, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
- { "no-cpp", 0, NULL, OPTION_ALIAS|OPTION_HIDDEN, NULL, GROUP_ID+1 },
+ { "no-preprocess", OPT_NO_PREPROCESS, NULL, 0,
+ N_("disable preprocessor"), GROUP_ID+1 },
+ { "no-cpp", 0, NULL, OPTION_ALIAS, NULL, GROUP_ID+1 },
#undef GROUP_ID
#define GROUP_ID 20
{ NULL, 0, NULL, 0,
N_("Output control:"), GROUP_ID },
{ "all", 'A', NULL, 0,
- N_("Show all functions, not only those reachable from main"),
+ N_("show all functions, not only those reachable from main"),
GROUP_ID+1 },
{ "number", 'n', NULL, 0,
- N_("* Print line numbers"), GROUP_ID+1 },
- { "no-number", OPT_NO_NUMBER, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("print line numbers"), GROUP_ID+1 },
+ { "no-number", OPT_NO_NUMBER, NULL, 0,
+ N_("don't print line numbers (default)"), GROUP_ID+1 },
{ "print-level", 'l', NULL, 0,
- N_("* Print nesting level along with the call tree"), GROUP_ID+1 },
- { "no-print-level", OPT_NO_PRINT_LEVEL, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("print nesting level along with the call tree"), GROUP_ID+1 },
+ { "no-print-level", OPT_NO_PRINT_LEVEL, NULL, 0,
+ N_("don't print nesting levels (default)"), GROUP_ID+1 },
{ "level-indent", OPT_LEVEL_INDENT, "ELEMENT", 0,
- N_("Control graph appearance"), GROUP_ID+1 },
+ N_("control graph appearance; see [1] for details"), GROUP_ID+1 },//FIXME
{ "tree", 'T', NULL, 0,
- N_("* Draw ASCII art tree"), GROUP_ID+1 },
- { "no-tree", OPT_NO_TREE, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("draw ASCII art tree"), GROUP_ID+1 },
+ { "no-tree", OPT_NO_TREE, NULL, 0,
+ N_("don't draw ASCII art tree (default)"), GROUP_ID+1 },
{ "brief", 'b', NULL, 0,
- N_("* Brief output"), GROUP_ID+1 },
- { "no-brief", OPT_NO_BRIEF, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("brief output"), GROUP_ID+1 },
+ { "no-brief", OPT_NO_BRIEF, NULL, 0,
+ N_("full output (default)"), GROUP_ID+1 },
{ "emacs", OPT_EMACS, NULL, 0,
- N_("* Additionally format output for use with GNU Emacs"), GROUP_ID+1 },
- { "no-emacs", OPT_NO_EMACS, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("additionally format output for use with GNU Emacs"), GROUP_ID+1 },
+ { "no-emacs", OPT_NO_EMACS, NULL, 0,
+ N_("don't format output for Emacs (default)"), GROUP_ID+1 },
{ "omit-arguments", OPT_OMIT_ARGUMENTS, NULL, 0,
- N_("* Do not print argument lists in function declarations"), GROUP_ID+1 },
- { "no-ignore-arguments", OPT_NO_OMIT_ARGUMENTS, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("don't print argument lists in function declarations"), GROUP_ID+1 },
+ { "no-omit-arguments", OPT_NO_OMIT_ARGUMENTS, NULL, 0,
+ N_("print argument lists in function declarations (default)"), GROUP_ID+1 },
{ "omit-symbol-names", OPT_OMIT_SYMBOL_NAMES, NULL, 0,
- N_("* Do not print symbol names in declaration strings"), GROUP_ID+1 },
- { "no-omit-symbol-names", OPT_NO_OMIT_SYMBOL_NAMES, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("don't print symbol names in declaration strings"), GROUP_ID+1 },
+ { "no-omit-symbol-names", OPT_NO_OMIT_SYMBOL_NAMES, NULL, 0,
+ N_("print symbol names in declaration strings (default)"), GROUP_ID+1 },
+ { "main", 'm', N_("NAME"), 0,
+ N_("start graph at this function; multiple options are allowed"),
+ GROUP_ID+1 },
+ { "start", 0, NULL, OPTION_ALIAS,
+ NULL,
+ GROUP_ID+1 },
+ { "no-main", OPT_NO_MAIN, NULL, 0,
+ N_("there's no main function; print graphs for all functions in the program") },
+ { "target", OPT_TARGET, N_("NAME"), 0,
+ N_("show only graphs leading from start symbols to this function; multiple options are allowed"),
+ GROUP_ID+1 },
#undef GROUP_ID
#define GROUP_ID 30
{ NULL, 0, NULL, 0,
N_("Informational options:"), GROUP_ID },
{ "verbose", 'v', NULL, 0,
- N_("* Verbose error diagnostics"), GROUP_ID+1 },
- { "no-verbose", OPT_NO_VERBOSE, NULL, OPTION_HIDDEN,
- "", GROUP_ID+1 },
+ N_("verbose error diagnostics"), GROUP_ID+1 },
+ { "no-verbose", OPT_NO_VERBOSE, NULL, 0,
+ N_("disable verbose diagnostics (default)"), GROUP_ID+1 },
{ "debug", OPT_DEBUG, "NUMBER", OPTION_ARG_OPTIONAL,
- N_("Set debugging level"), GROUP_ID+1 },
+ N_("set debugging level"), GROUP_ID+1 },
#undef GROUP_ID
+ {"help", '?', 0, OPTION_HIDDEN, N_("give this help list"), -1},
{ 0, }
};
@@ -186,7 +189,6 @@ int use_indentation; /* Rely on indentation,
* is necessarily surrounded by the curly braces
* in the first column
*/
-int record_defines; /* Record macro definitions */
int strict_ansi; /* Assume sources to be written in ANSI C */
int print_line_numbers; /* Print line numbers */
int print_levels; /* Print level number near every branch */
@@ -198,6 +200,8 @@ int emacs_option; /* Format and check for use with Emacs cflow-mode */
int omit_arguments_option; /* Omit arguments from function declaration string */
int omit_symbol_names_option; /* Omit symbol name from symbol declaration string */
+static int no_main_option; /* Disable start symbols */
+
#define SM_FUNCTIONS 0x0001
#define SM_DATA 0x0002
#define SM_STATIC 0x0004
@@ -212,7 +216,9 @@ int omit_symbol_names_option; /* Omit symbol name from symbol declaration string
(c)=='u' ? SM_UNDEFINED : 0)
#define SYMBOL_INCLUDE(c) (symbol_map |= CHAR_TO_SM(c))
#define SYMBOL_EXCLUDE(c) (symbol_map &= ~CHAR_TO_SM(c))
-int symbol_map; /* A bitmap of symbols included in the graph. */
+static int symbol_map; /* A bitmap of symbols included in the graph. */
+
+int output_visible;
char *level_indent[] = { NULL, NULL };
char *level_end[] = { "", "" };
@@ -220,7 +226,6 @@ char *level_begin = "";
int preprocess_option = 0; /* Do they want to preprocess sources? */
-char *start_name = "main"; /* Name of start symbol */
int all_functions;
struct linked_list *arglist; /* List of command line arguments */
@@ -235,6 +240,7 @@ find_option_type(struct option_type *optype, const char *str, int len)
len = strlen(str);
for ( ; optype->str; optype++) {
if (len >= optype->min_match &&
+ len <= strlen(optype->str) &&
memcmp(str, optype->str, len) == 0) {
return optype->type;
}
@@ -270,10 +276,24 @@ symbol_override(const char *str)
error(EX_USAGE, 0, _("%s: no symbol type supplied"), str);
else {
name = strndup(str, ptr - str);
+ if (!name)
+ xalloc_die();
if (ptr[1] == '=') {
- Symbol *alias = lookup(ptr+2);
- if (!alias) {
- alias = install(xstrdup(ptr+2), INSTALL_OVERWRITE);
+ Symbol *alias;
+
+ ptr += 2;
+ if (strcmp(name, ptr) == 0) {
+ error(EX_USAGE, 0, _("cyclic alias: %s -> %s"), name, ptr);
+ }
+
+ alias = lookup(ptr);
+ if (alias) {
+ if (strcmp(alias->name, name) == 0) {
+ error(EX_USAGE, 0, _("cyclic alias: %s -> %s -> %s"),
+ name, ptr, alias->name);
+ }
+ } else {
+ alias = install(xstrdup(ptr), INSTALL_OVERWRITE);
alias->type = SymToken;
alias->token_type = 0;
alias->source = NULL;
@@ -298,27 +318,6 @@ symbol_override(const char *str)
}
}
-/* Args for --print option */
-static struct option_type print_optype[] = {
- { "xref", 1, PRINT_XREF },
- { "cross-ref", 1, PRINT_XREF },
- { "tree", 1, PRINT_TREE },
- { 0 },
-};
-
-static void
-set_print_option(char *str)
-{
- int opt;
-
- opt = find_option_type(print_optype, str, 0);
- if (opt == 0) {
- error(EX_USAGE, 0, _("unknown print option: %s"), str);
- return;
- }
- print_option |= opt;
-}
-
/* Convert first COUNT bytes of the string pointed to by STR_PTR
* to integer using BASE. Move STR_PTR to the point where the
* conversion stopped.
@@ -511,6 +510,43 @@ add_preproc_option(int key, const char *arg)
preprocess_option = 1;
}
+#define end_of_options(opt) \
+ (!(opt)->key && !(opt)->name && !(opt)->doc && !(opt)->group)
+
+/* Override default argp's --help behavior */
+static void
+cflow_help(struct argp_state *state)
+{
+ struct argp_option *opt;
+
+ /*
+ * Unshadow the -? option.
+ *
+ * By default argp shadows (i.e. removes from the help listing), short
+ * options that appear more than once. The -? option added in the
+ * options array above falls into that category. To avoid shadowing it,
+ * find the option structure and replace its key with 0.
+ */
+ for (opt = (struct argp_option *) state->root_argp->children[0].argp->options;
+ !end_of_options(opt); opt++) {
+ if (opt->key == '?') {
+ opt->key = 0;
+ break;
+ }
+ }
+
+ /* Print the help screen without bug-reporting address. */
+ argp_state_help (state, stdout,
+ ARGP_HELP_STD_HELP & ~(ARGP_HELP_BUG_ADDR|ARGP_HELP_EXIT_OK));
+
+ printf ("\n%s\n", _("References:"));
+ printf (" [1] https://www.gnu.org/software/cflow/manual/html_section/ASCII-Tree.html\n");
+
+ /* Emit bug-reporting address and exit. */
+ emit_bug_reporting_address ();
+ exit (0);
+}
+
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -529,9 +565,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
case OPT_DEBUG:
debug = arg ? atoi(arg) : 1;
break;
- case 'P':
- set_print_option(arg);
- break;
case 'S':
use_indentation = 1;
break;
@@ -561,9 +594,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
if (max_depth < 0)
max_depth = 0;
break;
- case OPT_DEFINES: /* FIXME: Not used. */
- record_defines = 1;
- break;
case OPT_EMACS:
emacs_option = 1;
break;
@@ -622,10 +652,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
print_levels = 0;
break;
case 'm':
- start_name = strdup(arg);
+ install_starter(arg);
break;
case OPT_NO_MAIN:
- start_name = NULL;
+ clear_starters();
+ no_main_option = 1;
break;
case 'n':
print_line_numbers = 1;
@@ -675,6 +706,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'U':
add_preproc_option(key, arg);
break;
+ case OPT_TARGET:
+ install_target(arg);
+ break;
+ case '?':
+ cflow_help(state);
+ break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -704,6 +741,9 @@ include_symbol(Symbol *sym)
if (!sym)
return 0;
+
+ if (sym->visible != output_visible)
+ return 0;
if (sym->type == SymIdentifier) {
if (sym->name[0] == '_' && !(symbol_map & SM_UNDERSCORE))
@@ -772,6 +812,7 @@ main(int argc, char **argv)
register_output("gnu", gnu_output_handler, NULL);
register_output("posix", posix_output_handler, NULL);
+ register_output("dot", dot_output_handler, NULL);
symbol_map = SM_FUNCTIONS|SM_STATIC|SM_UNDEFINED;
@@ -788,6 +829,9 @@ main(int argc, char **argv)
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
exit(EX_USAGE);
+ if (!no_main_option)
+ set_default_starter();
+
if (print_option == 0)
print_option = PRINT_TREE;
diff --git a/src/output.c b/src/output.c
index 625d29e..1ba2da2 100644
--- a/src/output.c
+++ b/src/output.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -364,12 +364,12 @@ tree_output()
for (p = linked_list_head(symbols[i]->callee); p;
p = p->next) {
Symbol *s = (Symbol*) p->data;
- if (symbol_is_function(s))
- depmap_set(depmap, i, ((Symbol*)p->data)->ord);
+ if (s->ord != -1 && symbol_is_function(s))
+ depmap_set(depmap, i, s->ord);
}
}
}
-
+
depmap_tc(depmap);
/* Mark recursive calls */
@@ -392,16 +392,21 @@ tree_output()
separator();
}
} else {
- if ((main_sym = start_name ? lookup(start_name) : NULL) != NULL) {
- direct_tree(0, 0, main_sym);
- separator();
+ void *state;
+
+ main_sym = first_starter(&state);
+ if (main_sym) {
+ do {
+ direct_tree(0, 0, main_sym);
+ separator();
+ } while ((main_sym = next_starter(&state)) != NULL);
} else if (!all_functions) {
all_functions = 1;
}
if (all_functions) {
for (i = 0; i < num; i++) {
- if (main_sym != symbols[i]
+ if (symbols[i]->flag != symbol_start
&& symbols[i]->source
&& (all_functions > 1 || symbols[i]->caller == NULL)) {
direct_tree(0, 0, symbols[i]);
@@ -432,6 +437,7 @@ output()
xref_output();
}
if (print_option & PRINT_TREE) {
+ eliminate_non_targets();
tree_output();
}
fclose(outfile);
diff --git a/src/parser.c b/src/parser.c
index 39d4b7c..8c53942 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997-2019 Sergey Poznyakoff
+ Copyright (C) 1997-2022 Sergey Poznyakoff
GNU cflow is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -47,11 +47,11 @@ void maybe_parm_list(int *parm_cnt_return);
void call(char*, int);
void reference(char*, int);
-int level; /* Current nesting level */
-Symbol *caller; /* Current caller */
-struct obstack text_stk; /* Obstack for composing declaration line */
+static int level; /* Current nesting level */
+static Symbol *caller; /* Current caller */
+static struct obstack text_stk; /* Obstack for composing declaration line */
-int parm_level; /* Parameter declaration nesting level */
+static int parm_level; /* Parameter declaration nesting level */
typedef struct {
int type;
@@ -61,10 +61,10 @@ typedef struct {
typedef int Stackpos[1];
-TOKSTK tok;
-TOKSTK *token_stack;
-int tos;
-int curs;
+static TOKSTK tok;
+static TOKSTK *token_stack;
+static int tos;
+static int curs;
int token_stack_length = 64;
int token_stack_increase = 32;
static int need_space;
@@ -594,6 +594,14 @@ expression()
switch (tok.type) {
case ';':
return;
+ case PARM_WRAPPER:
+ if (skip_balanced('(', ')', 0) == -1) {
+ file_error(_("unexpected end of file in expression"),
+ NULL);
+ return;
+ }
+ putback();
+ break;
case LBRACE:
case LBRACE0:
case RBRACE:
@@ -637,12 +645,23 @@ expression()
break;
case '(':
/* maybe typecast */
- if (nexttoken() == TYPE || tok.type == STRUCT)
- skip_to(')');
- else {
- putback();
+ if (nexttoken() == TYPE || tok.type == STRUCT) {
+ if (skip_balanced('(', ')', 1) == -1) {
+ file_error(_("unexpected end of file in expression"),
+ NULL);
+ return;
+ }
+ if (tok.type == LBRACE || tok.type == LBRACE0) {
+ if (skip_balanced('{', '}', 1) == -1) {
+ file_error(_("unexpected end of file in expression"),
+ NULL);
+ return;
+ }
+ }
+ } else {
parens_lev++;
}
+