home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / C / MKPROTO / MKPROTO.C < prev    next >
C/C++ Source or Header  |  1991-01-23  |  18KB  |  764 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. /****************************************************************************\
  7. *                                                                              *
  8. * Revision history:                                                             *
  9. *                                                                              *
  10. *     910122    Bruce A. Mallett                                                 *
  11. *         Changed getdecl() so that the scanning for a routine definition         *
  12. *         would not trigger on one in which the symbol prior to the opening     *
  13. *         parenthasis was a non-C symbol.  Added IsCSymbol() to help             *
  14. *         accomplish this.                                                     *
  15. *                                                                              *
  16. *         Changed getparamlist() so that it does not claim to have seen         *
  17. *         something valid if the function parameters are followed by a         *
  18. *         parenthasised list.  Example: int foo( p1,p2 ) (list1,list2);         *
  19. *                                                                              *
  20. *     901109    Bruce A. Mallett                                                 *
  21. *         Changed nextch() so that newline_seen remains TRUE until the         *
  22. *         next non-whitespace character is encountered.  The prior version     *
  23. *         always set it according to the current character being a newline.     *
  24. *         This messed up newer C code that allows indented C preprocessor         *
  25. *         statements (where the "#" does not occur in column 1).                 *
  26. *                                                                              *
  27. *     900131    Bruce A. Mallett                                                 *
  28. *         Fixed getparamlist() so that it does not erroneously think that         *
  29. *         forward references such as:                                             *
  30. *             BOOL  (*rtn_ptr)();                                                 *
  31. *         are function definitions of the form:                                 *
  32. *             int BOOL( int *rtn_ptr );                                         *
  33. *                                                                              *
  34. *         This fix involved the section of code which scans for parameter         *
  35. *         definitions following the parameter list.  I simply made the         *
  36. *         setting of "sawsomething" dependent on finding a valid C symbol         *
  37. *         (by testing with the ISCSYM() macro).                                 *
  38. *                                                                              *
  39. \****************************************************************************/
  40.  
  41. #include <stddef.h>
  42. #include <stdlib.h>
  43.  
  44. #define EXIT_SUCCESS  0
  45. #define EXIT_FAILURE  1
  46.  
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include <string.h>
  50. #include <malloc.h>
  51.  
  52. /*#define DEBUG(s) (fputs(s, stderr)) /* */
  53. #define DEBUG(s) /* */
  54.  
  55. #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  56. #define ABORTED ( (Word *) -1 )
  57. #define MAXPARAM 20         /* max. number of parameters to a function */
  58. #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  59.  
  60. int inquote = 0;        /* in a quote?? */
  61. int newline_seen = 1;        /* are we at the start of a line */
  62. long linenum  = 1L;        /* line number in current file */
  63. int dostatic = 0;        /* do static functions? */
  64. int dotypefix= 1;        /* Do typefix hack */
  65. int donum    = 0;        /* print line numbers? */
  66. int dohead   = 1;        /* do file headers? */
  67. int docond   = 1;        /* conditionalize for non-ANSI compilers? */
  68. int glastc   = ' ';        /* last char. seen by getsym() */
  69.  
  70. typedef struct word {
  71.     struct word *next;
  72.     char   string[1];
  73. } Word;
  74.  
  75. #include "proto/mkproto.h"
  76.  
  77. /*
  78.  * Routines for manipulating lists of words.
  79.  */
  80.  
  81. Word *word_alloc(s)
  82.     char *s;
  83. {
  84.     Word *w;
  85.  
  86.     w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); /* ++jrb */
  87.     strcpy(w->string, s);
  88.     w->next = NULL;
  89.     return w;
  90. }
  91.  
  92. void word_free(w)
  93.     Word *w;
  94. {
  95.     Word *oldw;
  96.     while (w) {
  97.         oldw = w;
  98.         w = w->next;
  99.         free(oldw);
  100.     }
  101. }
  102.  
  103. /* return the length of a list; empty words are not counted */
  104. int
  105. List_len(w)
  106.     Word *w;
  107. {
  108.     int count = 0;
  109.  
  110.     while (w) {
  111.         if (*w->string) count++;
  112.         w = w->next;
  113.     }
  114.     return count;
  115. }
  116.  
  117. /* Append two lists, and return the result */
  118.  
  119. Word *word_append(w1, w2)
  120.     Word *w1, *w2;
  121. {
  122.     Word *r, *w;
  123.  
  124.     r = w = word_alloc("");
  125.  
  126.     while (w1) {
  127.         w->next = word_alloc(w1->string);
  128.         w = w->next;
  129.         w1 = w1->next;
  130.     }
  131.     while (w2) {
  132.         w->next = word_alloc(w2->string);
  133.         w = w->next;
  134.         w2 = w2->next;
  135.     }
  136.  
  137.     return r;
  138. }
  139.     
  140. /* see if the last entry in w2 is in w1 */
  141.  
  142. int
  143. foundin(w1, w2)
  144.     Word *w1, *w2;
  145. {
  146.     while (w2->next)
  147.         w2 = w2->next;
  148.  
  149.     while (w1) {
  150.         if (!strcmp(w1->string, w2->string))
  151.             return 1;
  152.         w1 = w1->next;
  153.     }
  154.     return 0;
  155. }
  156.  
  157. /* add the string s to the given list of words */
  158.  
  159. Word * addword(w, s)
  160.     Word *w; char *s;
  161. {
  162.     while (w->next) w = w->next;
  163.     w->next = word_alloc(s);
  164.  
  165.     return ( w->next );
  166. }
  167.  
  168. /* given a list representing a type and a variable name, extract just
  169.  * the base type, e.g. "struct word *x" would yield "struct word"
  170.  */
  171.  
  172. Word *typelist(p)
  173.     Word *p;
  174. {
  175.     Word *w, *r;
  176.  
  177.     r = w = word_alloc("");
  178.     while (p && p->next) {
  179.         if (p->string[0] && !ISCSYM(p->string[0]))
  180.             break;
  181.         w->next = word_alloc(p->string);
  182.         w = w->next;
  183.         p = p->next;
  184.     }
  185.     return r;
  186. }
  187.  
  188. /* typefixhack: promote formal parameters of type "char", "unsigned char",
  189.    "short", or "unsigned short" to "int".
  190. */
  191.  
  192. void typefixhack(w)
  193.     Word *w;
  194. {
  195.     Word *oldw = 0;
  196.  
  197.     if ( dotypefix ) {
  198.         while (w) {
  199.             if (*w->string) {
  200.                 if ( (!strcmp(w->string, "char") ||
  201.                       !strcmp(w->string, "short") )
  202.                     && (List_len(w->next) < 2) )
  203.                 {
  204.                     if (oldw && !strcmp(oldw->string, "unsigned")) {
  205.                         oldw->next = w->next;
  206.                         free(w);
  207.                         w = oldw;
  208.                     }
  209.                     strcpy(w->string, "int");
  210.                 }
  211.             }
  212.             w = w->next;
  213.         }
  214.     }
  215. }
  216.  
  217. /* read a character: if it's a newline, increment the line count */
  218.  
  219. #ifdef __GNUC__    /* ++jrb */
  220. inline
  221. #endif
  222. int ngetc(f)
  223.     FILE *f;
  224. {
  225.     int c;
  226.  
  227.     c = getc(f);
  228.     if (c == '\n') linenum++;
  229.  
  230.     return c;
  231. }
  232.  
  233. /* read the next character from the file. If the character is '\' then
  234.  * read and skip the next character. Any comment sequence is converted
  235.  * to a blank.
  236.  */
  237.  
  238. int fnextch(f)
  239.     FILE *f;
  240. {
  241.     int c, lastc, incomment;
  242.  
  243.     c = ngetc(f);
  244.     while (c == '\\') {
  245. DEBUG("fnextch: in backslash loop\n");
  246.         c = ngetc(f);    /* skip a character */
  247.         c = ngetc(f);
  248.     }
  249.     if (c == '/' && !inquote) {
  250.         c = ngetc(f);
  251.         if (c == '*') {
  252.             incomment = 1;
  253.             c = ' ';
  254. DEBUG("fnextch: comment seen\n");
  255.             while (incomment) {
  256.                 lastc = c;
  257.                 c = ngetc(f);
  258.                 if (lastc == '*' && c == '/')
  259.                     incomment = 0;
  260.                 else if (c < 0)
  261.                     return c;
  262.             }
  263.             return fnextch(f);
  264.         }
  265.         else {
  266.             if (c == '\n') linenum--;
  267.             ungetc(c, f);
  268.             return '/';
  269.         }
  270.     }
  271.     return c;
  272. }
  273.  
  274.  
  275. /* Get the next "interesting" character. Comments are skipped, and strings
  276.  * are converted to "0". Also, if a line starts with "#" it is skipped.
  277.  */
  278.  
  279. int nextch(f)
  280.     FILE *f;
  281. {
  282.     int c;
  283.  
  284.     c = fnextch(f);
  285.     if (newline_seen && c == '#') {
  286.         do {
  287.             c = fnextch(f);
  288.         } while (c >= 0 && c != '\n');
  289.         if (c < 0)
  290.             return c;
  291.     }
  292.  
  293.     /************************************************************************\
  294.     *                                                                          *
  295.     * BAM:    Changed newline_seen so that it can only get reset on the first     *
  296.     *         non-whitespace character after a newline.                         *
  297.     *                                                                          *
  298.     \************************************************************************/
  299.  
  300.     newline_seen = (c == '\n') || (newline_seen && isspace( c ));
  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++ = (char)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++ = (char)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.  * Get a parameter list; when this is called the next symbol in line
  395.  * should be the first thing in the list.
  396.  */
  397.  
  398. Word *getparamlist(f)
  399.     FILE *f;
  400. {
  401.     static Word *pname[MAXPARAM]; /* parameter names */
  402.     Word    *tlist,        /* type name */
  403.         *plist;        /* temporary */
  404.     int      np = 0;        /* number of parameters */
  405.     int      typed[MAXPARAM];  /* parameter has been given a type */
  406.     int    tlistdone;    /* finished finding the type name */
  407.     int    saw_start_of_function;
  408.     int    sawsomething;
  409.     int      i;
  410.     int    inparen = 0;
  411.     char buf[80];
  412.  
  413. DEBUG("in getparamlist\n");
  414.     for (i = 0; i < MAXPARAM; i++)
  415.         typed[i] = 0;
  416.  
  417.     plist = word_alloc("");
  418.  
  419. /* first, get the stuff inside brackets (if anything) */
  420.  
  421.     sawsomething = 0;    /* gets set nonzero when we see an arg */
  422.     for (;;) {
  423.         if (getsym(buf, f) < 0) return NULL;
  424.         if (*buf == ')' && (--inparen < 0)) {
  425.             if (sawsomething) {    /* if we've seen an arg */
  426.                 pname[np] = plist;
  427.                 plist = word_alloc("");
  428.                 np++;
  429.             }
  430.             break;
  431.         }
  432.         if (*buf == ';') {    /* something weird */
  433.             return ABORTED;
  434.         }
  435.         sawsomething = 1;    /* there's something in the arg. list */
  436.         if (*buf == ',' && inparen == 0) {
  437.             pname[np] = plist;
  438.             plist = word_alloc("");
  439.             np++;
  440.         }
  441.         else {
  442.             addword(plist, buf);
  443.             if (*buf == '(') inparen++;
  444.         }
  445.     }
  446.  
  447. /* next, get the declarations after the function header */
  448.  
  449.     inparen = 0;
  450.  
  451.     tlist = word_alloc("");
  452.     plist = word_alloc("");
  453.     tlistdone = 0;
  454.     saw_start_of_function = 0;            /* Nope, not yet! */
  455.     sawsomething = 0;
  456.     for(;;) {
  457.         if (getsym(buf, f) < 0) return NULL;
  458.  
  459. /* handle a list like "int x,y,z" */
  460.         if (*buf == ',' && !inparen) {
  461.             if (!sawsomething)
  462.                 return NULL;
  463.             for (i = 0; i < np; i++) {
  464.                 if (!typed[i] && foundin(plist, pname[i])) {
  465.                     typed[i] = 1;
  466.                     word_free(pname[i]);
  467.                     pname[i] = word_append(tlist, plist);
  468.                 /* promote types */
  469.                     typefixhack(pname[i]);
  470.                     break;
  471.                 }
  472.             }
  473.             if (!tlistdone) {
  474.                 tlist = typelist(plist);
  475.                 tlistdone = 1;
  476.             }
  477.             word_free(plist);
  478.             plist = word_alloc("");
  479.         }
  480. /* handle the end of a list */
  481.         else if (*buf == ';') {
  482.             if (!sawsomething)
  483.                 return ABORTED;
  484.             for (i = 0; i < np; i++) {
  485.                 if (!typed[i] && foundin(plist, pname[i])) {
  486.                     typed[i] = 1;
  487.                     word_free(pname[i]);
  488.                     pname[i] = word_append(tlist, plist);
  489.                     typefixhack(pname[i]);
  490.                     break;
  491.                 }
  492.             }
  493.             tlistdone = 0;
  494.             word_free(tlist); word_free(plist);
  495.             tlist = word_alloc("");
  496.             plist = word_alloc("");
  497.         }
  498. /* handle the  beginning of the function */
  499.         else if (!strcmp(buf, "{}")) {
  500.             saw_start_of_function = 1;    /* We have the start of function */
  501.             break;
  502.         }
  503.         else if ( *buf == '=' )
  504.             return ABORTED;
  505. /* otherwise, throw the word into the list (except for "register") */
  506.         else if (strcmp(buf, "register")) {
  507.             if ( ISCSYM(*buf) && (inparen == 0) )
  508.                 sawsomething = 1;
  509.  
  510.             addword(plist, buf);
  511.             if (*buf == '(') inparen++;
  512.             if (*buf == ')') inparen--;
  513.         }
  514.     }
  515.  
  516.     if ( !saw_start_of_function )        /* We must see start of function */
  517.         return ABORTED;
  518.  
  519. /* Now take the info we have and build a prototype list */
  520.  
  521. /* empty parameter list means "void" */
  522.     if (np == 0)
  523.         return word_alloc("void");
  524.  
  525.     plist = tlist = word_alloc("");
  526.     for (i = 0; i < np; i++) {
  527.  
  528. /* If no type provided, make it an "int" */
  529.         if ( !(pname[i]->next) ||
  530.        (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  531.             addword(tlist, "int");
  532.         }
  533.         while (tlist->next) tlist = tlist->next;
  534.         tlist->next = pname[i];
  535.         if (i < np - 1)
  536.             addword(tlist, ", ");
  537.     }
  538.     return plist;
  539. }
  540.  
  541. /*
  542.  * emit a function declaration. The attributes and name of the function
  543.  * are in wlist; the parameters are in plist.
  544.  */
  545. void emit(wlist, plist, startline)
  546.     Word *wlist, *plist;
  547.     long  startline;
  548. {
  549.     Word *w;
  550.     int count = 0;
  551.  
  552. DEBUG("emit called\n");
  553.     if (donum)
  554.         printf("/*%8ld */ ", startline);
  555.  
  556.     for (w = wlist; w; w = w->next) {
  557.         if (w->string[0])
  558.             count ++;
  559.     }
  560.  
  561.     if (count < 2)
  562.         printf("int ");
  563.  
  564.     for (w = wlist; w; w = w->next) {
  565.         printf("%s", w->string);
  566.         if (ISCSYM(w->string[0]))
  567.             printf(" ");
  568.     }
  569.     if (docond)
  570.         printf("P((");
  571.     else
  572.         printf("( ");
  573.     for (w = plist; w; w = w->next) {
  574.         printf("%s", w->string);
  575.         if (ISCSYM(w->string[0]))
  576.             printf(" ");
  577.     }
  578.     if (docond)
  579.         printf("));\n");
  580.     else
  581.         printf(");\n");
  582. }
  583.  
  584. /****************************************************************************\
  585. *                                                                              *
  586. * Template:        <^r^>                                                         *
  587. *                                                                              *
  588. * Name:            IsCSymbol( str )                                             *
  589. *                                                                              *
  590. * Description:    This routine returns a TRUE/FALSE indication as to whether     *
  591. *                 the passed string is a valid C symbol or not.                 *
  592. *                                                                              *
  593. * Parameters:    str        -    Pointer to the ASCIZ string to be tested         *
  594. *                                                                              *
  595. * Returns:        (int)    0    If not a valid C symbol                             *
  596. *                         Nz    If a valid C symbol                                 *
  597. *                                                                              *
  598. * Notes:                                                                     *
  599. *                                                                              *
  600. * Side effects:                                                                 *
  601. *                                                                              *
  602. * Revision History:                                                             *
  603. *   Vers   Date         Author                                                 *
  604. *    0.0   22-Jan-1991    Bruce A. Mallett                                     *
  605. *         Created Module.                                                         *
  606. *                                                                              *
  607. \****************************************************************************/
  608.  
  609. int    IsCSymbol( char * str )
  610.  
  611. {
  612.     if ( !str || !(*str) )
  613.         return ( 0 );                    /* If nothing passed */
  614.  
  615.     do
  616.     {
  617.         if ( !ISCSYM(*str) )            /* If not valid */
  618.             return ( 0 );
  619.     } while ( *++str );
  620.  
  621.     return ( 1 );                        /* Must be valid! */
  622.  
  623. }    /* IsCSymbol() */
  624.  
  625. /*
  626.  * get all the function declarations
  627.  */
  628.  
  629. void getdecl(f)
  630.     FILE *f;
  631. {
  632.     Word *plist, *wlist = NULL;
  633.     Word *LastWord = NULL;
  634.     char buf[80];
  635.     int sawsomething;
  636.     long startline;        /* line where declaration started */
  637.     int oktoprint;
  638. again:
  639.     word_free(wlist);
  640.     wlist = word_alloc("");
  641.     sawsomething = 0;
  642.     oktoprint = 1;
  643.  
  644.     for(;;) {
  645. DEBUG("main getdecl loop\n");
  646.         if (getsym(buf,f) < 0) {
  647. DEBUG("EOF in getdecl loop\n");
  648.              return;
  649.         }
  650. /* try to guess when a declaration is not an external function definition */
  651.         if ( (buf[0] == '.') ||
  652.              (buf[0] == '=') ||
  653.              !strcmp(buf, "{}") ||
  654.              !strcmp(buf, "typedef") ||
  655.              !strcmp(buf, "extern"))
  656.         {
  657.             skipit(buf, f);
  658.             goto again;
  659.         }
  660.         if (!dostatic && !strcmp(buf, "static")) {
  661.             oktoprint = 0;
  662.         }
  663. /* for the benefit of compilers that allow "inline" declarations */
  664.         if (!strcmp(buf, "inline") && !sawsomething)
  665.             continue;
  666.         if ( buf[0] == ';' ) goto again;
  667.  
  668. /* A left parenthesis *might* indicate a function definition */
  669.         if ( (buf[0] == '(') && IsCSymbol(LastWord->string) ) {
  670.             startline = linenum;
  671.             if (!sawsomething || !(plist = getparamlist(f))) {
  672.                 skipit(buf, f);
  673.                 goto again;
  674.             }
  675.             if (plist == ABORTED)
  676.                 goto again;
  677.  
  678. /* It seems to have been what we wanted */
  679.             if (oktoprint)
  680.                 emit(wlist, plist, startline);
  681.             word_free(plist);
  682.             goto again;
  683.         }
  684.  
  685.         LastWord = addword(wlist, buf);
  686.         sawsomething = 1;
  687.     }
  688. }
  689.  
  690. void
  691. cdecl main(argc, argv)
  692. int argc; char **argv;
  693. {
  694.     FILE *f;
  695.     char *t, *iobuf;
  696.     extern void Usage();
  697.  
  698.     argv++; argc--;
  699.  
  700.     iobuf = malloc(NEWBUFSIZ);
  701.     while (*argv && **argv == '-') {
  702.         t = *argv++; --argc; t++;
  703.         while (*t) {
  704.             if (*t == 's')
  705.                 dostatic = 1;
  706.             else if (*t == 'n')
  707.                 donum = 1;
  708.             else if (*t == 'p')
  709.                 docond = 0;
  710.             else if (*t == 't')
  711.                 dotypefix = 0;
  712.             else
  713.                 Usage();
  714.             t++;
  715.         }
  716.     }
  717.  
  718.     if (docond) {
  719.         printf("#ifdef __STDC__\n");
  720.         printf("# define\tP(s) s\n");
  721.         printf("#else\n");
  722.         printf("# define P(s) ()\n");
  723.         printf("#endif\n\n");
  724.     }
  725.     if (argc == 0)
  726.         getdecl(stdin);
  727.     else
  728.         while (argc > 0 && *argv) {
  729. DEBUG("trying a new file\n");
  730.             if (!(f = fopen(*argv, "r"))) {
  731.                 perror(*argv);
  732.                 exit(EXIT_FAILURE);
  733.             }
  734.             if (iobuf)
  735.                 setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
  736.             if (dohead)
  737.                 printf("\n/* %s */\n", *argv);
  738.             linenum = 1;
  739.             newline_seen = 1;
  740.             glastc = ' ';
  741. DEBUG("calling getdecl\n");
  742.             getdecl(f);
  743. DEBUG("back from getdecl\n");
  744.             argc--; argv++;
  745.             fclose(f);
  746. DEBUG("back from fclose\n");
  747.         }
  748.     if (docond) {
  749.         printf("\n#undef P\n");    /* clean up namespace */
  750.     }
  751.     exit(EXIT_SUCCESS);
  752. }
  753.  
  754.  
  755. void Usage()
  756. {
  757.     fputs("Usage: mkproto [-n][-s][-p][-t][files ...]\n",stderr);
  758.     fputs("   -n: put line numbers of declarations as comments\n",stderr);
  759.     fputs("   -p: don't make header files readable by non-ANSI compilers\n", stderr);
  760.     fputs("   -s: include declarations for static functions\n", stderr);
  761.     fputs("   -t: don't promote \"char\" types to \"int\"\n", stderr);
  762.     exit(EXIT_FAILURE);
  763. }
  764.