Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

cpp(1)

cc(1)

protogen(1)  —  Commands

NAME

protogen − ANSI C function prototype generator

SYNOPSIS

protogen [options] files

DESCRIPTION

protogen is an experimental tool that helps convert old style C code to ANSI C by generating prototypes for function declarations.  protogen does not expand macros or remove #ifdef preprocessor directives; it only alters the declarations of functions.  This approach retains the original form and content as much as possible.  However, it also imposes restrictions on the file being parsed.  The restrictions are:

• The program compiles with no errors. 

• Macro expansions cannot contain braces, parentheses, or semicolons.  protogen uses these symbols to determine where functions begin and end.  For example, a program that uses the following macros will not be prototyped correctly. 

#define BEGIN {
#define END   }

• No preprocessor directives are allowed within a function declaration.  For example, the following function will not be prototyped and a warning will be issued. 

foo(a,b
#ifdef EXTENDPARAMS
,c,d
#endif
)
char a,b
#ifdef EXTENDPARAMS
,c,d
#endif
;

• No more than one macro is used as a type specifier in a declaration.  For example, the following function will not be prototyped. 

#define EXTERNTYPE extern int
#define SPECIALTYPE register auto
EXTERNTYPE SPECIALTYPE foo(){}

• Programs that use erratic macro substitutions will not be prototyped correctly.  For example, when prototyping the following:

