Xref: utzoo comp.lang.c:33557 alt.religion.computers:2023 Path: utzoo!utgpu!cs.utexas.edu!sdd.hp.com!zaphod.mps.ohio-state.edu!sol.ctr.columbia.edu!trantor.harris-atd.com!mlb.semi.harris.com!uflorida!travis!brad From: brad@SSD.CSD.HARRIS.COM (Brad Appleton) Newsgroups: comp.lang.c,alt.religion.computers Subject: Re: ANSI C prototypes Message-ID: <1480@travis.csd.harris.com> Date: 8 Nov 90 16:48:10 GMT References: <3933.27353319@cc.helsinki.fi> Sender: news@travis.csd.harris.com Followup-To: comp.lang.c Organization: Harris Computers Systems Division, Fort Lauderdale,FL Lines: 835 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@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 #include #else #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 extern char *malloc(); #endif #include #include #include #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 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@ssd.csd.harris.com Harris Computer Systems uunet!hcx1!brad Fort Lauderdale, FL USA ~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~