home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / mkptypes.zip / mkptypes.c < prev    next >
C/C++ Source or Header  |  1991-02-07  |  18KB  |  822 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 to:
  4.  * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles
  5.  * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix
  6.  *   manual page, and some ANSI and C++ improvements.
  7.  * Skip Gilbrech for code to skip parameter names in prototypes.
  8.  * ... and many others for helpful comments and suggestions.
  9.  */
  10.  
  11. /* if your compiler claims to be ANSI but doesn't have stddef.h or stdlib.h,
  12.  * change the next line.
  13.  * (and then complain to the supplier of the defective compiler)
  14.  */
  15.  
  16. #if defined(__STDC__) && !defined(minix)
  17. #include <stddef.h>
  18. #include <stdlib.h>
  19. #else
  20. extern char *malloc();
  21. extern long atol();
  22. #endif
  23.  
  24. #ifndef EXIT_SUCCESS
  25. #define EXIT_SUCCESS  0
  26. #define EXIT_FAILURE  1
  27. #endif
  28.  
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32.  
  33. /*#define DEBUG(s) (fputs(s, stderr)) /* */
  34. #define DEBUG(s) /* */
  35.  
  36. #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  37. #define ABORTED ( (Word *) -1 )
  38. #define MAXPARAM 20         /* max. number of parameters to a function */
  39. #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  40.  
  41. int dostatic = 0;        /* do static functions? */
  42. int donum    = 0;        /* print line numbers? */
  43. int define_macro   = 1;        /* define macro for prototypes? */
  44. int use_macro   = 1;        /* use a macro for prototypes? */
  45. char *macro_name = "_P";    /*   macro to use for prototypes */
  46. int no_parm_names = 0;        /* no parm names - only types */
  47. int print_extern = 0;        /* use "extern" before function declarations */
  48. #ifdef CPP
  49. int call_cpp = 0;        /* preprocess files */
  50. #endif
  51.  
  52. char *ourname;            /* our name, from argv[] array */
  53. int inquote = 0;        /* in a quote?? */
  54. int newline_seen = 1;        /* are we at the start of a line */
  55. long linenum  = 1L;        /* line number in current file */
  56. int glastc   = ' ';        /* last char. seen by getsym() */
  57.  
  58. typedef struct word {
  59.     struct word *next;
  60.     char   string[1];
  61. } Word;
  62.  
  63. #include "mkptypes.h"
  64.  
  65. /*
  66.  * Routines for manipulating lists of words.
  67.  */
  68.  
  69. Word *word_alloc(s)
  70.     char *s;
  71. {
  72.     Word *w;
  73.  
  74. /* note that sizeof(Word) already contains space for a terminating null
  75.  * however, we add 1 so that typefixhack can promote "float" to "double"
  76.  *  by just doing a strcpy.
  77.  */
  78.     w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
  79.     strcpy(w->string, s);
  80.     w->next = NULL;
  81.     return w;
  82. }
  83.  
  84. void word_free(w)
  85.     Word *w;
  86. {
  87.     Word *oldw;
  88.     while (w) {
  89.         oldw = w;
  90.         w = w->next;
  91.         free(oldw);
  92.     }
  93. }
  94.  
  95. /* return the length of a list; empty words are not counted */
  96. int
  97. List_len(w)
  98.     Word *w;
  99. {
  100.     int count = 0;
  101.  
  102.     while (w) {
  103.         if (*w->string) count++;
  104.         w = w->next;
  105.     }
  106.     return count;
  107. }
  108.  
  109. /* Append two lists, and return the result */
  110.  
  111. Word *word_append(w1, w2)
  112.     Word *w1, *w2;
  113. {
  114.     Word *r, *w;
  115.  
  116.     r = w = word_alloc("");
  117.  
  118.     while (w1) {
  119.         w->next = word_alloc(w1->string);
  120.         w = w->next;
  121.         w1 = w1->next;
  122.     }
  123.     while (w2) {
  124.         w->next = word_alloc(w2->string);
  125.         w = w->next;
  126.         w2 = w2->next;
  127.     }
  128.  
  129.     return r;
  130. }
  131.  
  132. /* see if the last entry in w2 is in w1 */
  133.  
  134. int
  135. foundin(w1, w2)
  136.     Word *w1, *w2;
  137. {
  138.     while (w2->next)
  139.         w2 = w2->next;
  140.  
  141.     while (w1) {
  142.         if (!strcmp(w1->string, w2->string))
  143.             return 1;
  144.         w1 = w1->next;
  145.     }
  146.     return 0;
  147. }
  148.  
  149. /* add the string s to the given list of words */
  150.  
  151. void addword(w, s)
  152.     Word *w; char *s;
  153. {
  154.     while (w->next) w = w->next;
  155.     w->next = word_alloc(s);
  156. }
  157.  
  158. /* typefixhack: promote formal parameters of type "char", "unsigned char",
  159.    "short", or "unsigned short" to "int".
  160. */
  161.  
  162. void typefixhack(w)
  163.     Word *w;
  164. {
  165.     Word *oldw = 0;
  166.  
  167.     while (w) {
  168.         if (*w->string) {
  169.             if ( (!strcmp(w->string, "char") ||
  170.                   !strcmp(w->string, "short") )
  171.                 && (List_len(w->next) < 2) )
  172.             {
  173. /* delete any "unsigned" specifier present -- yes, it's supposed to do this */
  174.                 if (oldw && !strcmp(oldw->string, "unsigned")) {
  175.                     oldw->next = w->next;
  176.                     free(w);
  177.                     w = oldw;
  178.                 }
  179.                 strcpy(w->string, "int");
  180.             }
  181.             else if ( !strcmp(w->string, "float") &&
  182.                   List_len(w->next) < 2 )
  183.             {
  184.                 strcpy(w->string, "double");
  185.             }
  186.         }
  187.         w = w->next;
  188.     }
  189. }
  190.  
  191. /* read a character: if it's a newline, increment the line count */
  192.  
  193. #ifdef __GNUC__    /* ++jrb */
  194. inline
  195. #endif
  196. int ngetc(f)
  197.     FILE *f;
  198. {
  199.     int c;
  200.  
  201.     c = getc(f);
  202.     if (c == '\n') linenum++;
  203.  
  204.     return c;
  205. }
  206.  
  207. /* read the next character from the file. If the character is '\' then
  208.  * read and skip the next character. Any comment sequence is converted
  209.  * to a blank.
  210.  */
  211.  
  212. int fnextch(f)
  213.     FILE *f;
  214. {
  215.     int c, lastc, incomment;
  216.  
  217.     c = ngetc(f);
  218.     while (c == '\\') {
  219. DEBUG("fnextch: in backslash loop\n");
  220.         c = ngetc(f);    /* skip a character */
  221.         c = ngetc(f);
  222.     }
  223.     if (c == '/' && !inquote) {
  224.         c = ngetc(f);
  225.         if (c == '*') {
  226.             incomment = 1;
  227.             c = ' ';
  228. DEBUG("fnextch: comment seen\n");
  229.             while (incomment) {
  230.                 lastc = c;
  231.                 c = ngetc(f);
  232.                 if (lastc == '*' && c == '/')
  233.                     incomment = 0;
  234.                 else if (c < 0)
  235.                     return c;
  236.             }
  237.             return fnextch(f);
  238.         }
  239.         else {
  240. /* if we pre-fetched a linefeed, remember to adjust the line number */
  241.             if (c == '\n') linenum--;
  242.             ungetc(c, f);
  243.             return '/';
  244.         }
  245.     }
  246.     return c;
  247. }
  248.  
  249.  
  250. /* Get the next "interesting" character. Comments are skipped, and strings
  251.  * are converted to "0". Also, if a line starts with "#" it is skipped.
  252.  */
  253.  
  254. int nextch(f)
  255.     FILE *f;
  256. {
  257.     int c, n;
  258.     char *p, numbuf[10];
  259.  
  260.     c = fnextch(f);
  261.  
  262. /* skip preprocessor directives */
  263. /* EXCEPTION: #line nnn or #nnn lines are interpreted */
  264.  
  265.     if (newline_seen && c == '#') {
  266. /* skip blanks */
  267.         do {
  268.             c = fnextch(f);
  269.         } while ( c >= 0 && (c == '\t' || c == ' ') );
  270. /* check for #line */
  271.         if (c == 'l') {
  272.             c = fnextch(f);
  273.             if (c != 'i')    /* not a #line directive */
  274.                 goto skip_rest_of_line;
  275.             do {
  276.                 c = fnextch(f);
  277.             } while (c >= 0 && c != '\n' && !isdigit(c));
  278.         }
  279.  
  280. /* if we have a digit it's a line number, from the preprocessor */
  281.         if (c >= 0 && isdigit(c)) {
  282.             p = numbuf;
  283.             for (n = 8; n >= 0; --n) {
  284.                 *p++ = c;
  285.                 c = fnextch(f);
  286.                 if (c <= 0 || !isdigit(c))
  287.                     break;
  288.             }
  289.             *p = 0;
  290.             linenum = atol(numbuf) - 1;
  291.         }
  292.  
  293. /* skip the rest of the line */
  294. skip_rest_of_line:
  295.         while (c >= 0 && c != '\n')
  296.             c = fnextch(f);
  297.         if (c < 0)
  298.             return c;
  299.     }
  300.     newline_seen = (c == '\n');
  301.  
  302.     if (c == '\'' || c == '\"') {
  303. DEBUG("nextch: in a quote\n");
  304.         inquote = c;
  305.         while ( (c = fnextch(f)) >= 0 ) {
  306.             if (c == inquote) {
  307.                 inquote = 0;
  308. DEBUG("nextch: out of quote\n");
  309.                 return '0';
  310.             }
  311.         }
  312. DEBUG("nextch: EOF in a quote\n");
  313.     }
  314.     return c;
  315. }
  316.  
  317. /*
  318.  * Get the next symbol from the file, skipping blanks.
  319.  * Return 0 if OK, -1 for EOF.
  320.  * Also collapses everything between { and }
  321.  */
  322.  
  323. int
  324. getsym(buf, f)
  325.     char *buf; FILE *f;
  326. {
  327.     register int c;
  328.     int inbrack = 0;
  329.  
  330. DEBUG("in getsym\n");
  331.     c = glastc;
  332.     while ((c > 0) && isspace(c)) {
  333.         c = nextch(f);
  334.     }
  335. DEBUG("getsym: spaces skipped\n");
  336.     if (c < 0) {
  337. DEBUG("EOF read in getsym\n");
  338.         return -1;
  339.     }
  340.     if (c == '{') {
  341.         inbrack = 1;
  342. DEBUG("getsym: in bracket\n");
  343.         while (inbrack) {
  344.             c = nextch(f);
  345.             if (c < 0) {
  346. DEBUG("getsym: EOF seen in bracket loop\n");
  347.                 glastc = c;
  348.                 return c;
  349.             }
  350.             if (c == '{') inbrack++;
  351.             else if (c == '}') inbrack--;
  352.         }
  353.         strcpy(buf, "{}");
  354.         glastc = nextch(f);
  355. DEBUG("getsym: out of in bracket loop\n");
  356.         return 0;
  357.     }
  358.     if (!ISCSYM(c)) {
  359.         *buf++ = c;
  360.         *buf = 0;
  361.         glastc = nextch(f);
  362. DEBUG("getsym: returning special symbol\n");
  363.         return 0;
  364.     }
  365.     while (ISCSYM(c)) {
  366.         *buf++ = c;
  367.         c = nextch(f);
  368.     }
  369.     *buf = 0;
  370.     glastc = c;
  371. DEBUG("getsym: returning word\n");
  372.     return 0;
  373. }
  374.  
  375. /*
  376.  * skipit: skip until a ";" or the end of a function declaration is seen
  377.  */
  378. int skipit(buf, f)
  379.     char *buf;
  380.     FILE *f;
  381. {
  382.     int i;
  383.  
  384.     do {
  385. DEBUG("in skipit loop\n");
  386.         i = getsym(buf, f);
  387.         if (i < 0) return i;
  388.     } while (*buf != ';' && *buf != '{');
  389.  
  390.     return 0;
  391. }
  392.  
  393. /*
  394.  * find most common type specifiers for purpose of ruling them out as
  395.  * parm names
  396.  */
  397.  
  398. int is_type_word(s)
  399. char *s;
  400. {
  401.     static char *typewords[] = {
  402.     "char",        "const",    "double",    "enum",
  403.     "float",    "int",        "long",        "short",
  404.     "signed",    "struct",    "union",    "unsigned",
  405.     "void",        "volatile",    (char *)0
  406.     };
  407.  
  408.     register char **ss;
  409.  
  410.     for (ss = typewords; *ss; ++ss)
  411.     if (strcmp(s, *ss) == 0)
  412.         return 1;
  413.  
  414.     return 0;
  415. }
  416.  
  417.  
  418. /* Ad-hoc macro to recognize parameter name for purposes of removal.
  419.  * Idea is to remove the bulk of easily recognized parm names without
  420.  * losing too many type specifiers. (sg)
  421.  */
  422. #define IS_PARM_NAME(w) \
  423.     (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \
  424.     (!(w)->next || *(w)->next->string == ',' || \
  425.      *(w)->next->string == '['))
  426.  
  427.  
  428. /*
  429.  * given a list representing a type and a variable name, extract just
  430.  * the base type, e.g. "struct word *x" would yield "struct word"
  431.  */
  432.  
  433. Word *typelist(p)
  434.     Word *p;
  435. {
  436.     Word *w, *r;
  437.  
  438.     r = w = word_alloc("");
  439.     while (p && p->next) {
  440. /* handle int *x --> int */
  441.         if (p->string[0] && !ISCSYM(p->string[0]))
  442.             break;
  443. /* handle int x[] --> int */
  444.         if (p->next->string[0] == '[')
  445.             break;
  446.         w->next = word_alloc(p->string);
  447.         w = w->next;
  448.         p = p->next;
  449.     }
  450.     return r;
  451. }
  452.  
  453. /*
  454.  * Get a parameter list; when this is called the next symbol in line
  455.  * should be the first thing in the list.
  456.  */
  457.  
  458. Word *getparamlist(f)
  459.     FILE *f;
  460. {
  461.     static Word *pname[MAXPARAM]; /* parameter names */
  462.     Word    *tlist,          /* type name */
  463.         *plist;          /* temporary */
  464.     int      np = 0;          /* number of parameters */
  465.     int      typed[MAXPARAM];  /* parameter has been given a type */
  466.     int    tlistdone;      /* finished finding the type name */
  467.     int    sawsomething;
  468.     int      i;
  469.     int    inparen = 0;
  470.     char buf[80];
  471.  
  472. DEBUG("in getparamlist\n");
  473.     for (i = 0; i < MAXPARAM; i++)
  474.         typed[i] = 0;
  475.  
  476.     plist = word_alloc("");
  477.  
  478. /* first, get the stuff inside brackets (if anything) */
  479.  
  480.     sawsomething = 0;    /* gets set nonzero when we see an arg */
  481.     for (;;) {
  482.         if (getsym(buf, f) < 0) return NULL;
  483.         if (*buf == ')' && (--inparen < 0)) {
  484.             if (sawsomething) {    /* if we've seen an arg */
  485.                 pname[np] = plist;
  486.                 plist = word_alloc("");
  487.                 np++;
  488.             }
  489.             break;
  490.         }
  491.         if (*buf == ';') {    /* something weird */
  492.             return ABORTED;
  493.         }
  494.         sawsomething = 1;    /* there's something in the arg. list */
  495.         if (*buf == ',' && inparen == 0) {
  496.             pname[np] = plist;
  497.             plist = word_alloc("");
  498.             np++;
  499.         }
  500.         else {
  501.             addword(plist, buf);
  502.             if (*buf == '(') inparen++;
  503.         }
  504.     }
  505.  
  506. /* next, get the declarations after the function header */
  507.  
  508.     inparen = 0;
  509.  
  510.     tlist = word_alloc("");
  511.     plist = word_alloc("");
  512.     tlistdone = 0;
  513.     sawsomething = 0;
  514.     for(;;) {
  515.         if (getsym(buf, f) < 0) return NULL;
  516.  
  517. /* handle a list like "int x,y,z" */
  518.         if (*buf == ',' && !inparen) {
  519.             if (!sawsomething)
  520.                 return NULL;
  521.             for (i = 0; i < np; i++) {
  522.                 if (!typed[i] && foundin(plist, pname[i])) {
  523.                     typed[i] = 1;
  524.                     word_free(pname[i]);
  525.                     pname[i] = word_append(tlist, plist);
  526.                 /* promote types */
  527.                     typefixhack(pname[i]);
  528.                     break;
  529.                 }
  530.             }
  531.             if (!tlistdone) {
  532.                 tlist = typelist(plist);
  533.                 tlistdone = 1;
  534.             }
  535.             word_free(plist);
  536.             plist = word_alloc("");
  537.         }
  538. /* handle the end of a list */
  539.         else if (*buf == ';') {
  540.             if (!sawsomething)
  541.                 return ABORTED;
  542.             for (i = 0; i < np; i++) {
  543.                 if (!typed[i] && foundin(plist, pname[i])) {
  544.                     typed[i] = 1;
  545.                     word_free(pname[i]);
  546.                     pname[i] = word_append(tlist, plist);
  547.                     typefixhack(pname[i]);
  548.                     break;
  549.                 }
  550.             }
  551.             tlistdone = 0;
  552.             word_free(tlist); word_free(plist);
  553.             tlist = word_alloc("");
  554.             plist = word_alloc("");
  555.         }
  556. /* handle the  beginning of the function */
  557.         else if (!strcmp(buf, "{}")) break;
  558. /* otherwise, throw the word into the list (except for "register") */
  559.         else if (strcmp(buf, "register")) {
  560.             sawsomething = 1;
  561.             addword(plist, buf);
  562.             if (*buf == '(') inparen++;
  563.             if (*buf == ')') inparen--;
  564.         }
  565.     }
  566.  
  567. /* Now take the info we have and build a prototype list */
  568.  
  569. /* empty parameter list means "void" */
  570.     if (np == 0)
  571.         return word_alloc("void");
  572.  
  573.     plist = tlist = word_alloc("");
  574.     for (i = 0; i < np; i++) {
  575.  
  576. /* If no type provided, make it an "int" */
  577.         if ( !(pname[i]->next) ||
  578.        (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  579.             addword(tlist, "int");
  580.         }
  581.         while (tlist->next) tlist = tlist->next;
  582.         tlist->next = pname[i];
  583.         if (i < np - 1)
  584.             addword(tlist, ",");
  585.     }
  586.     return plist;
  587. }
  588.  
  589. /*
  590.  * emit a function declaration. The attributes and name of the function
  591.  * are in wlist; the parameters are in plist.
  592.  */
  593.  
  594. void emit(wlist, plist, startline)
  595.     Word *wlist, *plist;
  596.     long  startline;
  597. {
  598.     Word *w;
  599.     int count = 0;
  600.     int needspace = 0;
  601.     int isstatic = 0;
  602.  
  603. DEBUG("emit called\n");
  604.     if (donum)
  605.         printf("/*%8ld */ ", startline);
  606.  
  607.     for (w = wlist; w; w = w->next) {
  608.         if (w->string[0]) {
  609.             count ++;
  610.             if (!strcmp(w->string, "static"))
  611.                 isstatic = 1;
  612.         }
  613.     }
  614.  
  615. /* if the -e flag was given, and it's not a static function, print "extern" */
  616.  
  617.     if (print_extern && !isstatic) {
  618.         printf("extern ");
  619.     }
  620.  
  621.     if (count < 2) {
  622.         printf("int");
  623.         needspace = 1;
  624.     }
  625.  
  626.     for (w = wlist; w; w = w->next) {
  627.         if (needspace)
  628.             putchar(' ');
  629.         printf("%s", w->string);
  630.         needspace = ISCSYM(w->string[0]);
  631.     }
  632.     if (use_macro)
  633.         printf(" %s((", macro_name);
  634.     else
  635.         putchar('(');
  636.     needspace = 0;
  637.     for (w = plist; w; w = w->next) {
  638.         if (no_parm_names && IS_PARM_NAME(w))
  639.             continue;
  640.         if (w->string[0] == ',')
  641.             needspace = 1;
  642.         else if (w->string[0] == '[')
  643.             needspace = 0;
  644.         else
  645.         {
  646.             if (needspace)
  647.                 putchar(' ');
  648.             needspace = ISCSYM(w->string[0]);
  649.         }
  650.         printf("%s", w->string);
  651.     }
  652.     if (use_macro)
  653.         printf("));\n");
  654.     else
  655.         printf(");\n");
  656. }
  657.  
  658. /*
  659.  * get all the function declarations
  660.  */
  661.  
  662. void getdecl(f)
  663.     FILE *f;
  664. {
  665.     Word *plist, *wlist = NULL;
  666.     char buf[80];
  667.     int sawsomething;
  668.     long startline;        /* line where declaration started */
  669.     int oktoprint;
  670. again:
  671.     word_free(wlist);
  672.     wlist = word_alloc("");
  673.     sawsomething = 0;
  674.     oktoprint = 1;
  675.  
  676.     for(;;) {
  677. DEBUG("main getdecl loop\n");
  678.         if (getsym(buf,f) < 0) {
  679. DEBUG("EOF in getdecl loop\n");
  680.              return;
  681.         }
  682. /* try to guess when a declaration is not an external function definition */
  683.         if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
  684.             !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
  685.             !strcmp(buf, "extern")) {
  686.             skipit(buf, f);
  687.             goto again;
  688.         }
  689.         if (!dostatic && !strcmp(buf, "static")) {
  690.             oktoprint = 0;
  691.         }
  692. /* for the benefit of compilers that allow "inline" declarations */
  693.         if (!strcmp(buf, "inline") && !sawsomething)
  694.             continue;
  695.         if (!strcmp(buf, ";")) goto again;
  696.  
  697. /* A left parenthesis *might* indicate a function definition */
  698.         if (!strcmp(buf, "(")) {
  699.             startline = linenum;
  700.             if (!sawsomething || !(plist = getparamlist(f))) {
  701.                 skipit(buf, f);
  702.                 goto again;
  703.             }
  704.             if (plist == ABORTED)
  705.                 goto again;
  706.  
  707. /* It seems to have been what we wanted */
  708.             if (oktoprint)
  709.                 emit(wlist, plist, startline);
  710.             word_free(plist);
  711.             goto again;
  712.         }
  713.         addword(wlist, buf);
  714.         sawsomething = 1;
  715.     }
  716. }
  717.  
  718. void
  719. main(argc, argv)
  720. int argc; char **argv;
  721. {
  722.     FILE *f;
  723.     char *t, *iobuf;
  724.     extern void Usage();
  725.  
  726.     if (argv[0] && argv[0][0])
  727.         ourname = argv[0];
  728.     else
  729.         ourname = "mkptypes";
  730.  
  731.     argv++; argc--;
  732.  
  733.     if (argc < 0)        /* strange -- no args at all */
  734.         Usage();
  735.         else if ( argc == 0 && isatty(fileno(stdin)) )
  736.                 Usage();
  737.  
  738.     iobuf = malloc(NEWBUFSIZ);
  739.     while (*argv && **argv == '-') {
  740.         t = *argv++; --argc; t++;
  741.         while (*t) {
  742.             if (*t == 'e')
  743.                 print_extern = 1;
  744.             else if (*t == 'n')
  745.                 donum = 1;
  746.             else if (*t == 'p') {
  747.                 t = *argv++; --argc;
  748.                 if (!t)
  749.                     Usage();
  750.                 use_macro = 1;
  751.                 macro_name = t;
  752.                 break;
  753.             }
  754.             else if (*t == 's')
  755.                 dostatic = 1;
  756.             else if (*t == 'x')
  757.                 /* no parm names, only types (sg) */
  758.                 no_parm_names = 1;
  759.             else if (*t == 'z')
  760.                 define_macro = 0;
  761.             else if (*t == 'A')
  762.                 use_macro = 0;
  763.             else
  764.                 Usage();
  765.             t++;
  766.         }
  767.     }
  768.  
  769.     if (use_macro && define_macro) {
  770.         printf("#if defined(__STDC__) || defined(__cplusplus)\n");
  771.         printf("# define %s(s) s\n", macro_name);
  772.         printf("#else\n");
  773.         printf("# define %s(s) ()\n", macro_name);
  774.         printf("#endif\n\n");
  775.     }
  776.     if (argc == 0)
  777.         getdecl(stdin);
  778.     else
  779.         while (argc > 0 && *argv) {
  780. DEBUG("trying a new file\n");
  781.             if (!(f = fopen(*argv, "r"))) {
  782.                 perror(*argv);
  783.                 exit(EXIT_FAILURE);
  784.             }
  785.             if (iobuf)
  786.                 setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
  787.  
  788.             printf("\n/* %s */\n", *argv);
  789.             linenum = 1;
  790.             newline_seen = 1;
  791.             glastc = ' ';
  792. DEBUG("calling getdecl\n");
  793.             getdecl(f);
  794. DEBUG("back from getdecl\n");
  795.             argc--; argv++;
  796.             fclose(f);
  797. DEBUG("back from fclose\n");
  798.         }
  799.     if (use_macro && define_macro) {
  800.         printf("\n#undef %s\n", macro_name);    /* clean up namespace */
  801.     }
  802.     exit(EXIT_SUCCESS);
  803. }
  804.  
  805.  
  806. void Usage()
  807. {
  808.     fprintf(stderr,
  809.        "\nUsage: %s [-e][-n][-p sym][-s][-x][-z][-A][files ...]\n\n", ourname);
  810.     fputs("   -e      put an explicit \"extern\" keyword in declarations\n",
  811.        stderr);
  812.     fputs("   -n      put line numbers of declarations as comments\n",stderr);
  813.     fputs("   -p nm   use \"nm\" as the prototype macro (default \"_P\")\n",
  814.        stderr);
  815.     fputs("   -s      include declarations for static functions\n", stderr);
  816.     fputs("   -x      omit parameter names in prototypes\n", stderr);
  817.     fputs("   -z      omit prototype macro definition\n", stderr);
  818.     fputs("   -A      omit prototype macro, header files are strict ANSI\n",
  819.        stderr);
  820.     exit(EXIT_FAILURE);
  821. }
  822.