#define X int foo
#define Y a,b
X(Y){ ...

protogen produces:

int X(int Y){... 

Code that violates any of these assumptions can be preprocessed by cc(1) using the −P option before being prototyped.  Use of protogen on such code may cause the offending function to be ignored and no prototype generated, the issuance of a grammar conflict message or other warning, the incorrect prototype to be generated, or, when extremely erratic macro substitutions are used, protogen may produce unpredictable results.  In any case, protogen does not alter the original C source file. 

When invoking protogen, use the desired options and then a list of files to be prototyped. protogen then prototypes each file individually, and appends all prototypes to a common file specified by the −h option or to the default file prototypes.h.  All files containing functions that do not have prototypes result in the creation of a new file with the functions prototyped.  Thus, if the following files need new prototype declarations, their resulting modifications would appear under the result file name in the current directory. 

Source File Result File
filename.c → filename.a.c
filename.h → filename.a.h
filename → filename.a.c

If protogen encounters an #include directive and the file name is enclosed in angle brackets it is considered a system file and no modified result file is produced.  The file is scanned for #defines and #ifdef directives.  If, however, the file name is enclosed in double quotes, it is scanned for prototype generation.  If new prototypes are added, the modifications are produced in a result file following the same naming conventions. 

Once the new result files have been created, each should be compared to the original using the diff(1) command. Manual inspection of each file should show that only function declarations have been altered. If any of the above assumptions were violated, they show up in the results of the diff operation.  Next the prototypes.h file should be included in the proper location of each result file and compiled using the ANSI C compiler.  Once all files have been checked and compile successfully, they should be renamed and passed through protogen if other functions inside #if sections still exist. 

Options

protogen recognizes the following options:

−D name=def

−D name Defines name as if by a #define preprocessor directive (see cpp(1)).

−U name Removes any initial definition of name, where name is a reserved symbol that is predefined by the particular processor.  See cpp(1) for a list of possible predefined symbols.

−I dir Changes the algorithm for searching for #include files whose names do not begin with / to look in dir before looking in the standard directories.  See cpp(1) for more information on the −I option. 

−w Forces all prototype definitions to be widened to the standard C default promotions.  All char, unsigned char, short, and unsigned short declarations are promoted to int.  All floats are converted to double. 

−h file Specifies header output file for prototypes.  If this option is not given, the default output file prototypes.h is used. 

EXAMPLES

Let this be a sample C program to be prototyped, where NODE, RecordTypeHP700, and RecordTypeOther are defined in def.h. 

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
/∗ File: sample.c             ∗/
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
#include "def.h"
#ifdef HP700
NODE ∗foo(a,b,c)
RecordTypeHP700 c;
#else
NODE ∗foo(a,b,c)
RecordTypeOther c;
#endif
{/∗ function statements ∗/}
foo2(a,b)
long a;
char ∗b;
{/∗ function statements ∗/}

Since there are two possible paths through the program, depending on the existence of the define HP700, protogen requires two passes to prototype the program. 

$protogen -D HP700 -h sample.h sample.c
prototyping sample.c
no change   def.h
generating  sample.a.c

protogen has now prototyped the first declaration of foo and foo2.  The results are placed in sample.a.c.  The source file and result file should then be compared using the diff command and manually inspected.  After checking the contents of the file, it should be moved to a temporary file and prototyped for the second path. 

$mv sample.a.c temp.c
$protogen -U HP700 -h sample.h temp.c
prototyping temp.c
no change   def.h
generating  temp.a.c

The contents of temp.a.c:

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
/∗ File: sample.c             ∗/
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
#include "def.h"
#ifdef HP700
NODE ∗foo(int a,
int b,
RecordTypeHP700 c )
#else
NODE ∗foo(int a,
int b,
RecordTypeOther c )
#endif
{/∗ function statements ∗/}
int foo2(long a ,
char ∗b )
{/∗ function statements ∗/}

After inspecting the file for differences, the prototype header file should be inserted into the apropiate location of  the source file.  Line 4 would be the proper position for it in temp.a.c.  Next, look at the header file. 

The contents of sample.h:

#if defined(HP700)
/∗
Options  -DHP700
∗/
NODE ∗foo(int a,
int b,
RecordTypeHP700 c );
int foo2(long a ,
char ∗b );
#endif
#if !defined(HP700)
/∗
Options  -UHP700
∗/
NODE ∗foo(int a,
          int b,
          RecordTypeOther c );
int foo2(long a ,
char ∗b );
#endif

Note that the include file has two sections for each run.  Only the section with the matching defines is used.  This allows easy conversion of programs that require several passes through protogen. However, it also causes multiple declarations of the same function as with foo2().  Therefore, it might be more desirable to place the function prototypes in manually. 

Once the prototypes are in place, try to compile the new source with the ANSI C compiler.  When the program compiles and executes properly, back up the old source and replace it with the new ANSI source code. 

Common Problems When Adding Prototypes

For large programs, a common include file of all the prototypes decreases abstraction between files and may introduce naming conflicts.  Many definitions and types may also have to be added to the include file in order for the prototypes to be valid.  It is therefore very important to prototype programs together only if they make several calls to each other or in closely related groups.  Use protogen to generate special prototype header files for programs that are in different groups but make frequent calls to a common group of functions.  In most cases it is desirable to manually replace all empty declarations with their new prototypes and not introduce any new header files. 

The −w option can be used to widen parameters to their default promotions in function declarations.  It is necessary to remove empty declarations for functions that do not use default promotion types and were not prototyped with the −w option.  If any such declarations do exist or if they use typedefs that contain nonstandard promoted types, the following error message from cc(1) will be issued:

function prototype for <func-name> must contain
parameters compatible with default argument
promotions when used with an empty declaration

protogen is simply a scanner and performs no semantic analysis.  It does not look at typedefs and does not alter them when given the −w widen option.  Typedefs that need to be widened, must be done manually. 

Functions that have variable arguments must be fixed manually, using the ellipsis notation. 

DIAGNOSTICS

Error messages are sent to standard error, and report warnings and grammar conflicts.  Warnings are intended to be self-explanatory.  Grammar conflicts occur due to violations in the predefined assumptions protogen was designed for.  If a grammar conflict occurs, try preprocessing. 

COMPATIBILITY WITH OSF/1

This command is provided with the HP OSF/1 Technology Release.  It may not be provided on other implementations of OSF/1. 

SEE ALSO

cpp(1), cc(1). 

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026