home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / k / mkproto / c / MKPROTO
Encoding:
Text File  |  1990-08-10  |  18.6 KB  |  658 lines

  1. /* Program to extract function declarations from C source code */
  2. /* Written by Eric R. Smith and placed in the public domain    */
  3. /* Thanks are due to Jwahar R. Bammi for fixing several bugs   */
  4. /* and providing the Unix makefiles.                           */
  5.  
  6. #if defined(__STDC__) && !defined(minix)
  7. #include <stddef.h>
  8. #include <stdlib.h>
  9. #else
  10. #define EXIT_SUCCESS  0
  11. #define EXIT_FAILURE  1
  12. extern char *malloc();
  13. #endif
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <string.h>
  18.  
  19. /*#define DEBUG(s) (fputs(s, stderr))  */
  20. #define DEBUG(s) /* */
  21.  
  22. #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  23. #define ABORTED ( (Word *) -1 )
  24. #define MAXPARAM 20             /* max. number of parameters to a function */
  25. #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  26.  
  27. int inquote = 0;                /* in a quote?? */
  28. int newline_seen = 1;           /* are we at the start of a line */
  29. long linenum  = 1L;             /* line number in current file */
  30. int dostatic = 0;               /* do static functions? */
  31. int donum    = 0;               /* print line numbers? */
  32. int dohead   = 1;               /* do file headers? */
  33. int docond   = 1;               /* conditionalize for non-ANSI compilers? */
  34. int glastc   = ' ';             /* last char. seen by getsym() */
  35.  
  36. typedef struct word {
  37.         struct word *next;
  38.         char   string[1];
  39. } Word;
  40.  
  41. #include "mkproto.h"
  42.  
  43. /*
  44.  * Routines for manipulating lists of words.
  45.  */
  46.  
  47. Word *word_alloc(s)
  48.         char *s;
  49. {
  50.         Word *w;
  51.  
  52.         w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); /* ++jrb */
  53.         strcpy(w->string, s);
  54.         w->next = NULL;
  55.         return w;
  56. }
  57.  
  58. void word_free(w)
  59.         Word *w;
  60. {
  61.         Word *oldw;
  62.         while (w) {
  63.                 oldw = w;
  64.                 w = w->next;
  65.                 free(oldw);
  66.         }
  67. }
  68.  
  69. /* return the length of a list; empty words are not counted */
  70. int
  71. List_len(w)
  72.         Word *w;
  73. {
  74.         int count = 0;
  75.  
  76.         while (w) {
  77.                 if (*w->string) count++;
  78.                 w = w->next;
  79.         }
  80.         return count;
  81. }
  82.  
  83. /* Append two lists, and return the result */
  84.  
  85. Word *word_append(w1, w2)
  86.         Word *w1, *w2;
  87. {
  88.         Word *r, *w;
  89.  
  90.         r = w = word_alloc("");
  91.  
  92.         while (w1) {
  93.                 w->next = word_alloc(w1->string);
  94.                 w = w->next;
  95.                 w1 = w1->next;
  96.         }
  97.         while (w2) {
  98.                 w->next = word_alloc(w2->string);
  99.                 w = w->next;
  100.                 w2 = w2->next;
  101.         }
  102.  
  103.         return r;
  104. }
  105.         
  106. /* see if the last entry in w2 is in w1 */
  107.  
  108. int
  109. foundin(w1, w2)
  110.         Word *w1, *w2;
  111. {
  112.         while (w2->next)
  113.                 w2 = w2->next;
  114.  
  115.         while (w1) {
  116.                 if (!strcmp(w1->string, w2->string))
  117.                         return 1;
  118.                 w1 = w1->next;
  119.         }
  120.         return 0;
  121. }
  122.  
  123. /* add the string s to the given list of words */
  124.  
  125. void addword(w, s)
  126.         Word *w; char *s;
  127. {
  128.         while (w->next) w = w->next;
  129.         w->next = word_alloc(s);
  130. }
  131.  
  132. /* given a list representing a type and a variable name, extract just
  133.  * the base type, e.g. "struct word *x" would yield "struct word"
  134.  */
  135.  
  136. Word *typelist(p)
  137.         Word *p;
  138. {
  139.         Word *w, *r;
  140.  
  141.         r = w = word_alloc("");
  142.         while (p && p->next) {
  143.                 if (p->string[0] && !ISCSYM(p->string[0]))
  144.                         break;
  145.                 w->next = word_alloc(p->string);
  146.                 w = w->next;
  147.                 p = p->next;
  148.         }
  149.         return r;
  150. }
  151.  
  152. /* typefixhack: promote formal parameters of type "char", "unsigned char",
  153.    "short", or "unsigned short" to "int".
  154. */
  155.  
  156. void typefixhack(w)
  157.         Word *w;
  158. {
  159.         Word *oldw = 0;
  160.  
  161.         while (w) {
  162.                 if (*w->string) {
  163.                         if ( (!strcmp(w->string, "char") ||
  164.                               !strcmp(w->string, "short") )
  165.                             && (List_len(w->next) < 2) )
  166.                         {
  167.                                 if (oldw && !strcmp(oldw->string, "unsigned")) {
  168.                                         oldw->next = w->next;
  169.                                         free(w);
  170.                                         w = oldw;
  171.                                 }
  172.                                 strcpy(w->string, "int");
  173.                         }
  174.                 }
  175.                 w = w->next;
  176.         }
  177. }
  178.  
  179. /* read a character: if it's a newline, increment the line count */
  180.  
  181. #ifdef __GNUC__ /* ++jrb */
  182. inline
  183. #endif
  184. int ngetc(f)
  185.         FILE *f;
  186. {
  187.         int c;
  188.  
  189.         c = getc(f);
  190.         if (c == '\n') linenum++;
  191.  
  192.         return c;
  193. }
  194.  
  195. /* read the next character from the file. If the character is '\' then
  196.  * read and skip the next character. Any comment sequence is converted
  197.  * to a blank.
  198.  */
  199.  
  200. int fnextch(f)
  201.         FILE *f;
  202. {
  203.         int c, lastc, incomment;
  204.  
  205.         c = ngetc(f);
  206.         while (c == '\\') {
  207. DEBUG("fnextch: in backslash loop\n");
  208.                 c = ngetc(f);   /* skip a character */
  209.                 c = ngetc(f);
  210.         }
  211.         if (c == '/' && !inquote) {
  212.                 c = ngetc(f);
  213.                 if (c == '*') {
  214.                         incomment = 1;
  215.                         c = ' ';
  216. DEBUG("fnextch: comment seen\n");
  217.                         while (incomment) {
  218.                                 lastc = c;
  219.                                 c = ngetc(f);
  220.                                 if (lastc == '*' && c == '/')
  221.                                         incomment = 0;
  222.                                 else if (c < 0)
  223.                                         return c;
  224.                         }
  225.                         return fnextch(f);
  226.                 }
  227.                 else {
  228.                         if (c == '\n') linenum--;
  229.                         ungetc(c, f);
  230.                         return '/';
  231.                 }
  232.         }
  233.         return c;
  234. }
  235.  
  236.  
  237. /* Get the next "interesting" character. Comments are skipped, and strings
  238.  * are converted to "0". Also, if a line starts with "#" it is skipped.
  239.  */
  240.  
  241. int nextch(f)
  242.         FILE *f;
  243. {
  244.         int c;
  245.  
  246.         c = fnextch(f);
  247.         if (newline_seen && c == '#') {
  248.                 do {
  249.                         c = fnextch(f);
  250.                 } while (c >= 0 && c != '\n');
  251.                 if (c < 0)
  252.                         return c;
  253.         }
  254.         newline_seen = (c == '\n');
  255.  
  256.         if (c == '\'' || c == '\"') {
  257. DEBUG("nextch: in a quote\n");
  258.                 inquote = c;
  259.                 while ( (c = fnextch(f)) >= 0 ) {
  260.                         if (c == inquote) {
  261.                                 inquote = 0;
  262. DEBUG("nextch: out of quote\n");
  263.                                 return '0';
  264.                         }
  265.                 }
  266. DEBUG("nextch: EOF in a quote\n");
  267.         }
  268.         return c;
  269. }
  270.  
  271. /*
  272.  * Get the next symbol from the file, skipping blanks.
  273.  * Return 0 if OK, -1 for EOF.
  274.  * Also collapses everything between { and }
  275.  */
  276.  
  277. int
  278. getsym(buf, f)
  279.         char *buf; FILE *f;
  280. {
  281.         register int c;
  282.         int inbrack = 0;
  283.  
  284. DEBUG("in getsym\n");
  285.         c = glastc;
  286.         while ((c > 0) && isspace(c)) {
  287.                 c = nextch(f);
  288.         }
  289. DEBUG("getsym: spaces skipped\n");
  290.         if (c < 0) {
  291. DEBUG("EOF read in getsym\n");
  292.                 return -1;
  293.         }
  294.         if (c == '{') {
  295.                 inbrack = 1;
  296. DEBUG("getsym: in bracket\n");
  297.                 while (inbrack) {
  298.                         c = nextch(f);
  299.                         if (c < 0) {
  300. DEBUG("getsym: EOF seen in bracket loop\n");
  301.                                 glastc = c;
  302.                                 return c;
  303.                         }
  304.                         if (c == '{') inbrack++;
  305.                         else if (c == '}') inbrack--;
  306.                 }
  307.                 strcpy(buf, "{}");
  308.                 glastc = nextch(f);
  309. DEBUG("getsym: out of in bracket loop\n");
  310.                 return 0;
  311.         }
  312.         if (!ISCSYM(c)) {
  313.                 *buf++ = c;
  314.                 *buf = 0;
  315.                 glastc = nextch(f);
  316. DEBUG("getsym: returning special symbol\n");
  317.                 return 0;
  318.         }
  319.         while (ISCSYM(c)) {
  320.                 *buf++ = c;
  321.                 c = nextch(f);
  322.         }
  323.         *buf = 0;
  324.         glastc = c;
  325. DEBUG("getsym: returning word\n");
  326.         return 0;
  327. }
  328.  
  329. /*
  330.  * skipit: skip until a ";" or the end of a function declaration is seen
  331.  */
  332. int skipit(buf, f)
  333.         char *buf;
  334.         FILE *f;
  335. {
  336.         int i;
  337.  
  338.         do {
  339. DEBUG("in skipit loop\n");
  340.                 i = getsym(buf, f);
  341.                 if (i < 0) return i;
  342.         } while (*buf != ';' && *buf != '{');
  343.  
  344.         return 0;
  345. }
  346.  
  347. /*
  348.  * Get a parameter list; when this is called the next symbol in line
  349.  * should be the first thing in the list.
  350.  */
  351.  
  352. Word *getparamlist(f)
  353.         FILE *f;
  354. {
  355.         static Word *pname[MAXPARAM]; /* parameter names */
  356.         Word    *tlist,         /* type name */
  357.                 *plist;         /* temporary */
  358.         int     np = 0;         /* number of parameters */
  359.         int     typed[MAXPARAM];  /* parameter has been given a type */
  360.         int     tlistdone;      /* finished finding the type name */
  361.         int     sawsomething;
  362.         int     i;
  363.         int     inparen = 0;
  364.         char buf[80];
  365.  
  366. DEBUG("in getparamlist\n");
  367.         for (i = 0; i < MAXPARAM; i++)
  368.                 typed[i] = 0;
  369.  
  370.         plist = word_alloc("");
  371.  
  372. /* first, get the stuff inside brackets (if anything) */
  373.  
  374.         sawsomething = 0;       /* gets set nonzero when we see an arg */
  375.         for (;;) {
  376.                 if (getsym(buf, f) < 0) return NULL;
  377.                 if (*buf == ')' && (--inparen < 0)) {
  378.                         if (sawsomething) {     /* if we've seen an arg */
  379.                                 pname[np] = plist;
  380.                                 plist = word_alloc("");
  381.                                 np++;
  382.                         }
  383.                         break;
  384.                 }
  385.                 if (*buf == ';') {      /* something weird */
  386.                         return ABORTED;
  387.                 }
  388.                 sawsomething = 1;       /* there's something in the arg. list */
  389.                 if (*buf == ',' && inparen == 0) {
  390.                         pname[np] = plist;
  391.                         plist = word_alloc("");
  392.                         np++;
  393.                 }
  394.                 else {
  395.                         addword(plist, buf);
  396.                         if (*buf == '(') inparen++;
  397.                 }
  398.         }
  399.  
  400. /* next, get the declarations after the function header */
  401.  
  402.         inparen = 0;
  403.  
  404.         tlist = word_alloc("");
  405.         plist = word_alloc("");
  406.         tlistdone = 0;
  407.         sawsomething = 0;
  408.         for(;;) {
  409.                 if (getsym(buf, f) < 0) return NULL;
  410.  
  411. /* handle a list like "int x,y,z" */
  412.                 if (*buf == ',' && !inparen) {
  413.                         if (!sawsomething)
  414.                                 return NULL;
  415.                         for (i = 0; i < np; i++) {
  416.                                 if (!typed[i] && foundin(plist, pname[i])) {
  417.                                         typed[i] = 1;
  418.                                         word_free(pname[i]);
  419.                                         pname[i] = word_append(tlist, plist);
  420.                                 /* promote types */
  421.                                         typefixhack(pname[i]);
  422.                                         break;
  423.                                 }
  424.                         }
  425.                         if (!tlistdone) {
  426.                                 tlist = typelist(plist);
  427.                                 tlistdone = 1;
  428.                         }
  429.                         word_free(plist);
  430.                         plist = word_alloc("");
  431.                 }
  432. /* handle the end of a list */
  433.                 else if (*buf == ';') {
  434.                         if (!sawsomething)
  435.                                 return ABORTED;
  436.                         for (i = 0; i < np; i++) {
  437.                                 if (!typed[i] && foundin(plist, pname[i])) {
  438.                                         typed[i] = 1;
  439.                                         word_free(pname[i]);
  440.                                         pname[i] = word_append(tlist, plist);
  441.                                         typefixhack(pname[i]);
  442.                                         break;
  443.                                 }
  444.                         }
  445.                         tlistdone = 0;
  446.                         word_free(tlist); word_free(plist);
  447.                         tlist = word_alloc("");
  448.                         plist = word_alloc("");
  449.                 }
  450. /* handle the  beginning of the function */
  451.                 else if (!strcmp(buf, "{}")) break;
  452. /* otherwise, throw the word into the list (except for "register") */
  453.                 else if (strcmp(buf, "register")) {
  454.                         sawsomething = 1;
  455.                         addword(plist, buf);
  456.                         if (*buf == '(') inparen++;
  457.                         if (*buf == ')') inparen--;
  458.                 }
  459.         }
  460.  
  461. /* Now take the info we have and build a prototype list */
  462.  
  463. /* empty parameter list means "void" */
  464.         if (np == 0)
  465.                 return word_alloc("void");
  466.  
  467.         plist = tlist = word_alloc("");
  468.         for (i = 0; i < np; i++) {
  469.  
  470. /* If no type provided, make it an "int" */
  471.                 if ( !(pname[i]->next) ||
  472.            (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  473.                         addword(tlist, "int");
  474.                 }
  475.                 while (tlist->next) tlist = tlist->next;
  476.                 tlist->next = pname[i];
  477.                 if (i < np - 1)
  478.                         addword(tlist, ", ");
  479.         }
  480.         return plist;
  481. }
  482.  
  483. /*
  484.  * emit a function declaration. The attributes and name of the function
  485.  * are in wlist; the parameters are in plist.
  486.  */
  487. void emit(wlist, plist, startline)
  488.         Word *wlist, *plist;
  489.         long  startline;
  490. {
  491.         Word *w;
  492.         int count = 0;
  493.  
  494. DEBUG("emit called\n");
  495.         if (donum)
  496.                 printf("/*%8ld */ ", startline);
  497.  
  498.         for (w = wlist; w; w = w->next) {
  499.                 if (w->string[0])
  500.                         count ++;
  501.         }
  502.  
  503.         if (count < 2)
  504.                 printf("int ");
  505.  
  506.         for (w = wlist; w; w = w->next) {
  507.                 printf("%s", w->string);
  508.                 if (ISCSYM(w->string[0]))
  509.                         printf(" ");
  510.         }
  511.         if (docond)
  512.                 printf("P((");
  513.         else
  514.                 printf("( ");
  515.         for (w = plist; w; w = w->next) {
  516.                 printf("%s", w->string);
  517.                 if (ISCSYM(w->string[0]))
  518.                         printf(" ");
  519.         }
  520.         if (docond)
  521.                 printf("));\n");
  522.         else
  523.                 printf(");\n");
  524. }
  525.  
  526. /*
  527.  * get all the function declarations
  528.  */
  529.  
  530. void getdecl(f)
  531.         FILE *f;
  532. {
  533.         Word *plist, *wlist = NULL;
  534.         char buf[80];
  535.         int sawsomething;
  536.         long startline;         /* line where declaration started */
  537.         int oktoprint;
  538. again:
  539.         word_free(wlist);
  540.         wlist = word_alloc("");
  541.         sawsomething = 0;
  542.         oktoprint = 1;
  543.  
  544.         for(;;) {
  545. DEBUG("main getdecl loop\n");
  546.                 if (getsym(buf,f) < 0) {
  547. DEBUG("EOF in getdecl loop\n");
  548.                          return;
  549.                 }
  550. /* try to guess when a declaration is not an external function definition */
  551.                 if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
  552.                     !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
  553.                     !strcmp(buf, "extern")) {
  554.                         skipit(buf, f);
  555.                         goto again;
  556.                 }
  557.                 if (!dostatic && !strcmp(buf, "static")) {
  558.                         oktoprint = 0;
  559.                 }
  560. /* for the benefit of compilers that allow "inline" declarations */
  561.                 if (!strcmp(buf, "inline") && !sawsomething)
  562.                         continue;
  563.                 if (!strcmp(buf, ";")) goto again;
  564.  
  565. /* A left parenthesis *might* indicate a function definition */
  566.                 if (!strcmp(buf, "(")) {
  567.                         startline = linenum;
  568.                         if (!sawsomething || !(plist = getparamlist(f))) {
  569.                                 skipit(buf, f);
  570.                                 goto again;
  571.                         }
  572.                         if (plist == ABORTED)
  573.                                 goto again;
  574.  
  575. /* It seems to have been what we wanted */
  576.                         if (oktoprint)
  577.                                 emit(wlist, plist, startline);
  578.                         word_free(plist);
  579.                         goto again;
  580.                 }
  581.                 addword(wlist, buf);
  582.                 sawsomething = 1;
  583.         }
  584. }
  585.  
  586. void
  587. main(argc, argv)
  588. int argc; char **argv;
  589. {
  590.         FILE *f;
  591.         char *t, *iobuf;
  592.         extern void Usage();
  593.  
  594.         argv++; argc--;
  595.  
  596.         iobuf = malloc(NEWBUFSIZ);
  597.         while (*argv && **argv == '-') {
  598.                 t = *argv++; --argc; t++;
  599.                 while (*t) {
  600.                         if (*t == 's')
  601.                                 dostatic = 1;
  602.                         else if (*t == 'n')
  603.                                 donum = 1;
  604.                         else if (*t == 'p')
  605.                                 docond = 0;
  606.                         else
  607.                                 Usage();
  608.                         t++;
  609.                 }
  610.         }
  611.  
  612.         if (docond) {
  613.                 printf("#ifdef __STDC__\n");
  614.                 printf("# define\tP(s) s\n");
  615.                 printf("#else\n");
  616.                 printf("# define P(s) ()\n");
  617.                 printf("#endif\n\n");
  618.         }
  619.         if (argc == 0)
  620.                 getdecl(stdin);
  621.         else
  622.                 while (argc > 0 && *argv) {
  623. DEBUG("trying a new file\n");
  624.                         if (!(f = fopen(*argv, "r"))) {
  625.                                 perror(*argv);
  626.                                 exit(EXIT_FAILURE);
  627.                         }
  628.                         if (iobuf)
  629.                                 setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
  630.                         if (dohead)
  631.                                 printf("\n/* %s */\n", *argv);
  632.                         linenum = 1;
  633.                         newline_seen = 1;
  634.                         glastc = ' ';
  635. DEBUG("calling getdecl\n");
  636.                         getdecl(f);
  637. DEBUG("back from getdecl\n");
  638.                         argc--; argv++;
  639.                         fclose(f);
  640. DEBUG("back from fclose\n");
  641.                 }
  642.         if (docond) {
  643.                 printf("\n#undef P\n"); /* clean up namespace */
  644.         }
  645.         exit(EXIT_SUCCESS);
  646. }
  647.  
  648.  
  649. void Usage()
  650. {
  651.         fputs("Usage: mkproto [-n][-s][-p][files ...]\n",stderr);
  652.         fputs("   -n: put line numbers of declarations as comments\n",stderr);
  653.         fputs("   -s: include declarations for static functions\n", stderr);
  654.         fputs("   -p: don't make header files readable by non-ANSI compilers\n",
  655.               stderr);
  656.         exit(EXIT_FAILURE);
  657. }
  658.