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

  1. /* $Id: cproto.c 3.4 92/04/04 13:59:22 cthuang Exp $
  2.  *
  3.  * C function prototype generator and function definition converter
  4.  */
  5. #ifndef lint
  6. static char rcsid[] = "$Id: cproto.c 3.4 92/04/04 13:59:22 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 comments in prototypes */
  48. boolean proto_comments = 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. /* Run the C preprocessor */
  72. #ifdef CPP
  73. extern FILE *popen();
  74. extern int pclose();
  75. static char *cpp_cmd, *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("Options:\n", stderr);
  225.     fputs("  -a       Convert function definitions to ANSI style\n", stderr);
  226.     fputs("  -c       Omit comments in generated prototypes\n", stderr);
  227.     fputs("  -e       Output \"extern\" keyword before global declarations\n",
  228.     stderr);
  229.     fputs("  -f n     Set function prototype style (0 to 4)\n", stderr);
  230.     fputs("  -p       Disable formal parameter promotion\n", stderr);
  231.     fputs("  -s       Output static declarations\n", stderr);
  232.     fputs("  -t       Convert function definitions to traditional style\n",
  233.     stderr);
  234.     fputs("  -v       Output variable declarations\n", stderr);
  235.     fputs("  -m name  Set name of prototype macro\n", stderr);
  236.     fputs("  -d       Omit prototype macro definition\n", stderr);
  237.     fputs("  -P fmt   Set prototype format template \"int main (a, b)\"\n",
  238.     stderr);
  239.     fputs("  -F fmt   Set function definition format template \"int main (a, b)\"\n",
  240.     stderr);
  241.     fputs("  -C fmt   Set format for function definition with parameter comments\n",
  242.     stderr);
  243.     fputs("  -V       Print version information\n", stderr);
  244.     fputs("  -D name[=value]\n", stderr);
  245.     fputs("  -U name\n", stderr);
  246.     fputs("  -I directory\n", stderr);
  247.     fputs("           Set C preprocessor options\n", stderr);
  248.     exit(1);
  249. }
  250.  
  251. #define MAX_OPTIONS 40
  252.  
  253. /* Process the command line options.
  254.  */
  255. static void
  256. process_options (pargc, pargv)
  257. int *pargc;
  258. char ***pargv;
  259. {
  260.     int argc, eargc, nargc;
  261.     char **argv, *eargv[MAX_OPTIONS], **nargv;
  262.     int i, c;
  263.     char *s;
  264. #ifdef CPP
  265.     unsigned n;
  266.     char tmp[MAX_TEXT_SIZE];
  267. #endif
  268.  
  269.     argc = *pargc;
  270.     argv = *pargv;
  271.     if ((s = getenv("CPROTO")) != NULL) {
  272.     parse_options(s, MAX_OPTIONS, &eargc, eargv);
  273.     nargv = (char **)xmalloc((eargc+argc+1)*sizeof(char *));
  274.     nargv[0] = argv[0];
  275.     nargc = 1;
  276.     for (i = 0; i < eargc; ++i)
  277.         nargv[nargc++] = eargv[i];
  278.     for (i = 1; i < argc; ++i)
  279.         nargv[nargc++] = argv[i];
  280.     nargv[nargc] = NULL;
  281.     argc = nargc;
  282.     argv = nargv;
  283.     }
  284.  
  285. #ifdef CPP
  286.     /* Allocate buffer for C preprocessor command line. */
  287.     n = strlen(CPP) + 1;
  288.     for (i = 0; i < argc; ++i) {
  289.     n += strlen(argv[i]) + 1;
  290.     }
  291.     cpp_cmd = xmalloc(n);
  292.     strcpy(cpp_cmd, CPP);
  293.     cmd = xmalloc(n);
  294. #endif
  295.  
  296.     while ((c = getopt(argc, argv, "aC:cD:deF:f:I:m:P:pstU:Vv")) != EOF) {
  297.     switch (c) {
  298.     case 'I':
  299.         if (num_inc_dir < MAX_INC_DIR) {
  300.         inc_dir[num_inc_dir++] = trim_path_sep(xstrdup(optarg));
  301.         } else {
  302.         fprintf(stderr, "%s: too many include directories\n",
  303.             progname);
  304.         }
  305.     case 'D':
  306.     case 'U':
  307. #ifdef CPP
  308.         sprintf(tmp, " -%c%s", c, optarg);
  309.         strcat(cpp_cmd, tmp);
  310. #endif
  311.         break;
  312.     case 'a':
  313.         func_style = FUNC_ANSI;
  314.         break;
  315.     case 'c':
  316.         proto_comments = FALSE;
  317.         break;
  318.     case 'd':
  319.         define_macro = FALSE;
  320.         break;
  321.     case 'e':
  322.         extern_out = TRUE;
  323.         break;
  324.     case 'C':
  325.     case 'F':
  326.     case 'P':
  327.         s = escape_string(optarg);
  328.         i = (c == 'C') ? FMT_FUNC_COMMENT :
  329.         ((c == 'F') ? FMT_FUNC : FMT_PROTO);
  330.  
  331.         fmt[i].decl_spec_prefix = s;
  332.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  333.         if (*s == '\0') usage();
  334.         *s++ = '\0';
  335.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  336.         if (*s == '\0') usage();
  337.  
  338.         fmt[i].declarator_prefix = s;
  339.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  340.         if (*s == '\0') usage();
  341.         *s++ = '\0';
  342.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  343.         if (*s == '\0') usage();
  344.  
  345.         fmt[i].declarator_suffix = s;
  346.         while (*s != '\0' && *s != '(') ++s;
  347.         if (*s == '\0') usage();
  348.         *s++ = '\0';
  349.  
  350.         fmt[i].first_param_prefix = s;
  351.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  352.         if (*s == '\0') usage();
  353.         *s++ = '\0';
  354.         while (*s != '\0' && *s != ',') ++s;
  355.         if (*s == '\0') usage();
  356.  
  357.         fmt[i].middle_param_prefix = ++s;
  358.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  359.         if (*s == '\0') usage();
  360.         *s++ = '\0';
  361.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  362.         if (*s == '\0') usage();
  363.  
  364.         fmt[i].last_param_suffix = s;
  365.         while (*s != '\0' && *s != ')') ++s;
  366.         *s = '\0';
  367.  
  368.         break;
  369.     case 'f':
  370.         proto_style = atoi(optarg);
  371.         if (proto_style < 0 || proto_style > PROTO_MACRO)
  372.         usage();
  373.         break;
  374.     case 'm':
  375.         macro_name = optarg;
  376.         break;
  377.     case 'p':
  378.         promote_param = FALSE;
  379.         break;
  380.     case 's':
  381.         static_out = TRUE;
  382.         break;
  383.     case 't':
  384.         func_style = FUNC_TRADITIONAL;
  385.         break;
  386.     case 'V':
  387.         fprintf(stderr, "%s patchlevel %d\n", rcsid, PATCHLEVEL);
  388.         break;
  389.     case 'v':
  390.         variables_out = TRUE;
  391.         break;
  392.     default:
  393.         usage();
  394.     }
  395.     }
  396.  
  397.     *pargc = argc;
  398.     *pargv = argv;
  399. }
  400.  
  401. int
  402. main (argc, argv)
  403. int argc;
  404. char **argv;
  405. {
  406.     int i;
  407.     FILE *inf;
  408.  
  409.     process_options(&argc, &argv);
  410.  
  411.     if (proto_style == PROTO_MACRO && define_macro) {
  412.     printf("#if defined(__STDC__) || defined(__cplusplus)\n");
  413.     printf("#define %s(s) s\n", macro_name);
  414.     printf("#else\n");
  415.     printf("#define %s(s) ()\n", macro_name);
  416.     printf("#endif\n\n");
  417.     }
  418.  
  419.     init_parser();
  420.     if (optind == argc) {
  421.     if (func_style != FUNC_NONE) {
  422.         proto_style = PROTO_NONE;
  423.         variables_out = FALSE;
  424.         proto_comments = FALSE;
  425.     }
  426.     process_file(stdin, "stdin");
  427.     pop_file();
  428.     } else {
  429.     for (i = optind; i < argc; ++i) {
  430. #ifdef CPP
  431.         if (func_style == FUNC_NONE) {
  432.         sprintf(cmd, "%s %s", cpp_cmd, argv[i]);
  433.         if ((inf = popen(cmd, "r")) == NULL) {
  434.             fprintf(stderr, "%s: error running cpp\n", progname);
  435.             continue;
  436.         }
  437.         } else {
  438.         if ((inf = fopen(argv[i], "r")) == NULL) {
  439.             fprintf(stderr, "%s: cannot read file %s\n", progname,
  440.             argv[i]);
  441.             continue;
  442.         }
  443.         }
  444. #else
  445.         if ((inf = fopen(argv[i], "r")) == NULL) {
  446.         fprintf(stderr, "%s: cannot read file %s\n", progname, argv[i]);
  447.         continue;
  448.         }
  449. #endif
  450.         process_file(inf, argv[i]);
  451. #ifdef CPP
  452.         if (func_style == FUNC_NONE) {
  453.         pclose(inf);
  454.         } else {
  455.         pop_file();
  456.         }
  457. #else
  458.         pop_file();
  459. #endif
  460.     }
  461.     }
  462.  
  463.     if (proto_style == PROTO_MACRO && define_macro) {
  464.     printf("\n#undef %s\n", macro_name);
  465.     }
  466.  
  467.     return 0;
  468. }
  469.