ANSI C prototypes
Brad Appleton
brad at SSD.CSD.HARRIS.COM
Fri Nov 9 03:48:10 AEST 1990
I grabbed a PD prototype generator utility written in C (that I think works
for both ANSI and K&R) not too long ago - its pretty small - here it is:
I have a 10 line awk script that does it too but the C program is obviously
a wee bit more portable ;-)
Its only two files (a .c and a .h file). Actually its only one file - it can
create its own .h file but you need to get it running first :-)
Anyway - im sure some of you will find some use for it!
Its written in K&R but Im sure it would be no problem to convert to ANSI.
______________________ "And miles to go before I sleep." ______________________
Brad Appleton brad at ssd.csd.harris.com Harris Computer Systems
uunet!hcx1!brad Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~
------------------------------ cut here ---------------------------------------
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by brad on Thu Nov 8 11:41:53 EST 1990
# Contents: mkproto.c mkproto.h
echo x - mkproto.c
sed 's/^@//' > "mkproto.c" <<'@//E*O*F mkproto.c//'
/* 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. S. Manoharan included a */
/* Getopt() function and modified the code to handle C++ style */
/* comments and member functions. */
#if defined(__STDC__) && !defined(minix)
#include <stddef.h>
#include <stdlib.h>
#else
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
extern char *malloc();
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define DEBUG(s) { if (dodebug) fputs(s, stderr); } /* */
/*#define DEBUG(s) /* */
#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
#define ABORTED ( (Word *) -1 )
#define MAXPARAM 20 /* max. number of parameters to a function */
#define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
typedef enum { false = 0, true = 1 } Boolean;
Boolean newline_seen = true; /* are we at the start of a line */
Boolean dostatic = false; /* do static functions? */
Boolean donum = false; /* print line numbers? */
Boolean dopromote = true; /* promote certain sc-specifiers */
Boolean dohead = true; /* do file headers? */
Boolean dodebug = false; /* do debugging? */
Boolean docond = false; /* conditionalize for non-ANSI compilers */
long linenum = 1L; /* line number in current file */
int glastc = ' '; /* last char. seen by getsym() */
int inquote = 0; /* in a quote?? */
typedef struct word {
struct word *next;
char string[1];
} Word;
#include "mkproto.h"
/*
* Routines for manipulating lists of words.
*/
Word *word_alloc(s)
char *s;
{
Word *w;
w = (Word *) malloc((unsigned)sizeof(Word) + strlen(s) + 1);
/* ++jrb */
(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);
}
/* given a list representing a type and a variable name, extract just
* the base type, e.g. "struct word *x" would yield "struct word"
*/
Word *typelist(p)
Word *p;
{
Word *w, *r;
r = w = word_alloc("");
while (p && p->next) {
if (p->string[0] && !ISCSYM(p->string[0]))
break;
w->next = word_alloc(p->string);
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. [ Both C and C++ style comments are considered - sam ]
*/
int fnextch(f)
FILE *f;
{
int c, lastc, incomment;
c = ngetc(f);
while (c == '\\') {
DEBUG("fnextch: in backslash loop\n");
c = ngetc(f); /* skip a character */
c = ngetc(f);
}
if (c == '/' && !inquote) {
c = ngetc(f);
if (c == '*') { /* C comments */
incomment = 1;
c = ' ';
DEBUG("fnextch: comment seen\n");
while (incomment) {
lastc = c;
c = ngetc(f);
if (lastc == '*' && c == '/')
incomment = 0;
else if (c < 0)
return c;
}
return fnextch(f);
}
else if ( c == '/' ) { /* C++ comments */
incomment = 1;
c = ' ';
DEBUG("fnextch: C++ comment seen\n");
while ( c != '\n' ) {
c = ngetc(f);
}
incomment = 0;
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') ? true : false;
if (c == '\'' || c == '\"') {
DEBUG("nextch: in a quote\n");
inquote = c;
while ( (c = fnextch(f)) >= 0 ) {
if (c == inquote) {
inquote = 0;
DEBUG("nextch: out of quote\n");
return '0';
}
}
DEBUG("nextch: EOF in a quote\n");
}
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;
DEBUG("in getsym\n");
c = glastc;
while ((c > 0) && isspace(c)) {
c = nextch(f);
}
DEBUG("getsym: spaces skipped\n");
if (c < 0) {
DEBUG("EOF read in getsym\n");
return -1;
}
if (c == '{') {
inbrack = 1;
DEBUG("getsym: in bracket\n");
while (inbrack) {
c = nextch(f);
if (c < 0) {
DEBUG("getsym: EOF seen in bracket loop\n");
glastc = c;
return c;
}
if (c == '{') inbrack++;
else if (c == '}') inbrack--;
}
(void)strcpy(buf, "{}");
glastc = nextch(f);
DEBUG("getsym: out of in bracket loop\n");
return 0;
}
if (!ISCSYM(c)) {
*buf++ = c;
*buf = 0;
glastc = nextch(f);
DEBUG("getsym: returning special symbol\n");
return 0;
}
while (ISCSYM(c)) {
*buf++ = c;
c = nextch(f);
}
*buf = 0;
glastc = c;
DEBUG("getsym: returning word\n");
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 {
DEBUG("in skipit loop\n");
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];
DEBUG("in getparamlist\n");
for (i = 0; i < MAXPARAM; i++)
typed[i] = 0;
plist = 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 a list like "int x,y,z" */
if (*buf == ',' && !inparen) {
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 */
if ( dopromote ) typefixhack(pname[i]);
break;
}
}
if (!tlistdone) {
tlist = typelist(plist);
tlistdone = 1;
}
word_free(plist);
plist = word_alloc("");
}
/* handle the end of a list */
else if (*buf == ';') {
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);
/* promote types */
if ( dopromote ) typefixhack(pname[i]);
break;
}
}
tlistdone = 0;
word_free(tlist);
word_free(plist);
tlist = word_alloc("");
plist = word_alloc("");
}
/* handle the beginning of the function */
else if (!strcmp(buf, "{}")) break;
/* otherwise, throw the word into the 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;
DEBUG("emit called\n");
if (donum)
(void)printf("/*%8ld */ ", startline);
for (w = wlist; w; w = w->next) {
if ( w->string[0] == ':' )
return; /* C++ member function detected */
if (w->string[0])
count ++;
}
if (count < 2)
(void)printf("int ");
for (w = wlist; w; w = w->next) {
(void)printf("%s", w->string);
if (ISCSYM(w->string[0]))
(void)printf(" ");
}
if (docond)
(void)printf("PROTO((");
else
(void)printf("( ");
for (w = plist; w; w = w->next) {
(void)printf("%s", w->string);
if (ISCSYM(w->string[0]))
(void)printf(" ");
}
if (docond)
(void)printf("));\n");
else
(void)printf(");\n");
}
/*
* get all the function declarations
*/
void getdecl(f)
FILE *f;
{
Word *plist, *wlist = NULL;
char buf[80];
int sawsomething;
long startline; /* line where declaration started */
int oktoprint;
again:
word_free(wlist);
wlist = word_alloc("");
sawsomething = 0;
oktoprint = 1;
for(;;) {
DEBUG("main getdecl loop\n");
if (getsym(buf,f) < 0) {
DEBUG("EOF in getdecl loop\n");
return;
}
/* try to 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, "(")) {
startline = linenum;
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);
sawsomething = 1;
}
}
void main(argc, argv)
int argc;
char *argv[];
{
FILE *f;
char *iobuf;
char *title = "UNSPECIFIEDHEADERTITLE";
extern void Usage();
int opch; extern int Optind; extern char *Optarg;
while ( ( opch = Getopt(argc,argv,"h:snpPD") ) != -1 )
switch ( opch ) {
case 'h' :
(void)strcpy(title, Optarg);
break;
case 's' :
dostatic = true;
break;
case 'n' :
donum = true;
break;
case 'p' :
docond = true;
break;
case 'P' :
dopromote = false;
break;
case 'D' :
dodebug = true;
break;
default :
Usage(argv[0]);
exit(0);
} /* ensw */
iobuf = malloc((unsigned)NEWBUFSIZ);
(void)printf("#ifndef %s\n", title);
(void)printf("#define %s\n", title);
if (docond) {
(void)printf("#ifdef __STDC__\n");
(void)printf("# define\tPROTO(s) s\n");
(void)printf("#else\n");
(void)printf("# define PROTO(s) ()\n");
(void)printf("#endif\n\n");
}
if ( Optind > argc )
getdecl(stdin);
else
for ( ; Optind < argc; ++Optind ) {
DEBUG("trying a new file\n");
if ( ( f = fopen(argv[Optind],"r") ) == (FILE *)0 ) {
(void)fprintf(stderr,"%s: cannot open %s\n",
argv[0], argv[Optind]);
continue;
}
/* do the file operations here */
/*
if (iobuf)
(void)setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); /* */
if (dohead)
(void)printf("\n/* %s */\n", argv[Optind]);
linenum = 1;
newline_seen = true;
glastc = ' ';
DEBUG("calling getdecl\n");
getdecl(f);
DEBUG("back from getdecl\n");
DEBUG("back from fclose\n");
(void)fclose(f);
} /* enfo */
if (docond) {
(void)printf("\n#undef PROTO\n"); /* clean up namespace */
}
(void)printf("\n#endif\n");
exit(EXIT_SUCCESS);
}
void Usage(progname)
char *progname;
{
(void)fprintf(stderr,"Usage: %s [options][files ...]\n",progname);
(void)fprintf(stderr,
"\t-n: put line numbers of declarations as comments\n");
(void)fprintf(stderr,
"\t-s: include declarations for static functions\n");
(void)fprintf(stderr,
"\t-p: make header files readable by non-ANSI compilers\n");
(void)fprintf(stderr,
"\t-P: don't promote any sc-specifiers\n");
(void)fprintf(stderr,
"\t-h HeaderTitle: use HeaderTitle to title the header file\n");
(void)fprintf(stderr,
"\t-D: operate on debug mode\n");
exit(EXIT_FAILURE);
}
#ifndef lint
static char *scid = "s. manoharan edinburgh univ";
#endif
#include<stdio.h>
char *Optarg; int Optind;
int Getopt(argc,argv,options)
int argc; char **argv; char *options;
{
char *str, *ptr; char opch; char *Strchr();
static int flag = 0; static int Argc; static char **Argv;
if ( flag == 0 ) {
Argc = argc; Argv = argv; flag = 1; Optind = 1;
}
if ( Argc <= 1 ) return -1;
if ( --Argc >= 1 ) {
str = *++Argv;
if (*str != '-') return -1; /* argument is not an option */
else { /* argument is an option */
if ( ( ptr = Strchr(options, opch = *++str) ) != (char *) 0 ) {
++Optind;
Optarg = ++str; /* point to rest of argument if any */
if ( ( *++ptr == ':' ) && ( *Optarg == '\0' ) ) {
if (--Argc <= 0) return '?';
Optarg = *++Argv; ++Optind;
}
return opch;
}
else if ( opch == '-' ) { /* end of options */
++Optind;
return -1;
}
else return '?';
}
}
return 0; /* this will never be reached */
} /* EnGetopt */
char *Strchr(s,c)
char *s; char c;
{
while ( *s != '\0' ) {
if ( *s == c ) return s;
else ++s;
}
return ( (char *) 0 );
} /* EnStrchr */
@//E*O*F mkproto.c//
chmod u=rw,g=,o= mkproto.c
echo x - mkproto.h
sed 's/^@//' > "mkproto.h" <<'@//E*O*F mkproto.h//'
#ifdef __STDC__
# define PROTO(s) s
#else
# define PROTO(s) ()
#endif
/* mkproto.c */
Word *word_alloc PROTO((char *s ));
void word_free PROTO((Word *w ));
int List_len PROTO((Word *w ));
Word *word_append PROTO((Word *w1 , Word *w2 ));
int foundin PROTO((Word *w1 , Word *w2 ));
void addword PROTO((Word *w , char *s ));
Word *typelist PROTO((Word *p ));
void typefixhack PROTO((Word *w ));
int ngetc PROTO((FILE *f ));
int fnextch PROTO((FILE *f ));
int nextch PROTO((FILE *f ));
int getsym PROTO((char *buf , FILE *f ));
int skipit PROTO((char *buf , FILE *f ));
Word *getparamlist PROTO((FILE *f ));
void emit PROTO((Word *wlist , Word *plist , long startline ));
void getdecl PROTO((FILE *f ));
void main PROTO((int argc , char **argv ));
void Usage PROTO((void ));
#undef PROTO
@//E*O*F mkproto.h//
chmod u=rw,g=,o= mkproto.h
exit 0
______________________ "And miles to go before I sleep." ______________________
Brad Appleton brad at ssd.csd.harris.com Harris Computer Systems
uunet!hcx1!brad Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~
More information about the Comp.lang.c
mailing list