sunifdef(1)

NAME
sunifdef - simplify C preprocessor source files

SYNOPSIS
sunifdef [-v | --version]

sunifdef [-h | --help]

sunifdef [OPTION...] [files...]

DESCRIPTION
sunifdef is a more powerful successor of the FreeBSD unifdef tool. sunifdef is a preprocessor of C or C++ preprocessor source files (or more briefly a preprocessor of C/C++ source files).

From the commandline arguments it takes a set of assumptions about the symbols to be defined, or undefined, for the CPP. From the commandline it also takes one or more source files. It parses these source files to pick out conditional preprocessor directives (#if,#ifdef,#ifndef,#else,#elif,#endif). It applies the specified assumptions to these directives in attempt to evaluate them. Directives that cannot be fully evaluated on the basis of the assumptions are simplified as much as possible. Directives that can be fully evaluated are eliminated, and the source text that they control is either retained or deleted in accordance with the evaluation, mimicking the behaviour of the CPP.

sunifdef also detects #define and #undef directives and checks them for consistency with the specified assumptions. If a #define or #undef directive repeats one of the assumptions it is deleted on output; if it conflicts with any of the assumptions then it may be deleted or replaced with a diagnostic comment or a diagnostic #error, depending on commandline options.

For each source file, an output file is generated that reflects the simplifications arising from the specified assumptions. The command

sunifdef -DFOO bar.c

will write on the standard output a revision of the file bar.c that has been purged as far as possible of preprocessor constructions controlled by the truth-value of defined(FOO). This revision is equivalent to bar.c on the assumption that FOO is defined. With appropriate options and inputs, you can use a sunifdef command to perform wholesale removal of redundant preprocessor complexities from a C or C++ source tree. See the EXAMPLES section.

OPTIONS

-h,--help
    Display a usage summary and exit.

-v,--version
    Display version information and exit.

-s[f|a][l], --symbols [first | all][,locate]
    Output a list of symbols that are determinative for the truth value of #if conditions.

    f, first: List only the first occurrence of the symbol on input.

    a, all: List all occurrences of the symbol on input.

    l, locate: Report the file and line number of each listed occurrence.

fargfile, --file argfile
    Read (more) arguments from file argfile. Arguments may be written free-form, separated by whitespace, in argfile. These arguments will be parsed exactly as if they were listed on the commandline at the position of -fargfile.

-Dmacro[=string], --define macro[=string]
    Assume that #define macro[=string] is in force for processing the input file(s).

-Umacro, --undef macro
    Assume that #undef macro is in force for processing the input file(s).

-r, --replace
    Replace each input file with the corresponding output file. You must specify this option to process multiple input files.

    The option changes the default behaviour of the command when no input files are specified. In this case, input is acquired from the standard input. If -r is not specified, then a single input file is read from the standard input. If -r is specified then the names of the input files are read from the standard input. Note that --recurse implies --replace.

    If the names of the input files are read from stdin, the filenames are delimited by whitespace unless enclosed in double-quotes.

-R, --recurse
    Recurse into directories to find input files. Implies --replace. The input files may include directories with this option: otherwise a directory provokes a non-fatal error.

    All files within a directory (and within subdirectories) will be selected for input unless the --filter option is given: otherwise all files (including subdirectories) will be selected that match the --filter option.

    When --recurse is in effect, sunifdef builds a graph of all unique input files once and for all as it parses the filenames that are explicitly supplied and before it processes any of them. New files that may later appear in input directories during execution will not be processed, and files that have disappeared from input directories when they are due to be processed will provoke fatal errors.

-Fext1[,ext2...], --filter ext1[,ext2...]
    Process only input files that have one of the file extensions ext1,ext2... A file extension may be any terminal segment of a filename that follows a '.'.

-Bsuffix, --backup suffix
    Backup each input file before replacing it, the backup file having the same name as the input file with suffix appended to it.

-x[d|c|e], --conflict [delete | comment | error]
    Select the action to be taken when a #define or #undef directive is encountered in an input file that conflicts with one of the -D or -U assumptions:

    d, delete: Delete the conflicting directive.

    c, comment: Replace the conflicting directive with a diagnostic comment (default).

    e, error: Replace the conflicting directive with a diagnostic #error directive.

-g[p|i|w|e|a], --gag [progress | info | warning | error | abend]
    Suppress diagnostics no worse than [progress | info | warning | error | abend].

-gs, --gag summary.
    Suppress summary diagnostics at end of input.

-V, --verbose
    Output all diagnostics,

    If neither -V nor -garg is specified defaults are -gp -gi -gs.

-n[u|e[d]], --constant [unk | eval[,del]]
    Select the policy for processing constants in #if directives:

    u, unk: Treat constants as unknowns, i.e. like macros that are not subject to any assumptions (default).

    e[d], eval[,del]: Evaluate constants [and optionally eliminate them].

-c, --complement
    Ouput the lines that ought to be dropped and vice versa.

-d, --debug
    Write debugging information to stderr.

-k[d|b|c], --discard [drop | blank | comment]
    Select the policy for discarding lines from output:

    d, drop: Drop discarded lines.

    b, blank: Blank discarded lines.

    c, comment: Comment out discarded lines.

-K, --keepgoing
    If a parse error is encountered in an input file, continue processing subsequent input files. An event of severity abend will terminate processing regardless of --keepgoing.

-P, --pod
    Apart from CPP directives, input is to be treated as Plain Old Data. C/C++ comments and quotations will not be parsed.

-l, --line
    Output #line directives in place of discarded lines to preserve the line numbers of retained lines.

EXAMPLES

sunifdef -DUNIX -UWIN32 foo.c
sunifdef --define UNIX --undef WIN32 foo.c
    Simplify the file foo.c assuming that the symbol UNIX is defined and the symbol WIN32 is undefined. Write the simplified file to stdout. By default diagnostic messages whose severity is warning or higher will be output and no summary diagnostics will be output. All diagnostics are written to stderr.

sunifdef -DUNIX=1 -UWIN32 foo.c
sunifdef --define UNIX=1 --undef WIN32 foo.c
    Like the previous example, but the symbol UNIX is defined as 1.

sunifdef -gw -DUNIX -UWIN32 foo.c
sunifdef --gag warn --define UNIX --undef WIN32 foo.c
    Like the first example, but suppress all diagnostics (--gag) whose severity is warning or lower that would otherwise be written to stderr.

sunifdef -gw -DUNIX -UWIN32 foo.c
sunifdef --gag warn --define UNIX --undef WIN32 foo.c
    Like the first example, but suppress all diagnostics (--gag) whose severity is warning or lower that would otherwise be written to stderr.

sunifdef -gw -gs -DUNIX -UWIN32 foo.c
sunifdef --gag warn -gag summary --define UNIX --undef WIN32 foo.c
    Like the previous example, but also suppress all summary diagnostics that would otherwise be written to stderr after processing is finished (--gag summary).

sunifdef -V -DUNIX -UWIN32 foo.c
sunifdef --verbose --define UNIX --undef WIN32 foo.c
    Like the previous example, but write all diagnostics at all severities to stderr, as well as summary diagnostics (--verbose).

sunifdef -DUNIX -UWIN32 < bar.c
sunifdef --define UNIX --undef WIN32 < bar.c
    Like the previous example, but write only the default diagnostics to stderr and read the input file from stdin (in this case redirected from bar.c)

sunifdef -r -DUNIX -UWIN32 foo.c bar.c
sunifdef --replace --define UNIX --undef WIN32 foo.c bar.c
    Like the previous example, but --replace causes each input file to be replaced with the corresponding simplified output file. With this option multiple input files - foo.c, bar.c - can be supplied.

sunifdef -r -DUNIX -UWIN32 < filelist.txt
sunifdef --replace --define UNIX --undef WIN32 < filelist.txt
    Like the previous example, but read the list of input filenames from stdin (in this case redirected from filelist.txt)

sunifdef -r -B.bak -DUNIX -UWIN32 < filelist.txt
sunifdef --replace --backup ".bak" --define UNIX --undef WIN32 < filelist.txt
    Like the previous example, but create a backup of each input file with the extension .bak (--backup ".bak").

sunifdef -R -DUNIX -UWIN32 foo.c somedir bar.h otherdir
sunifdef --recurse --define UNIX --undef WIN32 foo.c somedir bar.h otherdir
    The --recurse option implies --replace and causes sunifdef to find additional input files by searching recursively within the directories somedir and otherdir

sunifdef -R -Fc,h -DUNIX -UWIN32 foo.c somedir bar.h otherdir
sunifdef --recurse --filter c,h --define UNIX --undef WIN32 foo.c somedir bar.h otherdir
    Like the previous example, but select only input files that have one of the extensions .c or .h (--filter c,h).

sunifdef -R -Fc,h -K -DUNIX -UWIN32 foo.c somedir bar.h otherdir
sunifdef --recurse --filter c,h --keepgoing --define UNIX --undef WIN32 foo.c somedir bar.h otherdir
    Like the previous example, but keep going through parse errors (--keepgoing). Processing of the input file in error will be abandoned but subsequent input files will be processed.

sunifdef -R -Fc,h -sf foo.c somedir bar.h otherdir
sunifdef --recurse --filter c,h --symbols first foo.c somedir bar.h otherdir
    Recursively select all the .c and .h files from foo.c, somedir, bar.h, otherdir and write on stderr a list of all the symbols that influence the truth-values of #if, #else, #elif conditions. Report only the first occurrence of each symbol.

sunifdef -R -Fc,h -sfl foo.c somedir bar.h otherdir
sunifdef --recurse --filter c,h --symbols first,locate foo.c somedir bar.h otherdir
    Like the previous example, but report the file and line number of each reported symbol (--symbols first,locate)

sunifdef -R -Fc,h -sal foo.c somedir bar.h otherdir
sunifdef --recurse --filter c,h --symbols all,locate foo.c somedir bar.h otherdir
    Like the previous example, but report all occurrences of the symbols (--symbols first,locate)

sunifdef -P -DUNIX -UWIN32 data.txt
sunifdef --pod --define UNIX --undef WIN32 data.txt
    Process the file data.txt with the assumptions --define UNIX and --undef WIN32 parsing the text (other than #-directives) as Plain Old Data, rather than C/C++ source. C/C++ comments and quotations will not be recognised.

sunifdef -R -fargs.txt foo.c somedir bar.h otherdir
sunifdef -R --file args.txt foo.c somedir bar.h otherdir
    Interprolate the contents of the file args.txt into the commandline, replacing --file args.txt and then execute the resulting command.

sunifdef -fargs.txt
sunifdef --file args.txt
    Substite the contents of the file args.txt for --file args.txt and then execute the resulting command.

DIAGNOSTICS

Diagnostics written to stderr are classified by severity. Each diagnostic includes a distinct hexadecimal code of the form "0xXXXXX" that encodes its severity. The 5 severities are:
    progress: Progress messages ("0xXXXXX & 0x00800" is true)

    info: Noteworthy information ("0xXXXXX & 0x01000" is true)

    warning: Indicating problematic input ("0xXXXXX & 0x02000" is true)

    error: Indicating invalid input ("0xXXXXX & 0x04000" is true)

    abend: Indicating a fatal environment or internal error ("0xXXXXX & 0x08000" is true)

Unless --gag summary is in force, sunifdef can write summary diagnostics at the end of processing. A summary diagnostic has a hexadecimal code S that encodes one of the severities and in addition S "& 0x10000" is true. Even if --gag summary is not in force, a summary will not be written if its severity is suppressed by one of the specified or default --gag options. Since all summaries have severity info or warning, this means that by default no summaries will appear and to obtain all summaries you must specify --verbose. The summaries include:
    info: The number of input files that were reached and the number that were not reached (due to abend).

    info: The number of input files reached that were abandoned (due to errors).

If there was no abend or error, then additional summaries are written (unless suppressed) indicating each of the following outcomes that has occurred:
    info: Input lines were dropped on output.

    info: Input lines were changed on output.

    warning: Input lines were changed to #error directives.

    warning: Unconditional #error directives were output.

sunifdef returns a system code SC of which the low order half of the low order byte is always meaningful:
    SC "& 1": Informational diagnostics accrued.

    SC "& 2": Warnings diagnostics accrued.

    SC "& 4": Error diagnostics accrued. (Input files provoking errors will be unchanged notwithstanding the --replace option.)

    SC "& 8": An abend occurred. Some input files may not have been reached.

If no error or abend is indicated, then the high order half of the low order byte is also meaningful:
    SC "& 16": Input lines were dropped on output. SC "& 32": Input lines were changed on output. SC "& 64": Input lines were changed to #error directives. SC "& 128": Unconditional #error directives were output.

The system code reflects diagnostics that were provoked even if they were not actually output due to --gag options.

BUGS
The conditional operator ?...:... is not parsed.

Trigraphs are not parsed.

#define and #undef directives that are found to be active are not factored into the evalation of subsequent #if directives.

Please report bugs to bugs dot sunifdef at strudl dot org

AUTHOR
Mike Kinghan imk at strudl dot org

SEE ALSO
FreeBSD unifdef(1)