## 6 Controlling Symbol Types ¶

An alert reader has already noticed something strange in the above output: the function `_exit` is missing, although according to the source file it is called twice by `printdir`. It is because by default `cflow` omits from its output all symbols beginning with underscore character. To include these symbols as well, specify `-i _` (or `--include _`) command line option. Continuing our example:

    $ cflow --number -i _ d.c
        1 main() <int main (int argc,char **argv) at d.c:85>:
        2     fprintf()
        3     atoi()
        4     printdir() <void printdir (int level,char *name) at d.c:42> (R):
        5         getcwd()
        6         perror()
        7         _exit()
        8         chdir()
        9         opendir()
       10         readdir()
       11         printf()
       12         ignorent() <int ignorent (char *name) at d.c:28>:
       13             strcmp()
       14         isdir() <int isdir (char *name) at d.c:12>:
       15             stat()
       16             perror()
       17             S_ISDIR()
       18         putchar()
       19         printdir()
                    <void printdir (int level,char *name) at d.c:42>
                    (recursive: see 4)
       20         closedir()

In general, `--include` takes an argument specifying a list of symbol classes. Default option behavior is to include the requested classes to the output. If the argument begins with a minus or caret sign, this behavior is reversed and the requested symbol classes are excluded from the output.

The symbol class ‘`_`’ includes symbols whose names begin with an underscore. Another useful symbol class is ‘`s`’, representing static functions or data. By default, static functions are always included in the output. To omit them, one can give `-i ^s` (or `-i -s` 4) command line option. Our sample program `d.c` defines static function `isdir`, running `cflow -i ^s`, completely omits this function and its callees from the resulting graph:

    $ cflow --number -i ^s d.c
        1 main() <int main (int argc,char **argv) at d.c:85>:
        2     fprintf()
        3     atoi()
        4     printdir() <void printdir (int level,char *name) at d.c:42> (R):
        5         getcwd()
        6         perror()
        7         chdir()
        8         opendir()
        9         readdir()
       10         printf()
       11         ignorent() <int ignorent (char *name) at d.c:28>:
       12             strcmp()
       13         putchar()
       14         printdir()
                    <void printdir (int level,char *name) at d.c:42>
                    (recursive: see 4)
       15         closedir()

Actually, the exclusion sign (‘`^`’ or ‘`-`’) can be used any place in `-i` argument, not only at the beginning. Thus, option `-i _^s` means “include symbols, beginning with underscore and exclude static functions”. Several `-i` options accumulate, so the previous example can also be written as `-i _ -i ^s`.

It is important to notice that by default `cflow` graphs contain only functions. You can, however, request displaying variables as well, by using symbol class ‘`x`’. This class contains all data symbols, both global and static, so to include these in the output, use option `-i x`. For example:

    $ cflow --number -i x d.c
        1 main() <int main (int argc,char **argv) at d.c:85>:
        2     fprintf()
        3     stderr
        4     max_level <int max_level at d.c:37>
        5     atoi()
        6     printdir() <void printdir (int level,char *name) at d.c:42> (R):
        7         DIR
        8         dir
        9         getcwd()
       10         perror()
       11         chdir()
       12         opendir()
       13         readdir()
       14         printf()
       15         ignorent() <int ignorent (char *name) at d.c:28>:
       16             ignored_names <char *ignored_names[] at d.c:24>
       17             strcmp()
       18         isdir() <int isdir (char *name) at d.c:12>:
       19             stat()
       20             perror()
       21             S_ISDIR()
       22             NULL
       23         max_level <int max_level at d.c:37>
       24         putchar()
       25         printdir()
                    <void printdir (int level,char *name) at d.c:42>
                    (recursive: see 6)
       26         closedir()

Now, lines 3, 4, 16 and 23 show data symbols, with their definitions when available. Notice, however, lines 7 and 8. Why both type name `DIR` and automatic variable `dir` are listed as data?

To answer this question, let’s first describe the `cflow` notion of symbols. The program keeps its symbol tables, which are initially filled with `C` predefined keywords. When parsing input files, `cflow` updates these tables. In particular, upon encountering a `typedef`, it registers the defined symbol as a type.

Now, `DIR` is not declared in `d.c`, so `cflow` has no way of knowing it is a data type. So, it supposes it is a variable. But then the input:

      DIR *dir;

is parsed as an expression, meaning “multiply `DIR` by `dir`”.

Of course, it is wrong. There are two ways to help `cflow` out of this confusion. You can either explicitly declare `DIR` as data type, or let `cflow` run preprocessor, so it sees the contents of the include files and determines it by itself. Running preprocessor is covered by the next chapter (see Running Preprocessor). In the present chapter we will concentrate on the first method.

The command line option `--symbol` (`-s`) declares a syntactic class of the symbol. Its argument consists of two strings separated by a colon:

      --symbol sym:class

The first string, sym is a `C` identifier to be recorded in the symbol table. The second string, class, specifies a class to be associated with this symbol. In particular, if class is ‘`type`’, the symbol sym will be recorded as a `C` type definition. Thus, to fix the above output, run:

    $ cflow --number -i x --symbol DIR:type d.c

Another important symbol type is a parameter wrapper. It is a kind of a macro, often used in sources that are meant to be compatible with pre-ANSI compilers to protect parameter declarations in function prototypes. For example, in the declaration below, taken from `/usr/include/resolv.h`, `__P` is a parameter wrapper:

    void res_npquery __P((const res_state, const u_char *, int, FILE *));

For `cflow` to be able to process such declarations, declare `__P` as a wrapper, for example:

    cflow --symbol __P:wrapper *.c

In both examples above the reason for using the `--symbol` option was that `cflow` was unable to determine what the given symbol was, either because it did not see the type definition, as it was in case with ‘`DIR`’, or because the macro definition was not expanded. Both cases are better solved by using preprocess mode, described in the next chapter. Nevertheless, even with preprocessor, the `--symbol` option remains useful, as shown in the following sections.

#### Footnotes

##### (4)

Notice that `-i -s` is a single option, in spite of `-s` beginning with a minus sign. Since this might be confusing, we prefer using ‘`^`’ instead of ‘`-`’ to denote symbol exclusion.