📄 proto.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) 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) 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; docond = 0; donum = 0; dostatic = 1; } else Usage(); t++; } } if (docond && doold) { printf("#ifdef __STDC__\n"); printf("# define\tP(s) s\n"); printf("#else\n"); printf("# define P(s) ()\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 (dodiff) { (void) sprintf(newname, "%sdif", *argv); (void) fclose(g); if (!(g = fopen(newname, "w"))) { perror(newname); exit(EXIT_FAILURE); } } 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -