[comp.os.minix] [source] Proto

wkt@ccadfa.adfa.oz.au (Warren Toomey) (11/14/90)

Seeing as Minix is becoming an Ansi/Posix system, here's some source to
add prototypes to C code. It was written by another person, and modified
by me to fix bugs and add more features. It's been lying around since
May I think. Have fun!


echo x - README
sed '/^X/s///' > README << '/'
XHere is proto, a program for generating prototype declarations for all
Xfunctions appearing in a C source file.
XUnlike some of the sed-based scripts floating around, it correctly
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 'proto *.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 proto)
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 -p flag.
X
XPlease read the description of bugs in proto.man; definitely proto
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 "proto.h"; this
Xis the result of 'proto proto.c >proto.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
XProto 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
/
echo x - Makefile
sed '/^X/s///' > Makefile << '/'
X#CC = /usr/bin2/cc
X#CFLAGS = -I/usr/include2
XALL =  proto
X
Xproto : proto.c proto.h
X	$(CC) -O -o proto $(CFLAGS) proto.c
X
Xclean:
X	rm -f $(ALL) core
/
echo x - proto.1
sed '/^X/s///' > proto.1 << '/'
X.TH proto 1L
X.SH NAME
Xproto - make prototypes for functions
X.SH SYNOPSIS
Xproto [-n] [-s] [-p] [-d] [ file ] ...
X.SH OPTIONS
X.TP 10
X.I -n
XCauses the line number where each function was defined
Xto be prepended to the prototype declaration as a comment.
X.TP
X.I -s
XCauses prototypes to be generated for functions declared
X"static" as well as extern functions.
X.TP
X.I -p
XCauses 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.TP
X.I -d
XCreates diff files for all the C files specified. These
Xdiff files contain patches to add protypes into the sources.
XIf no file is specified on the command line,
X.B proto
Xwill output the diffs on stdout.
XThis option also turns on
X.I -s
Xand
X.I -p.
X.SH DESCRIPTION
X.B Proto
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
XAlternatively,
X.B proto
Xmay be told to generate a list diff files which can be used with
X.B patch(1)
Xto add prototyped function declarations to the C code.
X.PP
X   If 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
X.B Proto
Xis easily confused by complicated declarations, such as
X.PP
X         struct foo { int x, y; } foofunc() { ...
X.PP
X   Float types are not properly promoted in old style definitions, i.e.
X.PP
X         int test(f) float f; { ...
X.PP
Xshould (because of the default type conversion rules) have prototype
X.PP
X         int test(double f);
X.PP
Xrather than the incorrect
X.PP
X         int test(float f);
X.PP
Xgenerated by 
X.B proto.
X.PP
X   Some programs may need to be run through the preprocessor before
Xbeing run through
X.B proto.
XThe
X.I -n
Xoption is unlikely to work as desired on the output of a preprocessor.
X.PP
X   Typedef'd types aren't correctly promoted, e.g. for
X.PP
X        typedef schar char; int foo(x) schar x;...
X.PP
X.B proto
Xincorrectly generates the prototype int foo(schar x) rather than
Xthe (correct) int foo(int x).
X.PP
X   Functions named "inline" with no explicit type qualifiers are not
Xrecognized.
X.SH OTHER LIMITATIONS
X.B Proto
Xcan handle functions returning function pointers, as long as the function's
Xarguments are not themselves function pointers. For example,
X.PP
X.nf
Xvoid (*func(x,y))()
X int x;
X char y;
X.fi
X.PP
Xis handled correctly, giving
X.PP
Xvoid (*func(int x, char y))(void)
X.PP
Xbut
X.PP
X.nf
Xint (*signal(sig, func))()
X void (*func)();
X.fi
X.PP
Xconfuses it. Because old C does not indicate what the function being
Xpointed at will return,
X.B proto
Xdefaults it to void.
X.PP
X.B Proto
Xgenerates diffs which, when applied, give the code both types
Xof function declarations, i.e.
X.PP
X.nf
X#ifdef __STDC__
Xvoid main ( int argc , char *argv[] )
X#else
Xmain(argc,argv)
X int argc;
X char *argv[];
X#endif
X.fi
X.PP
XHowever, if the diff'd source is then run through
X.B proto,
Xit will see both declarations and get thoroughly confused. To avoid this,
Xstrip out all of the __STDC__s with
X.B ifdef(1).
XFor example, to generate a list of prototypes for file.c, do
X.PP
X.nf
X% ifdef -U__STDC__ file.c | proto -s > prototypes
X.fi
X.SH SEE ALSO
X.nf
X   cc(1), lint(1), ifdef(1), patch(1)
X.fi
X.SH AUTHOR
X   Eric R. Smith.
X.B Proto
Xwas heavily modified by Warren Toomey to fix bugs and add diff production.
X.SH NOTE
X   There is no warranty for this program (as noted above, it's guaranteed
Xto break sometimes anyways!).
X.B Proto
Xis in the public domain.
/
echo x - proto.c
sed '/^X/s///' > proto.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 are due to Jwahar R. Bammi for fixing several bugs   */
X/* and providing the Unix makefiles.                           */
X
X#define EXIT_SUCCESS  0
X#define EXIT_FAILURE  1
X
X#include <string.h>
X#include <ctype.h>
X#include <stdio.h>
X#ifdef __STDC__
X# include <stdlib.h>
X#endif
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
Xtypedef struct word {
X	struct word *next;
X	char   string[1];
X} Word;
X
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 */
Xlong endline = 0L;		/* the last line before the { of a f'n */
Xlong symline = 0L;		/* Line that symbol was on, set by getsym() */
Xint dostatic = 0;		/* do static functions? */
Xint donum    = 0;		/* print line numbers? */
Xint dohead   = 1;		/* do file headers? */
Xint docond   = 1;		/* conditionalize for non-ANSI compilers? */
Xint dodiff   = 0;		/* Output a diff file to prototype original */
Xint glastc   = ' ';		/* last char. seen by getsym() */
XWord *endlist;			/* Parentheses after the parameters */
X
X#include "proto.h"
X
X/*
X * Routines for manipulating lists of words.
X */
X
X#ifdef __STDC__
XWord *word_alloc ( char *s )
X#else
XWord *word_alloc(s)
X	char *s;
X#endif
X{
X	Word *w;
X
X	w = (Word *) malloc((unsigned)sizeof(Word) + strlen(s) + 1);
X	(void)strcpy(w->string, s);
X	w->next = (Word *)NULL;
X	return w;
X}
X
X#ifdef __STDC__
Xvoid word_free ( Word *w )
X#else
Xvoid word_free(w)
X	Word *w;
X#endif
X{
X	Word *oldw;
X	while (w) {
X		oldw = w;
X		w = w->next;
X		free((char *)oldw);
X	}
X}
X
X/* return the length of a list; empty words are not counted */
X#ifdef __STDC__
Xint List_len ( Word *w )
X#else
Xint
XList_len(w)
X	Word *w;
X#endif
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
X#ifdef __STDC__
XWord *word_append ( Word *w1 , Word *w2 )
X#else
XWord *word_append(w1, w2)
X	Word *w1, *w2;
X#endif
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
X#ifdef __STDC__
Xint foundin ( Word *w1 , Word *w2 )
X#else
Xint
Xfoundin(w1, w2)
X	Word *w1, *w2;
X#endif
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
X#ifdef __STDC__
Xvoid addword ( Word *w , char *s )
X#else
Xvoid addword(w, s)
X	Word *w; char *s;
X#endif
X{
X	while (w->next) w = w->next;
X	w->next = word_alloc(s);
X}
X
X/* printlist: print out a list
X */
X
X#ifdef __STDC__
Xvoid printlist ( Word *p )
X#else
Xvoid printlist(p)
X Word *p;
X#endif
X {
X  Word *w;
X
X  for (w = p; w; w = w->next) {
X	(void)printf("%s", w->string);
X	if (ISCSYM(w->string[0]))
X		(void)printf(" ");
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 * Similarly, "unsigned char x[]" would yield "unsigned char".
X */
X
X#ifdef __STDC__
XWord *typelist ( Word *p )
X#else
XWord *typelist(p)
X	Word *p;
X#endif
X{
X	Word *w, *r ,*last;
X
X	last = r = w = word_alloc("");
X	while (p && p->next) {
X		if (p->string[0]=='[') {
X			word_free(w);
X			last->next=(Word *)NULL;
X			break;
X		}
X		if (p->string[0] && !ISCSYM(p->string[0]))
X			break;
X		w->next = word_alloc(p->string);
X		last = w;
X		w = w->next;
X		p = p->next;
X	}
X	return r;
X}
X
X/* typefixhack: promote formal parameters of type "char", "unsigned char",
X   "short", or "unsigned short" to "int".
X*/
X
X#ifdef __STDC__
Xvoid typefixhack ( Word *w )
X#else
Xvoid typefixhack(w)
X	Word *w;
X#endif
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				if (oldw && !strcmp(oldw->string, "unsigned")) {
X					oldw->next = w->next;
X					free((char *)w);
X					w = oldw;
X				}
X				(void)strcpy(w->string, "int");
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 __STDC__
Xint ngetc ( FILE *f )
X#else
Xint ngetc(f)
X	FILE *f;
X#endif
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
X#ifdef __STDC__
Xint fnextch ( FILE *f )
X#else
Xint fnextch(f)
X	FILE *f;
X#endif
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 (c == '\n') linenum--;
X			(void)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
X#ifdef __STDC__
Xint nextch ( FILE *f )
X#else
Xint nextch(f)
X	FILE *f;
X#endif
X{
X	int c;
X
X	c = fnextch(f);
X	if (newline_seen && c == '#') {
X		do {
X			c = fnextch(f);
X		} while (c >= 0 && c != '\n');
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
X#ifdef __STDC__
Xint getsym ( char *buf , FILE *f )
X#else
Xint
Xgetsym(buf, f)
X	char *buf; FILE *f;
X#endif
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;
X		endline= linenum;
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		(void)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		glastc = nextch(f);
X		if (c == '(' && glastc == '*') { /* Look for a 'f'n pointer */
X			*buf++ = glastc;
X			glastc = nextch(f);
X		}
X		*buf = 0;
XDEBUG("getsym: returning special symbol\n");
X		return 0;
X	}
X	symline= linenum;
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/*
X * skipit: skip until a ";" or the end of a function declaration is seen
X */
X#ifdef __STDC__
Xint skipit ( char *buf , FILE *f )
X#else
Xint skipit(buf, f)
X	char *buf;
X	FILE *f;
X#endif
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 * Get a parameter list; when this is called the next symbol in line
X * should be the first thing in the list.
X */
X
X#ifdef __STDC__
XWord *getparamlist ( FILE *f )
X#else
XWord *getparamlist(f)
X	FILE *f;
X#endif
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	endlist = 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((Word *)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((Word *)NULL);
X
X/* handle parentheses, which should indicate function pointer rtn values */
X		if (*buf == '(' ) {
X			addword(endlist,buf);
X			addword(endlist," void ");
X			inparen++;
X		}
X		else if (*buf == ')') {
X			if (symline==linenum) {
X				addword(endlist,buf);
X				addword(endlist,buf);
X			}
X			inparen--;
X		}
X/* handle a list like "int x,y,z" */
X		else if (*buf == ',' && !inparen) {
X			if (!sawsomething)
X				return((Word *)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#ifdef __STDC__
Xvoid emit ( Word *wlist , Word *plist , long startline )
X#else
Xvoid emit(wlist, plist, startline)
X	Word *wlist, *plist;
X	long  startline;
X#endif
X{
X	Word *w;
X	int count = 0;
X
XDEBUG("emit called\n");
X	if (dodiff) {
X		(void)printf("%lda%ld,%ld\n",startline-1,startline,startline+2);
X		(void)printf("> #ifdef __STDC__\n> ");
X	}
X
X	if (donum)
X		(void)printf("/*%8ld */ ", startline);
X
X	for (w = wlist; w; w = w->next) {
X		if (w->string[0])
X			count ++;
X	}
X
X	if (count < 2)
X		(void)printf("int ");
X
X	printlist(wlist);
X	
X	if (docond)
X		(void)printf("P((");
X	else
X		(void)printf("( ");
X
X	printlist(plist);
X	printlist(endlist);
X	
X	if (docond)
X		(void)printf("))");
X	else
X		(void)printf(")");
X
X	if (!dodiff)
X		(void)printf(";\n");
X	else
X		(void)printf("\n");
X
X	if (dodiff) {
X		(void)printf("> #else\n");
X		(void)printf("%lda%ld\n",endline-1,endline);
X		(void)printf("> #endif\n");
X	}
X}
X
X/*
X * get all the function declarations
X */
X
X#ifdef __STDC__
Xvoid getdecl ( FILE *f )
X#else
Xvoid getdecl(f)
X	FILE *f;
X#endif
X{
X	Word *plist, *wlist =(Word *)NULL;
X	char buf[80];
X	int sawsomething;
X	long startline= 0L;		/* 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			(void)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			if (!sawsomething || !(plist = getparamlist(f))) {
X				(void)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		if (!sawsomething) startline= symline;
X		sawsomething = 1;
X	}
X}
X
X#ifdef __STDC__
Xvoid main ( int argc , char **argv )
X#else
Xvoid
Xmain(argc, argv)
Xint argc; char **argv;
X#endif
X{
X	FILE *f, *g;
X	char *t;
X	extern void Usage();
X	char newname[40];
X
X	argv++; argc--;
X        g= stdout;
X
X	while (*argv && **argv == '-') {
X		t = *argv++; --argc; t++;
X		while (*t) {
X			if (*t == 's')
X				dostatic = 1;
X			else if (*t == 'n')
X				donum = 1;
X			else if (*t == 'p')
X				docond = 0;
X			else if (*t == 'd') {
X				dodiff = 1; docond = 0;
X				donum = 0; dostatic = 1;
X			}
X			else
X				Usage();
X			t++;
X		}
X	}
X
X	if (docond) {
X		(void)printf("#ifdef __STDC__\n");
X		(void)printf("# define\tP(s) s\n");
X		(void)printf("#else\n");
X		(void)printf("# define P(s) ()\n");
X		(void)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 (dodiff) {
X				(void)sprintf(newname,"%sdif",*argv);
X				(void)fclose(g);
X				if (!(g = fopen(newname, "w"))) {
X					perror(newname);
X					exit(EXIT_FAILURE);
X				}
X			}
X			if (dohead && !dodiff)
X				(void)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			(void)fclose(f);
XDEBUG("back from fclose\n");
X		}
X	if (docond) {
X		(void)printf("\n#undef P\n");	/* clean up namespace */
X	}
X	(void)fclose(g);
X	exit(EXIT_SUCCESS);
X}
X
X
X#ifdef __STDC__
Xvoid Usage ( void )
X#else
Xvoid Usage()
X#endif
X{
X	fputs("Usage: proto [-n][-s][-p][files ...]\n",stderr);
X	fputs("   -n: put line numbers of declarations as comments\n",stderr);
X	fputs("   -s: include declarations for static functions\n", stderr);
X	fputs("   -p: don't make header files readable by non-ANSI compilers\n",
X	      stderr);
X	fputs("   -d: produce a diff file to make original source prototyped\n",
X	      stderr);
X	exit(EXIT_FAILURE);
X}
/
echo x - proto.h
sed '/^X/s///' > proto.h << '/'
X#ifdef __STDC__
X# define	P(s) s
X#else
X# define P(s) ()
X#endif
X
X
X/* mkproto.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 ));
XWord *typelist P((Word *p ));
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 ));
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
/

-- 
   Warren Toomey VK1XWT, rescreened.
Deep in the bowels of ADFA Comp Science.
      `What the hell is SIGTTIN?'