home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / prpp / part01 / prpp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-21  |  8.7 KB  |  491 lines

  1. /*
  2.  * Prototype Pre-Processor, by Mike Gleason, NCEMRSoft.
  3.  * Version 1.0 / February 8, 1993.
  4.  */
  5.  
  6. #define VERSION "1.0"
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <stdlib.h>
  12.  
  13. /* Definitions. */
  14. #define CPP_LINE                '#'
  15. #define SEMICOLON                ';'
  16. #define LEFTBRACKET                '{'
  17. #define RIGHTBRACKET            '}'
  18. #define LEFTPAREN                '('
  19. #define RIGHTPAREN                ')'
  20. #define SLASH                    '/'
  21. #define BACKSLASH                '\\'
  22. #define ASTERISK                '*'
  23. #define COMMA                    ','
  24. #define CIDENTCHAR(c)            (isalnum(c) || ((c) == '_'))
  25. #define CIDENTCHAR1(c)            (isalpha(c) || ((c) == '_'))
  26. #define NEXTC                    (cbp->chr)
  27. #define SKIPCHAR                cbp->chr = getc(fp); cbp = (cbp->next)
  28. #define EQ(a,b)                    (strcmp((a), (b)) == 0)
  29. #define Strncpy(a,b)            strncpy((a), (b), sizeof(a) - 1)
  30. #define Strncat(a,b)            strncat((a), (b), sizeof(a) - 1)
  31. #define wt_unknown                0
  32. #define wt_extern                1
  33. #define wt_static                2
  34. #define wt_volatile                3
  35. #define wt_const                4
  36. #define wt_unsigned                5
  37. #define wt_signed                6
  38. #define wt_enum                    7
  39. #define wt_union                8
  40. #define wt_struct                9
  41. #define wt_typedef                10
  42. #ifndef HEADERDIR
  43. #    define HEADERDIR            "/usr/include"
  44. #endif
  45.  
  46. /* Types. */
  47. struct ch {
  48.     int chr;
  49.     struct ch *next;
  50. };
  51.  
  52. /* Globals. */
  53. FILE                        *fp;
  54. char                        word[128];
  55.  
  56. /* For now, pgrepoutput isn't very helpful.  I was going to support this
  57.  * weird format which prints the function name first so you could alphabetize
  58.  * the list (for fast searches), but fgrep is plenty fast for me.
  59.  */
  60.  
  61. int                            pgrepoutput = 0;
  62. int                            is_sue;
  63. int                            is_ptr;
  64. int                            is_volatile;
  65. int                            is_signed;
  66. int                            curline;
  67. int                            curchar;
  68. int                            startline;
  69. char                        typename[64];
  70. char                        funcname[64];
  71. char                        funcargs[256];
  72. char                        filename[256];
  73.  
  74. /* Keep a 4-byte look ahead buffer. */
  75. struct ch cbuf[4] = {
  76.     { EOF, &cbuf[1] },
  77.     { EOF, &cbuf[2] },
  78.     { EOF, &cbuf[3] },
  79.     { EOF, &cbuf[0] }
  80. }, *cbp;
  81.  
  82.  
  83.  
  84.  
  85. static void InitGetc(void)
  86. {
  87.     int i;
  88.     
  89.     cbp = cbuf;
  90.     curline = 1;
  91.     curchar = 0;
  92.     for (i=0; i<4; i++)
  93.         cbuf[i].chr = getc(fp);
  94. }    /* InitGetc */
  95.  
  96.  
  97.  
  98.  
  99. static int Getc(void)
  100. {
  101.     int c;
  102.     c = cbp->chr;
  103.     if (c == '\n') {
  104.         curchar = 0;
  105.         curline++;
  106.     } else
  107.         curchar++;
  108.     SKIPCHAR;
  109.     return c;
  110. }    /* Getc */
  111.  
  112.  
  113.  
  114.  
  115. static int Skipline(void)
  116. {
  117.     int c;
  118.  
  119.     while(1) {
  120.         c = Getc();
  121.         if (c == EOF) return (EOF);
  122.         if (c == BACKSLASH)
  123.             (void) Getc();
  124.         if (c == '\n') return ('\n');
  125.     }
  126. }    /* Skipline */
  127.  
  128.  
  129.  
  130.  
  131. static int Wordcmp(void)
  132. {
  133.     char *cp = word;
  134.     int wt = wt_unknown;
  135.  
  136.     switch(*cp++) {
  137.         case 'e':    /* extern? */
  138.             if (EQ(cp, "xtern"))
  139.                 wt = wt_extern;
  140.             else if (EQ(cp, "num"))
  141.                 wt = wt_enum;
  142.             break;
  143.         case 't':
  144.             if (EQ(cp, "ypedef"))
  145.                 wt = wt_typedef;
  146.             break;
  147.         case 'v':
  148.             if (EQ(cp, "olatile"))
  149.                 wt = wt_volatile;
  150.             break;
  151.         case 'u':
  152.             if (EQ(cp, "nsigned"))
  153.                 wt = wt_unsigned;
  154.             else if (EQ(cp, "nion"))
  155.                 wt = wt_union;
  156.             break;
  157.         case 's':
  158.             if (*cp++ == 't') {
  159.                 if (EQ(cp, "ruct"))
  160.                     wt = wt_struct;
  161.                 else if (EQ(cp, "atic"))
  162.                     wt = wt_static;
  163.             } else if (EQ(cp, "igned"))
  164.                 wt = wt_signed;
  165.             break;
  166.     }
  167.     return wt;
  168. }    /* Wordcmp */
  169.  
  170.  
  171.  
  172.  
  173. static int SkipUntilSemi(void)
  174. {
  175.     int brackets = 0, c;
  176.  
  177.     while (1) {
  178.         c = Getc();
  179.         if (c == EOF)
  180.             break;
  181.         else if (c == SEMICOLON && brackets <= 0)
  182.             break;
  183.         else if (c == LEFTBRACKET)
  184.             brackets++;
  185.         else if (c == RIGHTBRACKET)
  186.             --brackets;
  187.     }
  188.     return c;
  189. }    /* SkipUntilSemi */
  190.  
  191.  
  192.  
  193. static int SkipBrackets(void)
  194. {
  195.     int brackets = 1, c;
  196.  
  197.     while (brackets > 0) {
  198.         c = Getc();
  199.         if (c == EOF)
  200.             break;
  201.         else if (c == LEFTBRACKET)
  202.             brackets++;
  203.         else if (c == RIGHTBRACKET)
  204.             --brackets;
  205.     }
  206.     return c;
  207. }    /* SkipUntilSemi */
  208.  
  209.  
  210.  
  211.  
  212. static void PutProto(void)
  213. {
  214.     char *sue_str, *vol_str, *signed_str;
  215.     char *ptr_str = "***********";
  216.  
  217.     if (is_sue == wt_struct)
  218.         sue_str = "struct ";
  219.     else if (is_sue == wt_union)
  220.         sue_str = "union ";
  221.     else if (is_sue == wt_enum)
  222.         sue_str = "enum ";
  223.     else sue_str = "";
  224.  
  225.     if (is_volatile)
  226.         vol_str = "volatile ";
  227.     else vol_str = "";
  228.  
  229.     if (is_ptr > 0)
  230.         ptr_str[is_ptr] = 0;
  231.     else ptr_str = "";
  232.  
  233.     if (is_signed == wt_unsigned)
  234.         signed_str = "unsigned ";
  235.     else if (is_signed == wt_signed)
  236.         signed_str = "signed ";
  237.     else signed_str = "";
  238.     
  239.     if (pgrepoutput > 0) {
  240.         (void) printf("%s [%s%s%s%s %s]%s;%s %d\n",
  241.             funcname,
  242.             vol_str,
  243.             signed_str,
  244.             sue_str,
  245.             typename,
  246.             ptr_str,
  247.             funcargs,
  248.             filename,
  249.             startline
  250.         );
  251.     } else {
  252.         if (!EQ("-", filename))
  253.             (void) printf("%s %d:  ",
  254.                 filename,
  255.                 startline
  256.             );
  257.         (void) printf("%s%s%s%s %s%s%s;\n",
  258.             vol_str,
  259.             signed_str,
  260.             sue_str,
  261.             typename,
  262.             ptr_str,
  263.             funcname,
  264.             funcargs
  265.         );
  266.     }
  267.  
  268.     if (is_ptr > 0)
  269.         ptr_str[is_ptr] = ASTERISK;
  270. }    /* PutProto */
  271.  
  272.  
  273.  
  274.  
  275. static void NewType(void)
  276. {
  277.     is_sue = 0;
  278.     is_volatile = 0;
  279.     is_signed = 0;
  280.     is_ptr = 0;
  281.     typename[0] = funcname[0] = funcargs[0] = 0;
  282.     startline = -1;
  283. }    /* NewType */
  284.  
  285.  
  286.  
  287.  
  288. static int ParenCollect(char *dst, size_t siz)
  289. {
  290.     char *wordp = dst;
  291.     int parens = 1, c;
  292.     size_t len;
  293.  
  294.     siz -= 2;        /* leave room for last ) and null. */
  295.     *wordp++ = LEFTPAREN;
  296.     len = 1;
  297.  
  298.     while (1) {
  299.         c = Getc();
  300.         if (c == EOF)
  301.             break;
  302.         if (c == LEFTPAREN)
  303.             parens++;
  304.         else if (c == RIGHTPAREN) {
  305.             if (--parens == 0) {
  306.                 *wordp++ = c;
  307.                 break;
  308.             }
  309.         }
  310.         if (isspace(c)) {
  311.             /* Don't bother with consecutive whitespace. */
  312.             if (!isspace(wordp[-1]) && len < siz) {
  313.                 *wordp++ = ' ';
  314.                 ++len;
  315.             }
  316.         } else if (len < siz) {
  317.             *wordp++ = c;
  318.             ++len;
  319.         }
  320.     }
  321.     *wordp = 0;
  322.     return c;
  323. }    /* ParenCollect */
  324.  
  325.  
  326.  
  327.  
  328. static void Parse(void)
  329. {
  330.     int                c = '\n', c2;
  331.     int                inword = 0;
  332.     char            *wordp;
  333.     int                wt;
  334.  
  335.     InitGetc();
  336.     NewType();
  337.  
  338.     while(1) {
  339.         if (inword) {
  340.             if (CIDENTCHAR(c)) {
  341.                 *wordp++ = c;
  342.             } else {
  343.                 /* End token. */
  344.                 *wordp = 0;
  345.                 inword = 0;
  346.                 switch (wt = Wordcmp()) {
  347.                     case wt_typedef:
  348.                         (void) SkipUntilSemi();
  349.                         break;
  350.                     case wt_struct:
  351.                     case wt_enum:
  352.                     case wt_union:
  353.                         is_sue = wt;
  354.                         break;
  355.                     case wt_volatile:
  356.                         is_volatile = wt_volatile;
  357.                         break;
  358.                     case wt_unsigned:
  359.                     case wt_signed:
  360.                         is_signed = wt;
  361.                         break;
  362.                     case wt_static:
  363.                     case wt_extern:
  364.                         break;
  365.                     case wt_unknown:
  366.                         if (typename[0] == 0) {
  367.                             (void) Strncpy(typename, word);
  368.                         } else {
  369.                             if (startline == -1)
  370.                                 startline = curline;
  371.                             (void) Strncpy(funcname, word);
  372.                         }
  373.                 }
  374.             }
  375.         } else {
  376.             if (CIDENTCHAR1(c)) {
  377.                 wordp = word;
  378.                 inword = 1;
  379.                 *wordp++ = c;
  380.             }
  381.         }
  382.  
  383.         if (c == '\n') {
  384.             while (NEXTC == CPP_LINE) {
  385.                  if (Skipline() == EOF)
  386.                     goto done;
  387.             }
  388.         } else if (c == SLASH) {
  389.             /* C++ style comment. */
  390.             if (((c2 = NEXTC) == SLASH)) {
  391.                 if (Skipline() == EOF)
  392.                     goto done;
  393.             } else if (c2 == ASTERISK) {
  394.                 /* C comment block. */
  395.                 SKIPCHAR;
  396.                 while (1) {
  397.                     if ((c = Getc()) == EOF) goto done;
  398.                     if (c == ASTERISK && NEXTC == SLASH) {
  399.                         /* End of comment. */
  400.                         SKIPCHAR;
  401.                         break;
  402.                     }
  403.                 }    /* end getting comment block. */
  404.             }        /* end if the char was '*' */
  405.         } else if (c == SEMICOLON) {
  406.             if (funcargs[0])
  407.                 PutProto();
  408.             NewType();
  409.         } else if (c == COMMA) {
  410.             if (funcargs[0])
  411.                 PutProto();
  412.             funcname[0] = funcargs[0] = 0;
  413.             is_ptr = 0;
  414.             startline = -1;
  415.         } else if (c == LEFTBRACKET) {
  416.             if (is_sue && (SkipBrackets() == EOF))
  417.                 goto done;
  418.             else if (EQ(typename, "C"))        /* No 'extern "C" {' lines, please. */
  419.                 typename[0] = 0;
  420.         } else if (c == LEFTPAREN) {
  421.             if (is_signed && typename[0] && funcname[0] == 0) {
  422.                 (void) Strncpy(funcname, typename);
  423.                 (void) Strncpy(typename, "int");
  424.                 startline = curline;
  425.             }
  426.             if (funcname[0]) {
  427.                 /* We have an argument list. */
  428.                 if (ParenCollect(funcargs, sizeof(funcargs)) == EOF)
  429.                     goto done;
  430.             } else {
  431.                 /* Typename, could be something like: (void (*)(int)) */
  432.                 if (ParenCollect(typename, sizeof(typename)) == EOF)
  433.                     goto done;
  434.             }
  435.         } else if (c == ASTERISK) {
  436.             if (typename[0])
  437.                 is_ptr++;
  438.         }
  439.  
  440.         c = Getc();
  441.         if (c == EOF) break;
  442.     }
  443. done:
  444.     return;
  445. }    /* parse */
  446.  
  447.  
  448.  
  449. void main(int argc, char **argv)
  450. {
  451.     int i, c, files;
  452.  
  453.     for (i=1, files=0; i<argc; i++) {
  454.         if (argv[i][0] == '-') {
  455.             c = argv[i][1];
  456.             if (c == 'g')
  457.                 pgrepoutput++;
  458.             else if (c == 'c')
  459.                 --pgrepoutput;
  460.             else {
  461.                 (void) fprintf(stderr, "\
  462. %s version %s by Mike Gleason, NCEMRSoft.\n\
  463. Function: Parses C header files and prints the function prototypes from them.\n\
  464. Usage: %s [-g | -c] headers...\n", argv[0], VERSION, argv[0]);
  465.                 exit(1);
  466.             }
  467.         } else {
  468.             if ((fp = fopen(argv[i], "r")) == NULL)
  469.                 perror(argv[i]);
  470.             else {
  471.                 files++;
  472.                 if (strncmp(argv[i], HEADERDIR, sizeof(HEADERDIR) - 1) == 0) {
  473.                     filename[0] = '<';
  474.                     (void) strncpy(filename + 1, argv[i] + sizeof(HEADERDIR), sizeof(filename) - 2);
  475.                     (void) Strncat(filename, ">");
  476.                 } else
  477.                     (void) Strncpy(filename, argv[i]);
  478.                 Parse();
  479.                 (void) fclose(fp);
  480.             }
  481.         }
  482.     }
  483.     if (files == 0) {
  484.         fp = stdin;
  485.         (void) Strncpy(filename, "-");
  486.         Parse();
  487.     }
  488. }    /* main */
  489.  
  490. /* prpp.c */
  491.