689 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			689 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* proto - Generate ANSI C prototypes.	Author:	Eric R. Smith */
 | 
						|
 | 
						|
/* Program to extract function declarations from C source code
 | 
						|
 * Written by Eric R. Smith and placed in the public domain
 | 
						|
 * Thanks are due to Jwahar R. Bammi for fixing several bugs
 | 
						|
 * And providing the Unix makefiles.
 | 
						|
 */
 | 
						|
#define EXIT_SUCCESS  0
 | 
						|
#define EXIT_FAILURE  1
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_' ))
 | 
						|
#define ABORTED ( (Word *) -1 )
 | 
						|
#define MAXPARAM 20		/* max. number of parameters to a function */
 | 
						|
 | 
						|
typedef struct word {
 | 
						|
  struct word *next;
 | 
						|
  char string[1];
 | 
						|
} Word;
 | 
						|
 | 
						|
int inquote = 0;		/* in a quote? */
 | 
						|
int newline_seen = 1;		/* are we at the start of a line */
 | 
						|
long linenum = 1L;		/* line number in current file */
 | 
						|
long endline = 0L;		/* the last line before the { of a f'n */
 | 
						|
long symline = 0L;		/* Line that symbol was on, set by getsym() */
 | 
						|
int dostatic = 0;		/* do static functions? */
 | 
						|
int donum = 0;			/* print line numbers? */
 | 
						|
int dohead = 1;			/* do file headers? */
 | 
						|
int docond = 1;			/* conditionalize for non-ANSI compilers? */
 | 
						|
int dodiff = 0;			/* Output a diff file to prototype original */
 | 
						|
int doold = 0;			/* do old style: P() */
 | 
						|
int glastc = ' ';		/* last char. seen by getsym() */
 | 
						|
Word *endlist;			/* Parentheses after the parameters */
 | 
						|
char *progname;			/* name of program (for error messages) */
 | 
						|
 | 
						|
 | 
						|
_PROTOTYPE(Word * word_alloc, (char *s));
 | 
						|
_PROTOTYPE(void word_free, (Word * w));
 | 
						|
_PROTOTYPE(int List_len, (Word * w));
 | 
						|
_PROTOTYPE(Word * word_append, (Word * w1, Word * w2));
 | 
						|
_PROTOTYPE(int foundin, (Word * w1, Word * w2));
 | 
						|
_PROTOTYPE(void addword, (Word * w, char *s));
 | 
						|
_PROTOTYPE(void printlist, (Word * p));
 | 
						|
_PROTOTYPE(Word * typelist, (Word * p));
 | 
						|
_PROTOTYPE(void typefixhack, (Word * w));
 | 
						|
_PROTOTYPE(int ngetc, (FILE * f));
 | 
						|
_PROTOTYPE(int fnextch, (FILE * f));
 | 
						|
_PROTOTYPE(int nextch, (FILE * f));
 | 
						|
_PROTOTYPE(int getsym, (char *buf, FILE * f));
 | 
						|
_PROTOTYPE(int skipit, (char *buf, FILE * f));
 | 
						|
_PROTOTYPE(Word * getparamlist, (FILE * f));
 | 
						|
_PROTOTYPE(void emit, (Word * wlist, Word * plist, long startline));
 | 
						|
_PROTOTYPE(void getdecl, (FILE * f));
 | 
						|
_PROTOTYPE(int main, (int argc, char **argv));
 | 
						|
_PROTOTYPE(void Usage, (void));
 | 
						|
 | 
						|
/* Routines for manipulating lists of words. */
 | 
						|
 | 
						|
Word *word_alloc(s)
 | 
						|
char *s;
 | 
						|
{
 | 
						|
  Word *w;
 | 
						|
 | 
						|
  w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
 | 
						|
  if (w == NULL) {
 | 
						|
	fprintf(stderr, "%s: out of memory\n", progname);
 | 
						|
	exit(1);
 | 
						|
  }
 | 
						|
  (void) strcpy(w->string, s);
 | 
						|
  w->next = NULL;
 | 
						|
  return w;
 | 
						|
}
 | 
						|
 | 
						|
