Next: , Previous: Preprocessing, Up: Top

8 Using ASCII Art to Produce Flow Graphs.

You can configure the exact appearance of cflow output flow graph using --level-indent option. The simplest use for this option is to change the default indentation per nesting level. To do so, give the option a numeric argument specifying the number of columns to indent for each nesting level. For example, the following command sets the indentation level to 2, which is half of the default:

     cflow --level-indent 2 d.c

It can be used, for instance, to keep the graph within the page margins.

However, --level-indent can do much more than that. Each line in the flow graph consists of the following graphical elements: a start marker, an end marker, with several indent fills between them. By default, both start and end markers are empty, and each indent fill contains four spaces.

If the argument to --level-indent option has the form element=string, it specifies a character string that should be output in place of a given graph element. The element names are:

start Start marker
0 Indent fill 0
1 Indent fill 1
end0 End marker 0
end1 End marker 1

Why are there two kinds of indent fills and end markers? Remember that the flow graph represents a call tree, so it contains terminal nodes (leaves), i.e. the calls that end a function, and non-terminal nodes (the calls followed by another ones on the same nesting level). The end marker 0 is for non-terminal nodes, and end marker 1 is for terminal nodes.

As for indent fills, indent fill 1 is used to represent graph edge, whereas fill 0 is used to keep the output properly aligned.

To demonstrate this, let's consider following sample program:

     /* foo.c */
         i = h();

Now, let's represent line elements by the following strings:

start ::
0 ’ (two spaces)
1 | ’ (a vertical bar and a space)
end0 +-
end1 \-

The corresponding command line will be: cflow --level begin=:: --level '0= ' --level '1=| ' --level end0='+-' --level end1='\\-' foo.c. Notice escaping the backslash characters in end1: generally speaking, string in --level-option can contain usual C escape sequences, so the backslash character itself must be escaped. Another shortcut, allowed in string is the notation CxN, where C is any single character and N is a decimal number. This notation means “repeat character C N times”. However, character ‘x’ looses its special meaning if used at the beginning of the string.

This command will produce the following output:

     ::+-main() <int main () at foo.c:3>:
     ::  +-f() <int f () at foo.c:11>:
     ::  | \-h()
     ::  \-g()

Thus, we obtained an ASCII art representation of the call tree. GNU cflow provides a special option --tree (-T), which is a shortcut for --level '0= ' --level '1=| ' --level end0='+-' --level end1='\\-'. The following is an example of flow graph produced with this option. The source file wc.c is a simple implementation of UNIX wc command, See Source of wc command.

     $ cflow --tree --brief --cpp wc.c
     +-main() <int main (int argc,char **argv) at wc.c:127>
       +-errf() <void errf (char *fmt,...) at wc.c:34>
       | \-error_print()
       |     <void error_print (int perr,char *fmt,va_list ap) at wc.c:22>
       |   +-vfprintf()
       |   +-perror()
       |   +-fprintf()
       |   \-exit()
       +-counter() <void counter (char *file) at wc.c:108>
       | +-fopen()
       | +-perrf() <void perrf (char *fmt,...) at wc.c:46>
       | | \-error_print()
       | |    <void error_print (int perr,char *fmt,va_list ap)
       | |    at wc.c:22> [see 3]
       | +-getword() <int getword (FILE *fp) at wc.c:78>
       | | +-feof()
       | | \-isword() <int isword (unsigned char c) at wc.c:64>
       | |   \-isalpha()
       | +-fclose()
       | \-report()
       |     <void report (char *file,count_t ccount,
       |       count_t wcount,count_t lcount) at wc.c:57>
       |   \-printf()
            <void report (char *file,count_t ccount,
              count_t wcount,count_t lcount) at wc.c:57> [see 17]