home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / cproto-3.0 / cproto.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  11.4 KB  |  502 lines

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