ersmith@uwovax.bitnet (Eric R. Smith) (02/04/91)
Submitted-by: ersmith@uwovax.bitnet (Eric R. Smith) Posting-number: Volume 16, Issue 90 Archive-name: mkptypes/part01 Here is mkptypes, a program for generating prototype declarations for all functions appearing in a C source file. The output declarations are enclosed in a macro so as to be usable by either an ANSI or an older C compiler. Typical usage would be to do 'mkptypes *.c >proto.h' and then have a '#include "proto.h"' line in the relevant C source code files. See the README file for more details. An earlier version of this program was released on comp.sources.misc under the name "mkproto"; this updated version (with new command line options and several bug fixes) was renamed to avoid conflict with a file system utility available on some versions of Unix. The source will probably compile as-is on most systems, providing you edit the makefile appropriately (the default is for my configuration, an Atari ST with gcc). Eric R. Smith eric.smith@uwo.ca ersmith@uwovax.bitnet # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # README # Manifest # Makefile # mkptypes.1 # mkptypes.c # mkptypes.h # mkptypes.man # This archive created: 21 January 1991 12:16:52 PM EST # By: eric (at home) echo shar: extracting README sed 's/^X//' << \SHAR_EOF > README XHere is mkptypes, a program for generating prototype declarations for all Xfunctions appearing in a C source file. The input C code may be either XK&R or ANSI C (i.e. it's OK if the functions are defined using prototypes). XUnlike some of the sed-based scripts floating around, it (usually) Xhandles prototype promotion (e.g. the prototype for 'int foo() char x;...' Xis 'int foo(int x)'). Also, it should work OK on just about any computer, Xnot just Unix-based ones (it's been tested under minix, Unix, and TOS). X XUse: typically, you would type 'mkptypes *.c >proto.h' and then add a X'#include "proto.h"' line to all the C source files. An ANSI conformant Xcompiler will then be able to do type checking on function calls across Xmodule boundaries. As a bonus, proto.h will tell you which source files Xfunctions were defined in, and (if you gave the -n function to mkptypes) Xtheir line numbers. The resulting include file may also be used by Xnon-ANSI compilers; you can disable this feature (for cleaner, strictly XANSI-conforming output) with the -A flag. See the mkptypes.man file for Xa description of all the flags mkptypes accepts. X XPlease read the description of bugs in mkptypes.man; definitely mkptypes Xwill not handle all programs correctly, but it does work on the majority of Xthem. A sample of its output is provided in the file "mkptypes.h"; this Xis the result of 'mkptypes mkptypes.c >mkptypes.h'. X XThere is ABSOLUTELY NO WARRANTY for the program; as I said, it doesn't work Xon all programs (complicated function definitions can make it produce bogus Xoutput). It does what I need, though, and it can certainly make porting stuff Xto ANSI compilers easier. X XAn earlier version of mkptypes was released on Usenet under the name X"mkproto". This version has several new command line options, and some bug Xfixes. It has been renamed to avoid conflict with a file system utility Xavailable under some versions of Unix. X XMkptypes is in the public domain. If you find any bugs (other than the ones Xdocumented) please let me know. X-- XEric R. Smith email: XDept. of Mathematics ersmith@uwovax.uwo.ca XUniversity of Western Ontario ersmith@uwovax.bitnet XLondon, Ont. Canada N6A 5B7 Xph: (519) 661-3638 SHAR_EOF if test 2224 -ne "`wc -c README`" then echo shar: error transmitting README '(should have been 2224 characters)' fi echo shar: extracting Manifest sed 's/^X//' << \SHAR_EOF > Manifest XMakefile: makefile for mkptypes. Default configuration is for Atari ST. XManifest: this file Xmkptypes.1: Unix manual page for mkptypes Xmkptypes.c: source code for mkptypes Xmkptypes.h: prototypes for mkptypes (generated by mkptypes, too) Xmkptypes.man: text version of mkptypes.1 XREADME: do what it says SHAR_EOF if test 302 -ne "`wc -c Manifest`" then echo shar: error transmitting Manifest '(should have been 302 characters)' fi echo shar: extracting Makefile sed 's/^X//' << \SHAR_EOF > Makefile X# X# Makefile for mkptypes. Edit the lines below to suit your tastes; the default X# is for my computer (Atari ST running the gcc 1.37); a Unix configuration is X# also provided. X X#CC = cc X#PROG = mkptypes X#CFLAGS = -O X XCC = gcc XPROG = mkptypes.ttp XCFLAGS = -mshort -O X X$(PROG) : mkptypes.c mkptypes.h X $(CC) $(CFLAGS) -o $(PROG) mkptypes.c X Xclean: X rm -f mkptypes.o X Xrealclean: clean X rm -f $(PROG) report core SHAR_EOF if test 409 -ne "`wc -c Makefile`" then echo shar: error transmitting Makefile '(should have been 409 characters)' fi echo shar: extracting mkptypes.1 sed 's/^X//' << \SHAR_EOF > mkptypes.1 X.TH MKPTYPES 1 X.SH NAME Xmkptypes \- make prototypes for functions X.SH SYNOPSIS X.B mkptypes X[ X.B -e X] [ X.B -n X] [ X.B -p X.I symbol X] [ X.B -s X] [ X.B -x X] [ X.B -z X] [ X.B -A X] [ X.I file ... X] X.SH DESCRIPTION X.I Mkptypes Xtakes as input one or more C source code files, and Xproduces as output (on the standard output stream) a list of function Xprototypes (a la ANSI) for the external functions defined in the Xgiven source files. This output, redirected to a file, is suitable Xfor #include'ing in a C source file. X.PP XThe function definitions in the original source Xmay be either ``old-style'' (in which case appropriate prototypes are Xgenerated for the functions) or ``new-style'' (in which the definition Xincludes a prototype already). X.PP XThe -e option causes the ``extern'' keyword to be explicitly printed Xfor external functions. Some non-ANSI compilers may need this. X.PP XThe -n option causes the line number where each function was defined Xto be prepended to the prototype declaration as a comment. X.PP XThe -p option controls the name of the macro used to guard prototype Xdefinitions. Normally this is ``_P'', but you can change it to any string Xyou like. To eliminate the guard macro entirely, use the -A option. X.PP XThe -s option causes prototypes to be generated for functions declared X``static'' as well as extern functions. X.PP XThe -x option causes parameter names to be omitted from the output Xprototypes. This may be necessary for some brain-damaged pseudo-ANSI Xcompilers. You may also prefer this style of output. This option has not Xbeen thoroughly tested. X.PP XThe -z option suppresses the definition of the prototype macro given by X-p. Header files generated by X.I mkptypes Xwith this option will not work unless the prototype macro has been defined Xelsewhere in the program by the user. Used with the -p option, the -z Xoption allows use of predefined prototype hiding macros that may exist Xon some systems. X.PP XThe -A option causes the prototypes emitted to be only readable by ANSI Xcompilers. Normally, the prototypes are "macro-ized" so that compilers Xwith __STDC__ not defined don't see them. X.PP XIf files are specified on the command line, then a comment specifying Xthe file of origin is emitted before the prototypes constructed from Xthat file. If no files are given, then no comments are emitted and Xthe C source code is taken from the standard input stream. X.SH BUGS XMkptypes is easily confused by complicated declarations, such as X.nf X int ((*signal)())() { ... X.fi Xor X.nf X struct foo { int x, y; } foofunc() { ... X.fi XThis is because the program doesn't actually understand type definitions. X.PP XSome programs may need to be run through the preprocessor before Xbeing run through X.I mkptypes . XThe -n option will not work correctly on preprocessor output if function Xdefinitions (as opposed to declarations) appear in header files. X.PP XTypedef'd types aren't correctly promoted, e.g. for X.nf X typedef schar char; int foo(x) schar x;... X.fi X.I mkptypes Xincorrectly generates the prototype int foo(schar x) rather than the X[correct] int foo(int x). X.PP XFunctions named "inline" with no explicit type qualifiers are not Xrecognized. X.SH SEE ALSO X.I cc X(1), X.I lint X(1). X.SH AUTHOR XEric R. Smith <ersmith@uwovax.uwo.ca> X.SH NOTE XThere is no warranty for this program (as noted above, it's guaranteed Xto break sometimes anyways!). Mkptypes is in the public domain. SHAR_EOF if test 3399 -ne "`wc -c mkptypes.1`" then echo shar: error transmitting mkptypes.1 '(should have been 3399 characters)' fi echo shar: extracting mkptypes.c sed 's/^X//' << \SHAR_EOF > mkptypes.c X/* Program to extract function declarations from C source code X * Written by Eric R. Smith and placed in the public domain X * Thanks to: X * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles X * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix X * manual page, and some ANSI and C++ improvements. X * Skip Gilbrech for code to skip parameter names in prototypes. X * ... and many others for helpful comments and suggestions. X */ X X/* if your compiler claims to be ANSI but doesn't have stddef.h or stdlib.h, X * change the next line. X * (and then complain to the supplier of the defective compiler) X */ X X#if defined(__STDC__) && !defined(minix) X#include <stddef.h> X#include <stdlib.h> X#else Xextern char *malloc(); Xextern long atol(); X#endif X X#ifndef EXIT_SUCCESS X#define EXIT_SUCCESS 0 X#define EXIT_FAILURE 1 X#endif X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X X/*#define DEBUG(s) (fputs(s, stderr)) /* */ X#define DEBUG(s) /* */ X X#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_')) X#define ABORTED ( (Word *) -1 ) X#define MAXPARAM 20 /* max. number of parameters to a function */ X#define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */ X Xint dostatic = 0; /* do static functions? */ Xint donum = 0; /* print line numbers? */ Xint define_macro = 1; /* define macro for prototypes? */ Xint use_macro = 1; /* use a macro for prototypes? */ Xchar *macro_name = "_P"; /* macro to use for prototypes */ Xint no_parm_names = 0; /* no parm names - only types */ Xint print_extern = 0; /* use "extern" before function declarations */ X#ifdef CPP Xint call_cpp = 0; /* preprocess files */ X#endif X Xchar *ourname; /* our name, from argv[] array */ Xint inquote = 0; /* in a quote?? */ Xint newline_seen = 1; /* are we at the start of a line */ Xlong linenum = 1L; /* line number in current file */ Xint glastc = ' '; /* last char. seen by getsym() */ X Xtypedef struct word { X struct word *next; X char string[1]; X} Word; X X#include "mkptypes.h" X X/* X * Routines for manipulating lists of words. X */ X XWord *word_alloc(s) X char *s; X{ X Word *w; X X/* note that sizeof(Word) already contains space for a terminating null X * however, we add 1 so that typefixhack can promote "float" to "double" X * by just doing a strcpy. X */ X w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); X strcpy(w->string, s); X w->next = NULL; X return w; X} X Xvoid word_free(w) X Word *w; X{ X Word *oldw; X while (w) { X oldw = w; X w = w->next; X free(oldw); X } X} X X/* return the length of a list; empty words are not counted */ Xint XList_len(w) X Word *w; X{ X int count = 0; X X while (w) { X if (*w->string) count++; X w = w->next; X } X return count; X} X X/* Append two lists, and return the result */ X XWord *word_append(w1, w2) X Word *w1, *w2; X{ X Word *r, *w; X X r = w = word_alloc(""); X X while (w1) { X w->next = word_alloc(w1->string); X w = w->next; X w1 = w1->next; X } X while (w2) { X w->next = word_alloc(w2->string); X w = w->next; X w2 = w2->next; X } X X return r; X} X X/* see if the last entry in w2 is in w1 */ X Xint Xfoundin(w1, w2) X Word *w1, *w2; X{ X while (w2->next) X w2 = w2->next; X X while (w1) { X if (!strcmp(w1->string, w2->string)) X return 1; X w1 = w1->next; X } X return 0; X} X X/* add the string s to the given list of words */ X Xvoid addword(w, s) X Word *w; char *s; X{ X while (w->next) w = w->next; X w->next = word_alloc(s); X} X X/* typefixhack: promote formal parameters of type "char", "unsigned char", X "short", or "unsigned short" to "int". X*/ X Xvoid typefixhack(w) X Word *w; X{ X Word *oldw = 0; X X while (w) { X if (*w->string) { X if ( (!strcmp(w->string, "char") || X !strcmp(w->string, "short") ) X && (List_len(w->next) < 2) ) X { X/* delete any "unsigned" specifier present -- yes, it's supposed to do this */ X if (oldw && !strcmp(oldw->string, "unsigned")) { X oldw->next = w->next; X free(w); X w = oldw; X } X strcpy(w->string, "int"); X } X else if ( !strcmp(w->string, "float") && X List_len(w->next) < 2 ) X { X strcpy(w->string, "double"); X } X } X w = w->next; X } X} X X/* read a character: if it's a newline, increment the line count */ X X#ifdef __GNUC__ /* ++jrb */ Xinline X#endif Xint ngetc(f) X FILE *f; X{ X int c; X X c = getc(f); X if (c == '\n') linenum++; X X return c; X} X X/* read the next character from the file. If the character is '\' then X * read and skip the next character. Any comment sequence is converted X * to a blank. X */ X Xint fnextch(f) X FILE *f; X{ X int c, lastc, incomment; X X c = ngetc(f); X while (c == '\\') { XDEBUG("fnextch: in backslash loop\n"); X c = ngetc(f); /* skip a character */ X c = ngetc(f); X } X if (c == '/' && !inquote) { X c = ngetc(f); X if (c == '*') { X incomment = 1; X c = ' '; XDEBUG("fnextch: comment seen\n"); X while (incomment) { X lastc = c; X c = ngetc(f); X if (lastc == '*' && c == '/') X incomment = 0; X else if (c < 0) X return c; X } X return fnextch(f); X } X else { X/* if we pre-fetched a linefeed, remember to adjust the line number */ X if (c == '\n') linenum--; X ungetc(c, f); X return '/'; X } X } X return c; X} X X X/* Get the next "interesting" character. Comments are skipped, and strings X * are converted to "0". Also, if a line starts with "#" it is skipped. X */ X Xint nextch(f) X FILE *f; X{ X int c, n; X char *p, numbuf[10]; X X c = fnextch(f); X X/* skip preprocessor directives */ X/* EXCEPTION: #line nnn or #nnn lines are interpreted */ X X if (newline_seen && c == '#') { X/* skip blanks */ X do { X c = fnextch(f); X } while ( c >= 0 && (c == '\t' || c == ' ') ); X/* check for #line */ X if (c == 'l') { X c = fnextch(f); X if (c != 'i') /* not a #line directive */ X goto skip_rest_of_line; X do { X c = fnextch(f); X } while (c >= 0 && c != '\n' && !isdigit(c)); X } X X/* if we have a digit it's a line number, from the preprocessor */ X if (c >= 0 && isdigit(c)) { X p = numbuf; X for (n = 8; n >= 0; --n) { X *p++ = c; X c = fnextch(f); X if (c <= 0 || !isdigit(c)) X break; X } X *p = 0; X linenum = atol(numbuf) - 1; X } X X/* skip the rest of the line */ Xskip_rest_of_line: X while (c >= 0 && c != '\n') X c = fnextch(f); X if (c < 0) X return c; X } X newline_seen = (c == '\n'); X X if (c == '\'' || c == '\"') { XDEBUG("nextch: in a quote\n"); X inquote = c; X while ( (c = fnextch(f)) >= 0 ) { X if (c == inquote) { X inquote = 0; XDEBUG("nextch: out of quote\n"); X return '0'; X } X } XDEBUG("nextch: EOF in a quote\n"); X } X return c; X} X X/* X * Get the next symbol from the file, skipping blanks. X * Return 0 if OK, -1 for EOF. X * Also collapses everything between { and } X */ X Xint Xgetsym(buf, f) X char *buf; FILE *f; X{ X register int c; X int inbrack = 0; X XDEBUG("in getsym\n"); X c = glastc; X while ((c > 0) && isspace(c)) { X c = nextch(f); X } XDEBUG("getsym: spaces skipped\n"); X if (c < 0) { XDEBUG("EOF read in getsym\n"); X return -1; X } X if (c == '{') { X inbrack = 1; XDEBUG("getsym: in bracket\n"); X while (inbrack) { X c = nextch(f); X if (c < 0) { XDEBUG("getsym: EOF seen in bracket loop\n"); X glastc = c; X return c; X } X if (c == '{') inbrack++; X else if (c == '}') inbrack--; X } X strcpy(buf, "{}"); X glastc = nextch(f); XDEBUG("getsym: out of in bracket loop\n"); X return 0; X } X if (!ISCSYM(c)) { X *buf++ = c; X *buf = 0; X glastc = nextch(f); XDEBUG("getsym: returning special symbol\n"); X return 0; X } X while (ISCSYM(c)) { X *buf++ = c; X c = nextch(f); X } X *buf = 0; X glastc = c; XDEBUG("getsym: returning word\n"); X return 0; X} X X/* X * skipit: skip until a ";" or the end of a function declaration is seen X */ Xint skipit(buf, f) X char *buf; X FILE *f; X{ X int i; X X do { XDEBUG("in skipit loop\n"); X i = getsym(buf, f); X if (i < 0) return i; X } while (*buf != ';' && *buf != '{'); X X return 0; X} X X/* X * find most common type specifiers for purpose of ruling them out as X * parm names X */ X Xint is_type_word(s) Xchar *s; X{ X static char *typewords[] = { X "char", "const", "double", "enum", X "float", "int", "long", "short", X "signed", "struct", "union", "unsigned", X "void", "volatile", (char *)0 X }; X X register char **ss; X X for (ss = typewords; *ss; ++ss) X if (strcmp(s, *ss) == 0) X return 1; X X return 0; X} X X X/* Ad-hoc macro to recognize parameter name for purposes of removal. X * Idea is to remove the bulk of easily recognized parm names without X * losing too many type specifiers. (sg) X */ X#define IS_PARM_NAME(w) \ X (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \ X (!(w)->next || *(w)->next->string == ',' || \ X *(w)->next->string == '[')) X X X/* X * given a list representing a type and a variable name, extract just X * the base type, e.g. "struct word *x" would yield "struct word" X */ X XWord *typelist(p) X Word *p; X{ X Word *w, *r; X X r = w = word_alloc(""); X while (p && p->next) { X/* handle int *x --> int */ X if (p->string[0] && !ISCSYM(p->string[0])) X break; X/* handle int x[] --> int */ X if (p->next->string[0] == '[') X break; X w->next = word_alloc(p->string); X w = w->next; X p = p->next; X } X return r; X} X X/* X * Get a parameter list; when this is called the next symbol in line X * should be the first thing in the list. X */ X XWord *getparamlist(f) X FILE *f; X{ X static Word *pname[MAXPARAM]; /* parameter names */ X Word *tlist, /* type name */ X *plist; /* temporary */ X int np = 0; /* number of parameters */ X int typed[MAXPARAM]; /* parameter has been given a type */ X int tlistdone; /* finished finding the type name */ X int sawsomething; X int i; X int inparen = 0; X char buf[80]; X XDEBUG("in getparamlist\n"); X for (i = 0; i < MAXPARAM; i++) X typed[i] = 0; X X plist = word_alloc(""); X X/* first, get the stuff inside brackets (if anything) */ X X sawsomething = 0; /* gets set nonzero when we see an arg */ X for (;;) { X if (getsym(buf, f) < 0) return NULL; X if (*buf == ')' && (--inparen < 0)) { X if (sawsomething) { /* if we've seen an arg */ X pname[np] = plist; X plist = word_alloc(""); X np++; X } X break; X } X if (*buf == ';') { /* something weird */ X return ABORTED; X } X sawsomething = 1; /* there's something in the arg. list */ X if (*buf == ',' && inparen == 0) { X pname[np] = plist; X plist = word_alloc(""); X np++; X } X else { X addword(plist, buf); X if (*buf == '(') inparen++; X } X } X X/* next, get the declarations after the function header */ X X inparen = 0; X X tlist = word_alloc(""); X plist = word_alloc(""); X tlistdone = 0; X sawsomething = 0; X for(;;) { X if (getsym(buf, f) < 0) return NULL; X X/* handle a list like "int x,y,z" */ X if (*buf == ',' && !inparen) { X if (!sawsomething) X return NULL; X for (i = 0; i < np; i++) { X if (!typed[i] && foundin(plist, pname[i])) { X typed[i] = 1; X word_free(pname[i]); X pname[i] = word_append(tlist, plist); X /* promote types */ X typefixhack(pname[i]); X break; X } X } X if (!tlistdone) { X tlist = typelist(plist); X tlistdone = 1; X } X word_free(plist); X plist = word_alloc(""); X } X/* handle the end of a list */ X else if (*buf == ';') { X if (!sawsomething) X return ABORTED; X for (i = 0; i < np; i++) { X if (!typed[i] && foundin(plist, pname[i])) { X typed[i] = 1; X word_free(pname[i]); X pname[i] = word_append(tlist, plist); X typefixhack(pname[i]); X break; X } X } X tlistdone = 0; X word_free(tlist); word_free(plist); X tlist = word_alloc(""); X plist = word_alloc(""); X } X/* handle the beginning of the function */ X else if (!strcmp(buf, "{}")) break; X/* otherwise, throw the word into the list (except for "register") */ X else if (strcmp(buf, "register")) { X sawsomething = 1; X addword(plist, buf); X if (*buf == '(') inparen++; X if (*buf == ')') inparen--; X } X } X X/* Now take the info we have and build a prototype list */ X X/* empty parameter list means "void" */ X if (np == 0) X return word_alloc("void"); X X plist = tlist = word_alloc(""); X for (i = 0; i < np; i++) { X X/* If no type provided, make it an "int" */ X if ( !(pname[i]->next) || X (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) { X addword(tlist, "int"); X } X while (tlist->next) tlist = tlist->next; X tlist->next = pname[i]; X if (i < np - 1) X addword(tlist, ","); X } X return plist; X} X X/* X * emit a function declaration. The attributes and name of the function X * are in wlist; the parameters are in plist. X */ X Xvoid emit(wlist, plist, startline) X Word *wlist, *plist; X long startline; X{ X Word *w; X int count = 0; X int needspace = 0; X int isstatic = 0; X XDEBUG("emit called\n"); X if (donum) X printf("/*%8ld */ ", startline); X X for (w = wlist; w; w = w->next) { X if (w->string[0]) { X count ++; X if (!strcmp(w->string, "static")) X isstatic = 1; X } X } X X/* if the -e flag was given, and it's not a static function, print "extern" */ X X if (print_extern && !isstatic) { X printf("extern "); X } X X if (count < 2) { X printf("int"); X needspace = 1; X } X X for (w = wlist; w; w = w->next) { X if (needspace) X putchar(' '); X printf("%s", w->string); X needspace = ISCSYM(w->string[0]); X } X if (use_macro) X printf(" %s((", macro_name); X else X putchar('('); X needspace = 0; X for (w = plist; w; w = w->next) { X if (no_parm_names && IS_PARM_NAME(w)) X continue; X if (w->string[0] == ',') X needspace = 1; X else if (w->string[0] == '[') X needspace = 0; X else X { X if (needspace) X putchar(' '); X needspace = ISCSYM(w->string[0]); X } X printf("%s", w->string); X } X if (use_macro) X printf("));\n"); X else X printf(");\n"); X} X X/* X * get all the function declarations X */ X Xvoid getdecl(f) X FILE *f; X{ X Word *plist, *wlist = NULL; X char buf[80]; X int sawsomething; X long startline; /* line where declaration started */ X int oktoprint; Xagain: X word_free(wlist); X wlist = word_alloc(""); X sawsomething = 0; X oktoprint = 1; X X for(;;) { XDEBUG("main getdecl loop\n"); X if (getsym(buf,f) < 0) { XDEBUG("EOF in getdecl loop\n"); X return; X } X/* try to guess when a declaration is not an external function definition */ X if (!strcmp(buf, ",") || !strcmp(buf, "{}") || X !strcmp(buf, "=") || !strcmp(buf, "typedef") || X !strcmp(buf, "extern")) { X skipit(buf, f); X goto again; X } X if (!dostatic && !strcmp(buf, "static")) { X oktoprint = 0; X } X/* for the benefit of compilers that allow "inline" declarations */ X if (!strcmp(buf, "inline") && !sawsomething) X continue; X if (!strcmp(buf, ";")) goto again; X X/* A left parenthesis *might* indicate a function definition */ X if (!strcmp(buf, "(")) { X startline = linenum; X if (!sawsomething || !(plist = getparamlist(f))) { X skipit(buf, f); X goto again; X } X if (plist == ABORTED) X goto again; X X/* It seems to have been what we wanted */ X if (oktoprint) X emit(wlist, plist, startline); X word_free(plist); X goto again; X } X addword(wlist, buf); X sawsomething = 1; X } X} X Xvoid Xmain(argc, argv) Xint argc; char **argv; X{ X FILE *f; X char *t, *iobuf; X extern void Usage(); X X if (argv[0] && argv[0][0]) X ourname = argv[0]; X else X ourname = "mkptypes"; X X argv++; argc--; X X if (argc < 0) /* strange -- no args at all */ X Usage(); X X iobuf = malloc(NEWBUFSIZ); X while (*argv && **argv == '-') { X t = *argv++; --argc; t++; X while (*t) { X if (*t == 'e') X print_extern = 1; X else if (*t == 'n') X donum = 1; X else if (*t == 'p') { X t = *argv++; --argc; X if (!t) X Usage(); X use_macro = 1; X macro_name = t; X break; X } X else if (*t == 's') X dostatic = 1; X else if (*t == 'x') X /* no parm names, only types (sg) */ X no_parm_names = 1; X else if (*t == 'z') X define_macro = 0; X else if (*t == 'A') X use_macro = 0; X else X Usage(); X t++; X } X } X X if (use_macro && define_macro) { X printf("#if defined(__STDC__) || defined(__cplusplus)\n"); X printf("# define %s(s) s\n", macro_name); X printf("#else\n"); X printf("# define %s(s) ()\n", macro_name); X printf("#endif\n\n"); X } X if (argc == 0) X getdecl(stdin); X else X while (argc > 0 && *argv) { XDEBUG("trying a new file\n"); X if (!(f = fopen(*argv, "r"))) { X perror(*argv); X exit(EXIT_FAILURE); X } X if (iobuf) X setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); X X printf("\n/* %s */\n", *argv); X linenum = 1; X newline_seen = 1; X glastc = ' '; XDEBUG("calling getdecl\n"); X getdecl(f); XDEBUG("back from getdecl\n"); X argc--; argv++; X fclose(f); XDEBUG("back from fclose\n"); X } X if (use_macro && define_macro) { X printf("\n#undef %s\n", macro_name); /* clean up namespace */ X } X exit(EXIT_SUCCESS); X} X X Xvoid Usage() X{ X fprintf(stderr, X "Usage: %s [-e][-n][-p sym][-s][-x][-z][-A][files ...]\n", ourname); X fputs(" -e: put an explicit \"extern\" keyword in declarations\n", X stderr); X fputs(" -n: put line numbers of declarations as comments\n",stderr); X fputs(" -p nm: use \"nm\" as the prototype macro (default \"_P\")\n", X stderr); X fputs(" -s: include declarations for static functions\n", stderr); X fputs(" -x: omit parameter names in prototypes\n", stderr); X fputs(" -z: omit prototype macro definition\n", stderr); X fputs(" -A: omit prototype macro; header files are strict ANSI\n", X stderr); X exit(EXIT_FAILURE); X} SHAR_EOF if test 17019 -ne "`wc -c mkptypes.c`" then echo shar: error transmitting mkptypes.c '(should have been 17019 characters)' fi echo shar: extracting mkptypes.h sed 's/^X//' << \SHAR_EOF > mkptypes.h X#if defined(__STDC__) || defined(__cplusplus) X# define _P(s) s X#else X# define _P(s) () X#endif X X X/* mkptypes.c */ XWord *word_alloc _P((char *s)); Xvoid word_free _P((Word *w)); Xint List_len _P((Word *w)); XWord *word_append _P((Word *w1, Word *w2)); Xint foundin _P((Word *w1, Word *w2)); Xvoid addword _P((Word *w, char *s)); Xvoid typefixhack _P((Word *w)); Xint ngetc _P((FILE *f)); Xint fnextch _P((FILE *f)); Xint nextch _P((FILE *f)); Xint getsym _P((char *buf, FILE *f)); Xint skipit _P((char *buf, FILE *f)); Xint is_type_word _P((char *s)); XWord *typelist _P((Word *p)); XWord *getparamlist _P((FILE *f)); Xvoid emit _P((Word *wlist, Word *plist, long startline)); Xvoid getdecl _P((FILE *f)); Xvoid main _P((int argc, char **argv)); Xvoid Usage _P((void)); X X#undef _P SHAR_EOF if test 761 -ne "`wc -c mkptypes.h`" then echo shar: error transmitting mkptypes.h '(should have been 761 characters)' fi echo shar: extracting mkptypes.man sed 's/^X//' << \SHAR_EOF > mkptypes.man XNAME X mkptypes - make prototypes for functions X X XSYNOPSIS X mkptypes [ -e ][ -n ][ -p symbol ][ -s ][ -x ][ -z ][ -A ] [ file ... ] X X XDESCRIPTION X Mkptypes takes as input one or more C source code files, and produces as X output (on the standard output stream) a list of function prototypes (a X la ANSI) for the external functions defined in the given source files. This X output, redirected to a file, is suitable for #include'ing in a C source X file. The function definitions in the original source may be either "old- X style" (in which case appropriate prototypes are generated for the funct- X ions) or "new-style" (in which the definition includes a prototype already). X X The -e option causes the "extern" keyword to be explicitly printed for X external functions. Some non-ANSI compilers may need this. X X The -n option causes the line number where each function was defined to X be prepended to the prototype declaration as a comment. X X The -p option controls the name of the macro used to guard prototype X definitions. Normally this is "_P", but you can change it to any string you X like. To eliminate the guard macro entirely, use the -A option. X X The -s option causes prototypes to be generated for functions declared X "static" as well as extern functions. X X The -x option causes parameter names to be omitted from the output proto- X types. This may be necessary for some brain-damaged pseudo-ANSI com- X pilers. You may also prefer this style of output. This option has not been X thoroughly tested. X X The -z option suppresses the definition of the prototype macro given by -p. X Header files generated by mkptypes with this option will not work unless X the prototype macro has been defined elsewhere in the program by the user. X Used with the -p option, the -z option allows use of predefined prototype X hiding macros that may exist on some systems. X X The -A option causes the prototypes emitted to be only readable by ANSI X compilers. Normally, the prototypes are "macro-ized" so that compilers X with __STDC__not defined don't see them. X X If files are specified on the command line, then a comment specifying the X file of origin is emitted before the prototypes constructed from that file. X If no files are given, then no comments are emitted and the C source code X is taken from the standard input stream. X XBUGS X Mkptypes is easily confused by complicated declarations, such as X X int ((*signal)())() f ... X or X X struct foo f int x, y; g foofunc() f ... X X This is because the program doesn't actually understand type definitions. X Some programs may need to be run through the preprocessor before being X run through mkptypes . The -n option will not work correctly on prepro- X cessor output if function definitions (as opposed to declarations) appear X in header files. X X Typedef'd types aren't correctly promoted, e.g. for X X typedef schar char; int foo(x) schar x;... X mkptypes incorrectly generates the prototype int foo(schar x) rather than X the [correct] int foo(int x). X X Functions named "inline" with no explicit type qualifiers are not recog- X nized. X X XSEE ALSO X cc (1), lint (1). X X XAUTHOR X Eric R. Smith <ersmith@uwovax.uwo.ca> X X XNOTE X There is no warranty for this program (as noted above, it's guaranteed to X break sometimes anyways!). Mkptypes is in the public domain. SHAR_EOF if test 3462 -ne "`wc -c mkptypes.man`" then echo shar: error transmitting mkptypes.man '(should have been 3462 characters)' fi # End of shell archive exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.