home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / cproto / part02 / cproto.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-15  |  10.1 KB  |  468 lines

  1. /* $Id: cproto.c 3.3 92/03/14 11:58:01 cthuang Exp $
  2.  *
  3.  * C function prototype generator and function definition converter
  4.  */
  5. #ifndef lint
  6. static char rcsid[] = "$Id: cproto.c 3.3 92/03/14 11:58:01 cthuang Exp $";
  7. #endif
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include "cproto.h"
  11. #include "patchlev.h"
  12.  
  13. /* getopt declarations */
  14. extern int getopt();
  15. extern char *optarg;
  16. extern int optind;
  17.  
  18. /* Name of the program */
  19. char progname[] = "cproto";
  20.  
  21. /* Program options */
  22.  
  23. /* If TRUE, output "extern" before global declarations */
  24. boolean extern_out = FALSE;
  25.  
  26. /* If TRUE, generate static declarations */
  27. boolean static_out = FALSE;
  28.  
  29. /* If TRUE, generate variable declarations */
  30. boolean variables_out = FALSE;
  31.  
  32. /* If TRUE, enable formal parameter promotion */
  33. boolean promote_param = TRUE;
  34.  
  35. /* Style of function prototype to generate */
  36. PrototypeStyle proto_style = PROTO_ANSI;
  37.  
  38. /* Function definition style converted to */
  39. FuncDefStyle func_style = FUNC_NONE;
  40.  
  41. /* Name of macro to guard prototypes */
  42. char *macro_name = "P_";
  43.  
  44. /* If TRUE, output prototype macro definition */
  45. boolean define_macro = TRUE;
  46.  
  47. /* If TRUE, output file name comments */
  48. boolean file_comment_out = TRUE;
  49.  
  50. /* Output formats for function declarators */
  51. FuncFormat fmt[] = {
  52.     /* miscellaneous function declarator */
  53.     { "", " ", "", "", " ", "" },
  54.     /* prototype */
  55.     { "", " ", "", "", " ", "" },
  56.     /* function definition */
  57.     { "", "\n", " ", "", " ", "" },
  58.     /* function definition with parameter comments */
  59.     { "", "\n", " ", "\n    ", "\n    ", "\n" },
  60. };
  61.  
  62. /* Include file directories */
  63. #ifdef MSDOS
  64. int num_inc_dir = 1;
  65. char *inc_dir[MAX_INC_DIR] = { "" };
  66. #else
  67. int num_inc_dir = 2;
  68. char *inc_dir[MAX_INC_DIR] = { "", "/usr/include" };
  69. #endif
  70.  
  71. /* C preprocessor command */
  72. #ifdef CPP
  73. extern FILE *popen();
  74. extern int pclose();
  75. static char *cpp_cmd;
  76. #endif
  77.  
  78.  
  79. /* Try to allocate some memory.
  80.  * If unsuccessful, output an error message and exit.
  81.  */
  82. char *
  83. xmalloc (n)
  84. unsigned n;
  85. {
  86.     char *p;
  87.  
  88.     if ((p = malloc(n)) == NULL) {
  89.     fprintf(stderr, "%s: out of memory\n", progname);
  90.     exit(1);
  91.     }
  92.     return p;
  93. }
  94.  
  95. /* Copy the string into allocated memory.
  96.  * If unsuccessful, output an error message and exit.
  97.  */
  98. char *
  99. xstrdup (src)
  100. char *src;
  101. {
  102.     return strcpy(xmalloc(strlen(src)+1), src);
  103. }
  104.  
  105. /* Output the current source file name and line number.
  106.  */
  107. void
  108. put_error ()
  109. {
  110.     fprintf(stderr, "\"%s\", line %d: ", cur_file_name(), cur_line_num());
  111. }
  112.  
  113. /* Scan for options from a string.
  114.  */
  115. static void
  116. parse_options (src, maxargc, pargc, argv)
  117. char *src;
  118. int maxargc, *pargc;
  119. char **argv;
  120. {
  121.     char *g, *p, c;
  122.     int argc;
  123.  
  124.     argc = 0;
  125.     g = xstrdup(src);
  126.     c = *g;
  127.     while (c != '\0' && argc < maxargc) {
  128.     while (c == ' ' || c == '\t')
  129.         c = *++g;
  130.     if (c == '\0')
  131.         break;
  132.     argv[argc++] = g;
  133.  
  134.     p = g;
  135.     while (1) {
  136.         if (c == ' ' || c == '\t' || c == '\0') {
  137.         *p = '\0';
  138.         break;
  139.         } else if (c == '"') {
  140.         while (1) {
  141.             c = *++g;
  142.             if (c == '"') {
  143.             c = *++g;
  144.             break;
  145.             } else if (c == '\0') {
  146.             break;
  147.             } else {
  148.             *p++ = c;
  149.             }
  150.         }
  151.         } else {
  152.         *p++ = c;
  153.         c = *++g;
  154.         }
  155.     }
  156.     if (c != '\0')
  157.         c = *++g;
  158.     }
  159.  
  160.     *pargc = argc;
  161. }
  162.  
  163. /* Replace any character escape sequences in a string with the actual
  164.  * characters.    Return a pointer to malloc'ed memory containing the result.
  165.  * This function knows only a few escape sequences.
  166.  */
  167. static char *
  168. escape_string (src)
  169. char *src;
  170. {
  171.     char *result, *get, *put;
  172.  
  173.     result = xstrdup(src);
  174.     put = result;
  175.     get = src;
  176.     while (*get != '\0') {
  177.     if (*get == '\\') {
  178.         switch (*(++get)) {
  179.         case 'n':
  180.         *put++ = '\n';
  181.         ++get;
  182.         break;
  183.         case 't':
  184.         *put++ = '\t';
  185.         ++get;
  186.         break;
  187.         default:
  188.         if (*get != '\0')
  189.             *put++ = *get++;
  190.         }
  191.     } else {
  192.         *put++ = *get++;
  193.     }
  194.     }
  195.     *put = *get;
  196.     return result;
  197. }
  198.  
  199. /* Trim any path name separator from the end of the string.
  200.  * Return a pointer to the string.
  201.  */
  202. char *
  203. trim_path_sep (s)
  204. char *s;
  205. {
  206.     char ch;
  207.     int n;
  208.  
  209.     n = strlen(s);
  210.     if (n > 0) {
  211.     ch = s[n-1];
  212.     if (ch == '/' || ch == '\\')
  213.         s[n-1] = '\0';
  214.     }
  215.     return s;
  216. }
  217.  
  218. /* Output usage message and exit.
  219.  */
  220. static void
  221. usage ()
  222. {
  223.     fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
  224.     fputs("  -a       convert function definitions to ANSI style\n", stderr);
  225.     fputs("  -e       output \"extern\" keyword before global declarations\n",
  226.     stderr);
  227.     fputs("  -f n     set function prototype style (0 to 4)\n", stderr);
  228.     fputs("  -n       omit file name comments\n", stderr);
  229.     fputs("  -p       disable formal parameter promotion\n", stderr);
  230.     fputs("  -s       output static declarations\n", stderr);
  231.     fputs("  -t       convert function definitions to traditional style\n",
  232.     stderr);
  233.     fputs("  -v       output variable declarations\n", stderr);
  234.     fputs("  -m name  set name of prototype macro\n", stderr);
  235.     fputs("  -d       omit prototype macro definition\n", stderr);
  236.     fputs("  -P fmt   set prototype format template \"int main (a, b)\"\n",
  237.     stderr);
  238.     fputs("  -F fmt   set function definition format template \"int main (a, b)\"\n",
  239.     stderr);
  240.     fputs("  -C fmt   set format for function definition with parameter comments\n",
  241.     stderr);
  242.     fputs("  -V       print version information\n", stderr);
  243.     fputs("  -D name[=value]\n", stderr);
  244.     fputs("  -U name\n", stderr);
  245.     fputs("  -I directory\n", stderr);
  246.     fputs("           C preprocessor options\n", stderr);
  247.     exit(1);
  248. }
  249.  
  250. #define MAX_OPTIONS 20
  251.  
  252. /* Process the command line options.
  253.  */
  254. static void
  255. process_options (pargc, pargv)
  256. int *pargc;
  257. char ***pargv;
  258. {
  259.     int argc, eargc, nargc;
  260.     char **argv, *eargv[MAX_OPTIONS], **nargv;
  261.     int i, c;
  262.     char *s;
  263. #ifdef CPP
  264.     char tmp[MAX_TEXT_SIZE];
  265. #endif
  266.  
  267.     argc = *pargc;
  268.     argv = *pargv;
  269.     if ((s = getenv("CPROTO")) != NULL) {
  270.     parse_options(s, MAX_OPTIONS, &eargc, eargv);
  271.     nargv = (char **)xmalloc((eargc+argc+1)*sizeof(char *));
  272.     nargv[0] = argv[0];
  273.     nargc = 1;
  274.     for (i = 0; i < eargc; ++i)
  275.         nargv[nargc++] = eargv[i];
  276.     for (i = 1; i < argc; ++i)
  277.         nargv[nargc++] = argv[i];
  278.     nargv[nargc] = NULL;
  279.     argc = nargc;
  280.     argv = nargv;
  281.     }
  282.  
  283.     while ((c = getopt(argc, argv, "aC:D:deF:f:I:m:nP:pstU:Vv")) != EOF) {
  284.     switch (c) {
  285.     case 'I':
  286.         if (num_inc_dir < MAX_INC_DIR) {
  287.         inc_dir[num_inc_dir++] = trim_path_sep(xstrdup(optarg));
  288.         } else {
  289.         fprintf(stderr, "%s: too many include directories\n",
  290.             progname);
  291.         }
  292.     case 'D':
  293.     case 'U':
  294. #ifdef CPP
  295.         sprintf(tmp, " -%c%s", c, optarg);
  296.         strcat(cpp_cmd, tmp);
  297. #endif
  298.         break;
  299.     case 'a':
  300.         func_style = FUNC_ANSI;
  301.         break;
  302.     case 'd':
  303.         define_macro = FALSE;
  304.         break;
  305.     case 'e':
  306.         extern_out = TRUE;
  307.         break;
  308.     case 'C':
  309.     case 'F':
  310.     case 'P':
  311.         s = escape_string(optarg);
  312.         i = (c == 'C') ? FMT_FUNC_COMMENT :
  313.         ((c == 'F') ? FMT_FUNC : FMT_PROTO);
  314.  
  315.         fmt[i].decl_spec_prefix = s;
  316.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  317.         if (*s == '\0') usage();
  318.         *s++ = '\0';
  319.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  320.         if (*s == '\0') usage();
  321.  
  322.         fmt[i].declarator_prefix = s;
  323.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  324.         if (*s == '\0') usage();
  325.         *s++ = '\0';
  326.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  327.         if (*s == '\0') usage();
  328.  
  329.         fmt[i].declarator_suffix = s;
  330.         while (*s != '\0' && *s != '(') ++s;
  331.         if (*s == '\0') usage();
  332.         *s++ = '\0';
  333.  
  334.         fmt[i].first_param_prefix = s;
  335.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  336.         if (*s == '\0') usage();
  337.         *s++ = '\0';
  338.         while (*s != '\0' && *s != ',') ++s;
  339.         if (*s == '\0') usage();
  340.  
  341.         fmt[i].middle_param_prefix = ++s;
  342.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  343.         if (*s == '\0') usage();
  344.         *s++ = '\0';
  345.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  346.         if (*s == '\0') usage();
  347.  
  348.         fmt[i].last_param_suffix = s;
  349.         while (*s != '\0' && *s != ')') ++s;
  350.         *s = '\0';
  351.  
  352.         break;
  353.     case 'f':
  354.         proto_style = atoi(optarg);
  355.         if (proto_style < 0 || proto_style > PROTO_MACRO)
  356.         usage();
  357.         break;
  358.     case 'm':
  359.         macro_name = optarg;
  360.         break;
  361.     case 'n':
  362.         file_comment_out = FALSE;
  363.         break;
  364.     case 'p':
  365.         promote_param = FALSE;
  366.         break;
  367.     case 's':
  368.         static_out = TRUE;
  369.         break;
  370.     case 't':
  371.         func_style = FUNC_TRADITIONAL;
  372.         break;
  373.     case 'V':
  374.         fprintf(stderr, "%s patchlevel %d\n", rcsid, PATCHLEVEL);
  375.         break;
  376.     case 'v':
  377.         variables_out = TRUE;
  378.         break;
  379.     default:
  380.         usage();
  381.     }
  382.     }
  383.  
  384.     *pargc = argc;
  385.     *pargv = argv;
  386. }
  387.  
  388. int
  389. main (argc, argv)
  390. int argc;
  391. char **argv;
  392. {
  393.     int i;
  394.     FILE *inf;
  395. #ifdef CPP
  396.     unsigned n;
  397.     char *cmd;
  398.  
  399.     /* Allocate buffer for C preprocessor command line. */
  400.     n = strlen(CPP) + 1;
  401.     for (i = 0; i < argc; ++i) {
  402.     n += strlen(argv[i]) + 1;
  403.     }
  404.     cpp_cmd = xmalloc(n);
  405.     strcpy(cpp_cmd, CPP);
  406.     cmd = xmalloc(n);
  407. #endif
  408.     process_options(&argc, &argv);
  409.  
  410.     if (proto_style == PROTO_MACRO && define_macro) {
  411.     printf("#if defined(__STDC__) || defined(__cplusplus)\n");
  412.     printf("#define %s(s) s\n", macro_name);
  413.     printf("#else\n");
  414.     printf("#define %s(s) ()\n", macro_name);
  415.     printf("#endif\n\n");
  416.     }
  417.  
  418.     init_parser();
  419.     if (optind == argc) {
  420.     if (func_style != FUNC_NONE) {
  421.         proto_style = PROTO_NONE;
  422.         variables_out = FALSE;
  423.         file_comment_out = FALSE;
  424.     }
  425.     process_file(stdin, "stdin");
  426.     pop_file();
  427.     } else {
  428.     for (i = optind; i < argc; ++i) {
  429. #ifdef CPP
  430.         if (func_style == FUNC_NONE) {
  431.         sprintf(cmd, "%s %s", cpp_cmd, argv[i]);
  432.         if ((inf = popen(cmd, "r")) == NULL) {
  433.             fprintf(stderr, "%s: error running cpp\n", progname);
  434.             continue;
  435.         }
  436.         } else {
  437.         if ((inf = fopen(argv[i], "r")) == NULL) {
  438.             fprintf(stderr, "%s: cannot read file %s\n", progname,
  439.             argv[i]);
  440.             continue;
  441.         }
  442.         }
  443. #else
  444.         if ((inf = fopen(argv[i], "r")) == NULL) {
  445.         fprintf(stderr, "%s: cannot read file %s\n", progname, argv[i]);
  446.         continue;
  447.         }
  448. #endif
  449.         process_file(inf, argv[i]);
  450. #ifdef CPP
  451.         if (func_style == FUNC_NONE) {
  452.         pclose(inf);
  453.         } else {
  454.         pop_file();
  455.         }
  456. #else
  457.         pop_file();
  458. #endif
  459.     }
  460.     }
  461.  
  462.     if (proto_style == PROTO_MACRO && define_macro) {
  463.     printf("\n#undef %s\n", macro_name);
  464.     }
  465.  
  466.     return 0;
  467. }
  468.