void word_free(w)
 | 
						|
Word *w;
 | 
						|
{
 | 
						|
  Word *oldw;
 | 
						|
  while (w) {
 | 
						|
	oldw = w;
 | 
						|
	w = w->next;
 | 
						|
	free((char *) oldw);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Return the length of a list; empty words are not counted */
 | 
						|
int List_len(w)
 | 
						|
Word *w;
 | 
						|
{
 | 
						|
  int count = 0;
 | 
						|
 | 
						|
  while (w) {
 | 
						|
	if (*w->string) count++;
 | 
						|
	w = w->next;
 | 
						|
  }
 | 
						|
  return count;
 | 
						|
}
 | 
						|
 | 
						|
/* Append two lists, and return the result */
 | 
						|
Word *word_append(w1, w2)
 | 
						|
Word *w1, *w2;
 | 
						|
{
 | 
						|
  Word *r, *w;
 | 
						|
 | 
						|
  r = w = word_alloc("");
 | 
						|
 | 
						|
  while (w1) {
 | 
						|
	w->next = word_alloc(w1->string);
 | 
						|
	w = w->next;
 | 
						|
	w1 = w1->next;
 | 
						|
  }
 | 
						|
  while (w2) {
 | 
						|
	w->next = word_alloc(w2->string);
 | 
						|
	w = w->next;
 | 
						|
	w2 = w2->next;
 | 
						|
  }
 | 
						|
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
/* See if the last entry in w2 is in w1 */
 | 
						|
int foundin(w1, w2)
 | 
						|
Word *w1, *w2;
 | 
						|
{
 | 
						|
  while (w2->next) w2 = w2->next;
 | 
						|
 | 
						|
  while (w1) {
 | 
						|
	if (!strcmp(w1->string, w2->string)) return 1;
 | 
						|
	w1 = w1->next;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Add the string s to the given list of words */
 | 
						|
void addword(w, s)
 | 
						|
Word *w;
 | 
						|
char *s;
 | 
						|
{
 | 
						|
  while (w->next) w = w->next;
 | 
						|
  w->next = word_alloc(s);
 | 
						|
}
 | 
						|
 | 
						|
/* Printlist: print out a list */
 | 
						|
void printlist(p)
 | 
						|
Word *p;
 | 
						|
{
 | 
						|
  Word *w;
 | 
						|
  int i = 0;
 | 
						|
 | 
						|
  for (w = p; w; w = w->next) {
 | 
						|
	printf("%s", w->string);
 | 
						|
	if (ISCSYM(w->string[0]) && i > 0
 | 
						|
			&& w->next && w->next->string[0] != ',') printf(" ");
 | 
						|
	i++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Given a list representing a type and a variable name, extract just
 | 
						|
 * the base type, e.g. "struct word *x" would yield "struct word".
 | 
						|
 * Similarly, "unsigned char x[]" would yield "unsigned char".
 | 
						|
 */
 | 
						|
Word *typelist(p)
 | 
						|
Word *p;
 | 
						|
{
 | 
						|
  Word *w, *r, *last;
 | 
						|
 | 
						|
  last = r = w = word_alloc("");
 | 
						|
  while (p && p->next) {
 | 
						|
	if (p->string[0] == '[') {
 | 
						|
		word_free(w);
 | 
						|
		last->next = NULL;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (p->string[0] && !ISCSYM(p->string[0])) break;
 | 
						|
	w->next = word_alloc(p->string);
 | 
						|
	last = w;
 | 
						|
	w = w->next;
 | 
						|
	p = p->next;
 | 
						|
  }
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
/* Typefixhack: promote formal parameters of type "char", "unsigned char",
 | 
						|
 * "short", or "unsigned short" to "int".
 | 
						|
 */
 | 
						|
void typefixhack(w)
 | 
						|
Word *w;
 | 
						|
{
 | 
						|
  Word *oldw = 0;
 | 
						|
 | 
						|
  while (w) {
 | 
						|
	if (*w->string) {
 | 
						|
		if ((!strcmp(w->string, "char") ||
 | 
						|
		     !strcmp(w->string, "short"))
 | 
						|
		    && (List_len(w->next) < 2)) {
 | 
						|
			if (oldw && !strcmp(oldw->string, "unsigned")) {
 | 
						|
				oldw->next = w->next;
 | 
						|
				free((char *) w);
 | 
						|
				w = oldw;
 | 
						|
			}
 | 
						|
			(void) strcpy(w->string, "int");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	w = w->next;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Read a character: if it's a newline, increment the line count */
 | 
						|
int ngetc(f)
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  c = getc(f);
 | 
						|
  if (c == '\n') linenum++;
 | 
						|
 | 
						|
  return c;
 | 
						|
}
 | 
						|
 | 
						|
/* Read the next character from the file. If the character is '\' then
 | 
						|
 * read and skip the next character. Any comment sequence is converted
 | 
						|
 * to a blank.
 | 
						|
 */
 | 
						|
int fnextch(f)
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  int c, lastc, incomment;
 | 
						|
 | 
						|
  c = ngetc(f);
 | 
						|
  while (c == '\\') {
 | 
						|
	c = ngetc(f);		/* skip a character */
 | 
						|
	c = ngetc(f);
 | 
						|
  }
 | 
						|
  if (c == '/' && !inquote) {
 | 
						|
	c = ngetc(f);
 | 
						|
	if (c == '*') {
 | 
						|
		incomment = 1;
 | 
						|
		c = ' ';
 | 
						|
		while (incomment) {
 | 
						|
			lastc = c;
 | 
						|
			c = ngetc(f);
 | 
						|
			if (lastc == '*' && c == '/')
 | 
						|
				incomment = 0;
 | 
						|
			else if (c < 0)
 | 
						|
				return c;
 | 
						|
		}
 | 
						|
		return fnextch(f);
 | 
						|
	} else {
 | 
						|
		if (c == '\n') linenum--;
 | 
						|
		(void) ungetc(c, f);
 | 
						|
		return '/';
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return c;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Get the next "interesting" character. Comments are skipped, and strings
 | 
						|
 * are converted to "0". Also, if a line starts with "#" it is skipped.
 | 
						|
 */
 | 
						|
int nextch(f)
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  c = fnextch(f);
 | 
						|
  if (newline_seen && c == '#') {
 | 
						|
	do {
 | 
						|
		c = fnextch(f);
 | 
						|
	} while (c >= 0 && c != '\n');
 | 
						|
	if (c < 0) return c;
 | 
						|
  }
 | 
						|
  newline_seen = (c == '\n');
 | 
						|
 | 
						|
  if (c == '\'' || c == '\"') {
 | 
						|
	inquote = c;
 | 
						|
	while ((c = fnextch(f)) >= 0) {
 | 
						|
		if (c == inquote) {
 | 
						|
			inquote = 0;
 | 
						|
			return '0';
 | 
						|
		}
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return c;
 | 
						|
}
 | 
						|
 | 
						|
/* Get the next symbol from the file, skipping blanks.
 | 
						|
 * Return 0 if OK, -1 for EOF.
 | 
						|
 * Also collapses everything between { and }
 | 
						|
 */
 | 
						|
int getsym(buf, f)
 | 
						|
char *buf;
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  register int c;
 | 
						|
  int inbrack = 0;
 | 
						|
 | 
						|
  c = glastc;
 | 
						|
  while ((c > 0) && isspace(c)) c = nextch(f);
 | 
						|
  if (c < 0) return -1;
 | 
						|
  if (c == '{') {
 | 
						|
	inbrack = 1;
 | 
						|
	endline = linenum;
 | 
						|
	while (inbrack) {
 | 
						|
		c = nextch(f);
 | 
						|
		if (c < 0) {
 | 
						|
			glastc = c;
 | 
						|
			return c;
 | 
						|
		}
 | 
						|
		if (c == '{')
 | 
						|
			inbrack++;
 | 
						|
		else if (c == '}')
 | 
						|
			inbrack--;
 | 
						|
	}
 | 
						|
	(void) strcpy(buf, "{}");
 | 
						|
	glastc = nextch(f);
 | 
						|
	return 0;
 | 
						|
  }
 | 
						|
  if (!ISCSYM(c)) {
 | 
						|
	*buf++ = c;
 | 
						|
	glastc = nextch(f);
 | 
						|
	if (c == '(' && glastc == '*') {	/* Look for a 'f'n pointer */
 | 
						|
		*buf++ = glastc;
 | 
						|
		glastc = nextch(f);
 | 
						|
	}
 | 
						|
	*buf = 0;
 | 
						|
	return 0;
 | 
						|
  }
 | 
						|
  symline = linenum;
 | 
						|
  while (ISCSYM(c)) {
 | 
						|
	*buf++ = c;
 | 
						|
	c = nextch(f);
 | 
						|
  }
 | 
						|
  *buf = 0;
 | 
						|
  glastc = c;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Skipit: skip until a ";" or the end of a function declaration is seen */
 | 
						|
int skipit(buf, f)
 | 
						|
char *buf;
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  do {
 | 
						|
	i = getsym(buf, f);
 | 
						|
	if (i < 0) return i;
 | 
						|
  } while (*buf != ';' && *buf != '{');
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Get a parameter list; when this is called the next symbol in line
 | 
						|
 * should be the first thing in the list.
 | 
						|
 */
 | 
						|
Word *getparamlist(f)
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  static Word *pname[MAXPARAM];	/* parameter names */
 | 
						|
  Word *tlist,			/* type name */
 | 
						|
  *plist;			/* temporary */
 | 
						|
  int np = 0;			/* number of parameters */
 | 
						|
  int typed[MAXPARAM];		/* parameter has been given a type */
 | 
						|
  int tlistdone;		/* finished finding the type name */
 | 
						|
  int sawsomething;
 | 
						|
  int i;
 | 
						|
  int inparen = 0;
 | 
						|
  char buf[80];
 | 
						|
 | 
						|
  for (i = 0; i < MAXPARAM; i++) typed[i] = 0;
 | 
						|
 | 
						|
  plist = word_alloc("");
 | 
						|
  endlist = word_alloc("");
 | 
						|
 | 
						|
  /* First, get the stuff inside brackets (if anything) */
 | 
						|
 | 
						|
  sawsomething = 0;		/* gets set nonzero when we see an arg */
 | 
						|
  for (;;) {
 | 
						|
	if (getsym(buf, f) < 0) return(NULL);
 | 
						|
	if (*buf == ')' && (--inparen < 0)) {
 | 
						|
		if (sawsomething) {	/* if we've seen an arg */
 | 
						|
			pname[np] = plist;
 | 
						|
			plist = word_alloc("");
 | 
						|
			np++;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (*buf == ';') {	/* something weird */
 | 
						|
		return ABORTED;
 | 
						|
	}
 | 
						|
	sawsomething = 1;	/* there's something in the arg. list */
 | 
						|
	if (*buf == ',' && inparen == 0) {
 | 
						|
		pname[np] = plist;
 | 
						|
		plist = word_alloc("");
 | 
						|
		np++;
 | 
						|
	} else {
 | 
						|
		addword(plist, buf);
 | 
						|
		if (*buf == '(') inparen++;
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  /* Next, get the declarations after the function header */
 | 
						|
  inparen = 0;
 | 
						|
  tlist = word_alloc("");
 | 
						|
  plist = word_alloc("");
 | 
						|
  tlistdone = 0;
 | 
						|
  sawsomething = 0;
 | 
						|
  for (;;) {
 | 
						|
	if (getsym(buf, f) < 0) return(NULL);
 | 
						|
 | 
						|
	/* Handle parentheses, which should indicate func pointer rtn values */
 | 
						|
	if (*buf == '(') {
 | 
						|
		addword(endlist, buf);
 | 
						|
		addword(endlist, " void ");
 | 
						|
		inparen++;
 | 
						|
	} else if (*buf == ')') {
 | 
						|
		if (symline == linenum) {
 | 
						|
			addword(endlist, buf);
 | 
						|
			addword(endlist, buf);
 | 
						|
		}
 | 
						|
		inparen--;
 | 
						|
	} else if (*buf == ',' && !inparen) {
 | 
						|
		/* Handle a list like "int x,y,z" */
 | 
						|
		if (!sawsomething) return(NULL);
 | 
						|
		for (i = 0; i < np; i++) {
 | 
						|
			if (!typed[i] && foundin(plist, pname[i])) {
 | 
						|
				typed[i] = 1;
 | 
						|
				word_free(pname[i]);
 | 
						|
				pname[i] = word_append(tlist, plist);
 | 
						|
				/* Promote types */
 | 
						|
				typefixhack(pname[i]);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (!tlistdone) {
 | 
						|
			tlist = typelist(plist);
 | 
						|
			tlistdone = 1;
 | 
						|
		}
 | 
						|
		word_free(plist);
 | 
						|
		plist = word_alloc("");
 | 
						|
	} else if (*buf == ';') {
 | 
						|
		/* Handle the end of a list */
 | 
						|
		if (!sawsomething) return ABORTED;
 | 
						|
		for (i = 0; i < np; i++) {
 | 
						|
			if (!typed[i] && foundin(plist, pname[i])) {
 | 
						|
				typed[i] = 1;
 | 
						|
				word_free(pname[i]);
 | 
						|
				pname[i] = word_append(tlist, plist);
 | 
						|
				typefixhack(pname[i]);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		tlistdone = 0;
 | 
						|
		word_free(tlist);
 | 
						|
		word_free(plist);
 | 
						|
		tlist = word_alloc("");
 | 
						|
		plist = word_alloc("");
 | 
						|
	} else if (!strcmp(buf, "{}"))
 | 
						|
		break;	/* Handle the  beginning of the function */
 | 
						|
		/* Otherwise, throw word into list (except for "register") */
 | 
						|
	else if (strcmp(buf, "register")) {
 | 
						|
		sawsomething = 1;
 | 
						|
		addword(plist, buf);
 | 
						|
		if (*buf == '(') inparen++;
 | 
						|
		if (*buf == ')') inparen--;
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  /* Now take the info we have and build a prototype list */
 | 
						|
 | 
						|
  /* Empty parameter list means "void" */
 | 
						|
  if (np == 0) return word_alloc("void");
 | 
						|
 | 
						|
  plist = tlist = word_alloc("");
 | 
						|
  for (i = 0; i < np; i++) {
 | 
						|
 | 
						|
  /* If no type provided, make it an "int" */
 | 
						|
	if (!(pname[i]->next) ||
 | 
						|
	    (!(pname[i]->next->next)&&strcmp(pname[i]->next->string,"void"))) {
 | 
						|
		addword(tlist, "int");
 | 
						|
	}
 | 
						|
	while (tlist->next) tlist = tlist->next;
 | 
						|
	tlist->next = pname[i];
 | 
						|
	if (i < np - 1) addword(tlist, ", ");
 | 
						|
  }
 | 
						|
  return plist;
 | 
						|
}
 | 
						|
 | 
						|
/* Emit a function declaration. The attributes and name of the function
 | 
						|
 * are in wlist; the parameters are in plist.
 | 
						|
 */
 | 
						|
void emit(wlist, plist, startline)
 | 
						|
Word *wlist, *plist;
 | 
						|
long startline;
 | 
						|
{
 | 
						|
  Word *w;
 | 
						|
  int count = 0;
 | 
						|
 | 
						|
  if (doold == 0) printf("_PROTOTYPE( ");
 | 
						|
  if (dodiff) {
 | 
						|
	printf("%lda%ld,%ld\n", startline - 1, startline, startline +2);
 | 
						|
	printf("> #ifdef __STDC__\n> ");
 | 
						|
  }
 | 
						|
  if (donum) printf("/*%8ld */ ", startline);
 | 
						|
  for (w = wlist; w; w = w->next) {
 | 
						|
	if (w->string[0]) count++;
 | 
						|
  }
 | 
						|
  if (count < 2) printf("int ");
 | 
						|
  printlist(wlist);
 | 
						|
  if (docond) {
 | 
						|
	if (doold)
 | 
						|
		printf(" P((");
 | 
						|
	else
 | 
						|
		printf(", (");
 | 
						|
  } else {
 | 
						|
	printf("(");
 | 
						|
  }
 | 
						|
 | 
						|
  printlist(plist);
 | 
						|
  printlist(endlist);
 | 
						|
 | 
						|
  if (docond) {
 | 
						|
	if (doold)
 | 
						|
		printf("))");
 | 
						|
	else
 | 
						|
		printf(") )");
 | 
						|
  } else {
 | 
						|
	printf(")");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!dodiff)
 | 
						|
	printf(";\n");
 | 
						|
  else
 | 
						|
	printf("\n");
 | 
						|
 | 
						|
  if (dodiff) {
 | 
						|
	printf("> #else\n");
 | 
						|
	printf("%lda%ld\n", endline - 1, endline);
 | 
						|
	printf("> #endif\n");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Get all the function declarations */
 | 
						|
void getdecl(f)
 | 
						|
FILE *f;
 | 
						|
{
 | 
						|
  Word *plist, *wlist = NULL;
 | 
						|
  char buf[80];
 | 
						|
  int sawsomething;
 | 
						|
  long startline = 0L;		/* line where declaration started */
 | 
						|
  int oktoprint;
 | 
						|
 | 
						|
again:				/* SHAME SHAME */
 | 
						|
  word_free(wlist);
 | 
						|
  wlist = word_alloc("");
 | 
						|
  sawsomething = 0;
 | 
						|
  oktoprint = 1;
 | 
						|
 | 
						|
  for (;;) {
 | 
						|
	if (getsym(buf, f) < 0) return;
 | 
						|
 | 
						|
	/* Guess when a declaration is not an external function definition */
 | 
						|
	if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
 | 
						|
	    !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
 | 
						|
	    !strcmp(buf, "extern")) {
 | 
						|
		(void) skipit(buf, f);
 | 
						|
		goto again;
 | 
						|
	}
 | 
						|
	if (!dostatic && !strcmp(buf, "static")) oktoprint = 0;
 | 
						|
 | 
						|
	/* For the benefit of compilers that allow "inline" declarations */
 | 
						|
	if (!strcmp(buf, "inline") && !sawsomething) continue;
 | 
						|
	if (!strcmp(buf, ";")) goto again;
 | 
						|
 | 
						|
	/* A left parenthesis *might* indicate a function definition */
 | 
						|
	if (!strcmp(buf, "(")) {
 | 
						|
		if (!sawsomething || !(plist = getparamlist(f))) {
 | 
						|
			(void) skipit(buf, f);
 | 
						|
			goto again;
 | 
						|
		}
 | 
						|
		if (plist == ABORTED) goto again;
 | 
						|
 | 
						|
		/* It seems to have been what we wanted */
 | 
						|
		if (oktoprint) emit(wlist, plist, startline);
 | 
						|
		word_free(plist);
 | 
						|
		goto again;
 | 
						|
	}
 | 
						|
	addword(wlist, buf);
 | 
						|
	if (!sawsomething) startline = symline;
 | 
						|
	sawsomething = 1;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int main(argc, argv)
 | 
						|
int argc;
 | 
						|
char **argv;
 | 
						|
{
 | 
						|
  FILE *f, *g;
 | 
						|
  char *t;
 | 
						|
  char newname[40];
 | 
						|
 | 
						|
  progname = argv[0];
 | 
						|
  argv++;
 | 
						|
  argc--;
 | 
						|
  g = stdout;
 | 
						|
 | 
						|
  while (*argv && **argv == '-') {
 | 
						|
	t = *argv++;
 | 
						|
	--argc;
 | 
						|
	t++;
 | 
						|
	while (*t) {
 | 
						|
		if (*t == 's')
 | 
						|
			dostatic = 1;
 | 
						|
		else if (*t == 'n')
 | 
						|
			donum = 1;
 | 
						|
		else if (*t == 'p')
 | 
						|
			docond = 0;
 | 
						|
		else if (*t == 'P')
 | 
						|
			doold =1;
 | 
						|
		else if (*t == 'd') {
 | 
						|
			dodiff = 1;
 | 
						|
			doold = 1;
 | 
						|
			docond = 0;
 | 
						|
			donum = 0;
 | 
						|
			dostatic = 1;
 | 
						|
		} else
 | 
						|
			Usage();
 | 
						|
		t++;
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  if (docond && doold) {
 | 
						|
	printf("#ifdef __STDC__\n");
 | 
						|
	printf("# define P(args)\targs\n");
 | 
						|
	printf("#else\n");
 | 
						|
	printf("# define P(args)\t()\n");
 | 
						|
	printf("#endif\n\n");
 | 
						|
  }
 | 
						|
  if (argc == 0)
 | 
						|
	getdecl(stdin);
 | 
						|
  else
 | 
						|
	while (argc > 0 && *argv) {
 | 
						|
		if (!(f = fopen(*argv, "r"))) {
 | 
						|
			perror(*argv);
 | 
						|
			exit(EXIT_FAILURE);
 | 
						|
		}
 | 
						|
#if 0
 | 
						|
		if (dodiff) {
 | 
						|
			(void) sprintf(newname, "%sdif", *argv);
 | 
						|
			(void) fclose(g);
 | 
						|
			if (!(g = fopen(newname, "w"))) {
 | 
						|
				perror(newname);
 | 
						|
				exit(EXIT_FAILURE);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		if (doold && dohead && !dodiff) printf("\n/* %s */\n", *argv);
 | 
						|
		linenum = 1;
 | 
						|
		newline_seen = 1;
 | 
						|
		glastc = ' ';
 | 
						|
		getdecl(f);
 | 
						|
		argc--;
 | 
						|
		argv++;
 | 
						|
		(void) fclose(f);
 | 
						|
	}
 | 
						|
  if (docond && doold) printf("\n#undef P\n");	/* clean up namespace */
 | 
						|
  (void) fclose(g);
 | 
						|
  return(EXIT_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Usage()
 | 
						|
{
 | 
						|
  fputs("Usage: ", stderr);
 | 
						|
  fputs(progname, stderr);
 | 
						|
  fputs(" [-d][-n][-p][-s] [files ...]\n", stderr);
 | 
						|
  fputs("   -P: use P() style instead of _PROTOTYPE\n", stderr);
 | 
						|
  fputs("   -d: produce a diff file to prototype original source\n", stderr);
 | 
						|
  fputs("   -n: put line numbers of declarations as comments\n", stderr);
 | 
						|
  fputs("   -p: don't make header files readable by K&R compilers\n", stderr);
 | 
						|
  fputs("   -s: include declarations for static functions\n", stderr);
 | 
						|
  exit(EXIT_FAILURE);
 | 
						|
}
 |