home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cproto.zip / cproto46 / cproto.c < prev    next >
C/C++ Source or Header  |  1998-01-23  |  20KB  |  886 lines

  1. /* $Id: cproto.c,v 4.8 1998/01/24 01:42:07 cthuang Exp $
  2.  *
  3.  * C function prototype generator and function definition converter
  4.  */
  5. #define VERSION "4.6"
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include "cproto.h"
  10.  
  11. /* getopt declarations */
  12. #if HAVE_GETOPT_H
  13. #include <getopt.h>
  14. #else
  15. extern int getopt ARGS((int argc, char *const *argv, const char *shortopts));
  16. extern char *optarg;
  17. extern int optind;
  18. #endif
  19.  
  20. /* Name of the program (from argv[0]) */
  21. char *progname;
  22.  
  23. /* Program options */
  24.  
  25. /* If nonzero, output variables declared "extern" in include-files */
  26. int extern_in = 0;
  27.  
  28. /* When TRUE, suppress return-statements in function-bodies */
  29. int exitlike_func = FALSE;
  30.  
  31. /* If TRUE, output "extern" before global declarations */
  32. boolean extern_out = FALSE;
  33.  
  34. /* By default, generate global declarations only */
  35. Scope scope_out = SCOPE_EXTERN;
  36.  
  37. /* If TRUE, export typedef declarations (needed for lint-libs) */
  38. #if OPT_LINTLIBRARY
  39. boolean types_out = FALSE;
  40. #endif
  41.  
  42. /* If TRUE, undef functions to avoid shadowing problems */
  43. #if OPT_LINTLIBRARY
  44. boolean lint_shadowed = FALSE;
  45. #endif
  46.  
  47. /* If TRUE, generate variable declarations */
  48. boolean variables_out = FALSE;
  49.  
  50. /* If TRUE, enable formal parameter promotion */
  51. boolean promote_param = TRUE;
  52.  
  53. /* Style of function prototype to generate */
  54. PrototypeStyle proto_style = PROTO_ANSI;
  55.  
  56. /* Function definition style converted to */
  57. FuncDefStyle func_style = FUNC_UNKNOWN;
  58.  
  59. /* If TRUE, put guard macro around prototype parameters */
  60. boolean proto_macro = FALSE;
  61.  
  62. /* Name of macro to guard prototypes */
  63. char *macro_name = "P_";
  64.  
  65. /* If TRUE, output prototype macro definition */
  66. boolean define_macro = TRUE;
  67.  
  68. /* If TRUE, output comments in prototypes */
  69. boolean proto_comments = FALSE;
  70.  
  71. /* If TRUE, output comments naming source files */
  72. boolean file_comments = TRUE;
  73.  
  74. /* Conditional compilation directive output in front of function definitions */
  75. char *func_directive = "#ifdef ANSI_FUNC";
  76.  
  77. /* Output formats for function declarators */
  78. FuncFormat fmt[] = {
  79.     /* miscellaneous function declarator */
  80.     { "", " ", "", "", " ", "" },
  81.     /* prototype */
  82.     { "", " ", "", "", " ", "" },
  83.     /* function definition */
  84.     { "", "\n", " ", "", " ", "" },
  85.     /* function definition with parameter comments */
  86.     { "", "\n", " ", "\n    ", "\n    ", "\n" },
  87. };
  88.  
  89. /* If TRUE, don't output message if unable to read an include file */
  90. boolean quiet = FALSE;
  91.  
  92. /* Include file directories */
  93. #ifdef MSDOS
  94. # ifdef __TURBOC__
  95. int num_inc_dir = 2;
  96. char *inc_dir[MAX_INC_DIR] = { "" , "/tc/include" };
  97. # else
  98. int num_inc_dir = 1;
  99. char *inc_dir[MAX_INC_DIR] = { "" };
  100. # endif
  101. #else
  102. # ifdef vms
  103. int num_inc_dir = 2;
  104. char *inc_dir[MAX_INC_DIR] = { "[]", "sys$library:" };
  105. # else
  106. int num_inc_dir = 2;
  107. char *inc_dir[MAX_INC_DIR] = { "", "/usr/include" };
  108. # endif
  109. #endif
  110.  
  111. /* Run the C preprocessor */
  112. #ifdef CPP
  113. # if !HAVE_POPEN_PROTOTYPE
  114. extern FILE *popen ARGS((const char *c, const char *m));
  115. # endif
  116. extern int pclose ARGS((FILE *p));
  117. static char *cpp = CPP, *cpp_opt, *cpp_cmd;
  118. #endif
  119.  
  120. static    char *    escape_string   ARGS((char *src));
  121. static    void    usage           ARGS((void));
  122. static    void    process_options ARGS((int *pargc, char ***pargv));
  123. static    void    parse_options   ARGS((char *src, int maxargc, int *pargc, char **argv));
  124.  
  125. /* Try to allocate some memory.
  126.  * If unsuccessful, output an error message and exit.
  127.  */
  128. #if !HAVE_LIBDMALLOC
  129. #ifdef NO_LEAKS
  130. char *xMalloc(n,f,l) unsigned n; char *f; int l;
  131. #else
  132. char *xmalloc (n) unsigned n;
  133. #endif
  134. {
  135.     char *p;
  136. #if HAVE_LIBDBMALLOC
  137.     p = debug_malloc(f, l, n);
  138. #else
  139.     p = malloc(n);
  140. #endif
  141.  
  142.     if (p == NULL) {
  143.     fprintf(stderr, "%s: out of memory (cannot allocate %d bytes)\n",
  144.         progname, n);
  145.     exit(EXIT_FAILURE);
  146.     }
  147.     *p = '\0';
  148.     return p;
  149. }
  150. #endif /* if !HAVE_LIBDMALLOC */
  151.  
  152. /* Copy the string into allocated memory.
  153.  * If unsuccessful, output an error message and exit.
  154.  */
  155. #if !HAVE_LIBDMALLOC
  156. #ifdef NO_LEAKS
  157. char *xStrdup(src, f, l) char *src; char *f; int l;
  158. #else
  159. char *xstrdup (src) char *src;
  160. #endif
  161. {
  162. #if defined(NO_LEAKS)
  163.     return strcpy(xMalloc(strlen(src)+1, f, l), src);
  164. #else
  165.     return strcpy(xmalloc(strlen(src)+1), src);
  166. #endif
  167. }
  168. #endif /* if !HAVE_LIBDMALLOC */
  169.  
  170. /* Output the current source file name and line number.
  171.  */
  172. void
  173. put_error ()
  174. {
  175.     fprintf(stderr, "\"%s\", line %u: ", cur_file_name(), cur_line_num());
  176. }
  177.  
  178. /* Scan for options from a string.
  179.  */
  180. static void
  181. parse_options (src, maxargc, pargc, argv)
  182. char *src;
  183. int maxargc, *pargc;
  184. char **argv;
  185. {
  186.     char *g, *p, c;
  187.     int argc;
  188.  
  189.     argc = 0;
  190.     g = xstrdup(src);
  191.     c = *g;
  192.     while (c != '\0' && argc < maxargc) {
  193.     while (c == ' ' || c == '\t')
  194.         c = *++g;
  195.     if (c == '\0')
  196.         break;
  197.     argv[argc++] = g;
  198.  
  199.     p = g;
  200.     while (1) {
  201.         if (c == ' ' || c == '\t' || c == '\0') {
  202.         *p = '\0';
  203.         break;
  204.         } else if (c == '"') {
  205.         while (1) {
  206.             c = *++g;
  207.             if (c == '"') {
  208.             c = *++g;
  209.             break;
  210.             } else if (c == '\0') {
  211.             break;
  212.             } else {
  213.             *p++ = c;
  214.             }
  215.         }
  216.         } else {
  217.         *p++ = c;
  218.         c = *++g;
  219.         }
  220.     }
  221.     if (c != '\0')
  222.         c = *++g;
  223.     }
  224.  
  225.     *pargc = argc;
  226. }
  227.  
  228. /* Replace any character escape sequences in a string with the actual
  229.  * characters.    Return a pointer to malloc'ed memory containing the result.
  230.  * This function knows only a few escape sequences.
  231.  */
  232. static char *
  233. escape_string (src)
  234. char *src;
  235. {
  236.     char *result, *get, *put;
  237.  
  238.     result = xstrdup(src);
  239.     put = result;
  240.     get = src;
  241.     while (*get != '\0') {
  242.     if (*get == '\\') {
  243.         switch (*(++get)) {
  244.         case 'n':
  245.         *put++ = '\n';
  246.         ++get;
  247.         break;
  248.         case 's':
  249.         *put++ = ' ';
  250.         ++get;
  251.         break;
  252.         case 't':
  253.         *put++ = '\t';
  254.         ++get;
  255.         break;
  256.         default:
  257.         if (*get != '\0')
  258.             *put++ = *get++;
  259.         }
  260.     } else {
  261.         *put++ = *get++;
  262.     }
  263.     }
  264.     *put = *get;
  265.     return result;
  266. }
  267.  
  268. /* Returns true iff the character is a path leaf separator
  269.  */
  270. int
  271. is_path_sep (ch)
  272. int ch;
  273. {
  274. #if defined(MSDOS) || defined(OS2)
  275.     return ch == '/' || ch == '\\';
  276. #else
  277.     return ch == '/';
  278. #endif
  279. }
  280.  
  281. /* Trim any path name separator from the end of the string.
  282.  * Return a pointer to the string.
  283.  */
  284. char *
  285. trim_path_sep (s)
  286. char *s;
  287. {
  288.     int n;
  289.  
  290.     n = strlen(s);
  291.     if (n > 0) {
  292.     if (is_path_sep(s[n-1]))
  293.         s[n-1] = '\0';
  294.     }
  295.     return s;
  296. }
  297.  
  298. /* Output usage message and exit.
  299.  */
  300. static void
  301. usage ()
  302. {
  303.     fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
  304.     fputs("Options:\n", stderr);
  305.     fputs("  -a, -t           Convert function definitions to ANSI or traditional style\n", stderr);
  306.     fputs("  -b               Rewrite function definitions in both styles\n", stderr);
  307.     fputs("  -c               Enable comments in prototype parameters\n", stderr);
  308.     fputs("  -e               Output \"extern\" keyword before global declarations\n", stderr);
  309.     fputs("  -f n             Set function prototype style (0 to 3)\n", stderr);
  310. #if OPT_LINTLIBRARY
  311.     fputs("  -l               Generate output in lint-library style\n", stderr);
  312. #endif
  313.     fputs("  -o file          Redirect output to file\n", stderr);
  314.     fputs("  -O file          Redirect errors to file\n", stderr);
  315.     fputs("  -p               Disable formal parameter promotion\n", stderr);
  316.     fputs("  -q               Disable include file read failure messages\n", stderr);
  317.     fputs("  -s               Output static declarations also\n", stderr);
  318.     fputs("  -S               Output static declarations only\n", stderr);
  319. #if OPT_LINTLIBRARY
  320.     fputs("  -T               Output type definitions\n", stderr);
  321. #endif
  322.     fputs("  -v               Output variable declarations\n", stderr);
  323.     fputs("  -x               Output variables and functions declared \"extern\"\n", stderr);
  324.     fputs("  -m               Put macro around prototype parameters\n", stderr);
  325.     fputs("  -M name          Set name of prototype macro\n", stderr);
  326.     fputs("  -d               Omit prototype macro definition\n", stderr);
  327.     fputs("  -P template      Set prototype format template \" int f (a, b)\"\n", stderr);
  328.     fputs("  -F template      Set function definition format template \" int f (a, b)\"\n", stderr);
  329.     fputs("  -C template      Set format for function definition with parameter comments\n", stderr);
  330.     fputs("  -D name[=value]  Define C preprocessor symbol\n", stderr);
  331.     fputs("  -U name          Undefine C preprocessor symbol\n", stderr);
  332.     fputs("  -I directory     Add #include search directory\n", stderr);
  333.     fputs("  -E command       Run specified C preprocessor command\n", stderr);
  334.     fputs("  -E 0             Do not run any C preprocessor\n", stderr);
  335.     fputs("  -V               Print version information\n", stderr);
  336.     exit(EXIT_FAILURE);
  337. }
  338.  
  339. #ifdef    vms
  340. static    char    *cpp_defines;
  341. static    char    *cpp_include;
  342. static    char    *cpp_undefns;
  343.  
  344. static    void    add2list ARGS((char *dst, char *src));
  345. static    void    add_option ARGS((char *keyword, char *src));
  346.  
  347. static void
  348. add2list(dst, src)
  349. char *dst;
  350. char *src;
  351. {
  352.     if (*dst)
  353.     strcat(dst, ",");
  354.     strcat(dst, src);
  355. }
  356.  
  357. static void
  358. add_option(keyword, src)
  359. char *keyword;
  360. char *src;
  361. {
  362.     if (*src)
  363.     sprintf(cpp_opt + strlen(cpp_opt), " /%s=(%s)", keyword, src);
  364. }
  365. #endif    /* vms */
  366.  
  367. #ifdef QUOTE_POPEN_ARGS
  368.  
  369. /* Calculate length of string including shell quoting characters that
  370.  * must be inserted to preserve the string when it is passed to /bin/sh.
  371.  * On UNIX systems, popen() runs /bin/sh.
  372.  */
  373. #define QUOTECHARS "\"\'\t\n "
  374.  
  375. static int
  376. quote_length (s)
  377. char *s;
  378. {
  379.     int len = strlen(s);
  380.  
  381.     if (strpbrk(s, QUOTECHARS))  {
  382.     len += 2;
  383.     while (*s)
  384.         if (*s++ == '\'')
  385.         len += 4; /* replace ' with '"'"' (ick!) */
  386.     }
  387.     return len;
  388. }
  389.  
  390. /* Insert quoting characters to preserve the string when it is passed to
  391.  * /bin/sh.
  392.  */
  393. static char *
  394. quote_string (s) 
  395. char *s;
  396. {
  397.     if (strpbrk(s, QUOTECHARS))  {
  398.     char *src = s;
  399.     char *dup, *dup_orig;
  400.     
  401.     dup = dup_orig = xstrdup(s);
  402.  
  403.     while (isspace(*src))
  404.         *src++ = *dup++;
  405.  
  406.     *src++ = '\'';
  407.     while (*dup) {
  408.         if (*dup == '\'') {
  409.         *src++ = '\'';
  410.         *src++ = '"';
  411.         *src++ = '\'';
  412.         *src++ = '"';
  413.         *src++ = '\'';
  414.         dup++;
  415.         } else {
  416.             *src++ = *dup++;
  417.         }
  418.     }
  419.  
  420.     *src++ = '\'';
  421.     *src = '\0';
  422.     free(dup_orig);
  423.     }
  424.  
  425.     return s;
  426. }
  427. #else
  428. #define    quote_length(s) strlen(s)
  429. #define quote_string(s)    (s)
  430. #endif /*QUOTE_POPEN_ARGS*/
  431.  
  432. #define MAX_OPTIONS 40
  433.  
  434. /* Process the command line options.
  435.  */
  436. static void
  437. process_options (pargc, pargv)
  438. int *pargc;
  439. char ***pargv;
  440. {
  441.     int argc, eargc, nargc;
  442.     char **argv, *eargv[MAX_OPTIONS], **nargv;
  443.     int i, c;
  444.     char *s;
  445. #if defined(CPP)
  446.     unsigned n;
  447. #endif
  448. #if defined(CPP) && !defined(vms)
  449.     char tmp[MAX_TEXT_SIZE];
  450. #endif
  451.  
  452.     argc = *pargc;
  453.     argv = *pargv;
  454. #ifndef vms    /* this conflicts with use of foreign commands... */
  455.     if ((s = getenv("CPROTO")) != NULL) {
  456.     parse_options(s, MAX_OPTIONS, &eargc, eargv);
  457.     nargv = (char **)xmalloc((eargc+argc+1)*sizeof(char *));
  458.     nargv[0] = argv[0];
  459.     nargc = 1;
  460.     for (i = 0; i < eargc; ++i)
  461.         nargv[nargc++] = eargv[i];
  462.     for (i = 1; i < argc; ++i)
  463.         nargv[nargc++] = argv[i];
  464.     nargv[nargc] = NULL;
  465.     argc = nargc;
  466.     argv = nargv;
  467.     }
  468. #endif
  469.  
  470. #ifdef CPP
  471.     /* Allocate buffer for C preprocessor command line. */
  472.     n = strlen(cpp) + 1;
  473.     for (i = 0; i < argc; ++i) {
  474.     n += quote_length(argv[i]) + 1;  /* add more for possible quoting */
  475.     }
  476. #ifdef    vms
  477.     *(cpp_include = xmalloc(n+argc)) = '\0';
  478.     *(cpp_defines = xmalloc(n+argc)) = '\0';
  479.     *(cpp_undefns = xmalloc(n+argc)) = '\0';
  480.     n += 30;    /* for keywords */
  481. #endif
  482.     *(cpp_opt = xmalloc(n)) = '\0';
  483.     n += (2 + strlen(CPP) + BUFSIZ);
  484.     *(cpp_cmd = xmalloc(n)) = '\0';
  485. #endif
  486.  
  487.     while ((c = getopt(argc, argv, "aB:bC:cD:dE:eF:f:I:mM:P:pqSstU:Vvo:O:Tlx")) != EOF) {
  488.     switch (c) {
  489.     case 'I':
  490. #ifdef    vms
  491.         add2list(cpp_include, optarg);
  492.         break;
  493. #else    /* unix */
  494.         if (num_inc_dir < MAX_INC_DIR) {
  495.         char *save = inc_dir[--num_inc_dir];
  496.         inc_dir[num_inc_dir++] = trim_path_sep(xstrdup(optarg));
  497.         inc_dir[num_inc_dir++] = save;
  498.         } else {
  499.         fprintf(stderr, "%s: too many include directories\n",
  500.             progname);
  501.         }
  502. #endif
  503.         /*FALLTHRU*/
  504.     case 'D':
  505. #ifdef    vms
  506.         add2list(cpp_defines, optarg);
  507.         break;
  508. #endif
  509.         /*FALLTHRU*/
  510.     case 'U':
  511. #ifdef    vms
  512.         add2list(cpp_undefns, optarg);
  513.         break;
  514. #else    /* UNIX, etc. */
  515. #ifdef CPP
  516.         sprintf(tmp, " -%c%s", c, optarg);
  517.         strcat(cpp_opt, quote_string(tmp));
  518. #endif
  519. #endif
  520.         break;
  521.  
  522.     case 'a':
  523.         func_style = FUNC_ANSI;
  524.         break;
  525.     case 'B':
  526.         func_directive = optarg;
  527.         break;
  528.     case 'b':
  529.         func_style = FUNC_BOTH;
  530.         break;
  531.     case 'c':
  532.         proto_comments = TRUE;
  533.         break;
  534.     case 'd':
  535.         define_macro = FALSE;
  536.         break;
  537.     case 'E':
  538. #ifdef CPP
  539.         if (strcmp(optarg, "0") == 0) {
  540.         cpp = NULL;
  541.         } else {
  542.         cpp = optarg;
  543.         }
  544. #endif
  545.         break;
  546.     case 'e':
  547.         extern_out = TRUE;
  548.         break;
  549.     case 'C':
  550.     case 'F':
  551.     case 'P':
  552.         s = escape_string(optarg);
  553.         i = (c == 'C') ? FMT_FUNC_COMMENT :
  554.         ((c == 'F') ? FMT_FUNC : FMT_PROTO);
  555.  
  556.         fmt[i].decl_spec_prefix = s;
  557.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  558.         if (*s == '\0') usage();
  559.         *s++ = '\0';
  560.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  561.         if (*s == '\0') usage();
  562.  
  563.         fmt[i].declarator_prefix = s;
  564.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  565.         if (*s == '\0') usage();
  566.         *s++ = '\0';
  567.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  568.         if (*s == '\0') usage();
  569.  
  570.         fmt[i].declarator_suffix = s;
  571.         while (*s != '\0' && *s != '(') ++s;
  572.         if (*s == '\0') usage();
  573.         *s++ = '\0';
  574.  
  575.         fmt[i].first_param_prefix = s;
  576.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  577.         if (*s == '\0') usage();
  578.         *s++ = '\0';
  579.         while (*s != '\0' && *s != ',') ++s;
  580.         if (*s == '\0') usage();
  581.  
  582.         fmt[i].middle_param_prefix = ++s;
  583.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  584.         if (*s == '\0') usage();
  585.         *s++ = '\0';
  586.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  587.         if (*s == '\0') usage();
  588.  
  589.         fmt[i].last_param_suffix = s;
  590.         while (*s != '\0' && *s != ')') ++s;
  591.         *s = '\0';
  592.  
  593.         break;
  594.     case 'f':
  595.         proto_style = atoi(optarg);
  596.         if (proto_style < 0 || proto_style > PROTO_ANSI)
  597.         usage();
  598.         break;
  599.     case 'm':
  600.         proto_macro = TRUE;
  601.         break;
  602.     case 'M':
  603.         macro_name = optarg;
  604.         break;
  605.     case 'p':
  606.         promote_param = FALSE;
  607.         break;
  608.     case 'q':
  609.         quiet = TRUE;
  610.         break;
  611.     case 'S':
  612.         scope_out = SCOPE_STATIC;
  613.         break;
  614.     case 's':
  615.         scope_out = SCOPE_ALL;
  616.         break;
  617.     case 't':
  618.         func_style = FUNC_TRADITIONAL;
  619.         break;
  620.     case 'V':
  621.         fprintf(stderr, "%s\n", VERSION);
  622.         exit(EXIT_FAILURE);
  623.         break;
  624.     case 'v':
  625.         variables_out = TRUE;
  626.         break;
  627.     case 'o':
  628.         if (freopen(optarg, "w", stdout) == 0) {
  629.         perror(optarg);
  630.         exit(EXIT_FAILURE);
  631.           }
  632.         break;
  633.     case 'O':
  634.         if (freopen(optarg, "w", stderr) == 0) {
  635.         perror(optarg);
  636.         exit(EXIT_FAILURE);
  637.           }
  638.         break;
  639. #if OPT_LINTLIBRARY
  640.     case 'T':    /* emit typedefs */
  641.         types_out = TRUE;
  642.         break;
  643.     case 'l':
  644.         proto_style   = PROTO_LINTLIBRARY;
  645.         extern_out    = FALSE;
  646.         types_out     = TRUE;
  647.         variables_out = TRUE;
  648. # if !defined(vms) && !defined(MSDOS)
  649.         (void)strcat(cpp_opt, " -C");    /* pass-through comments */
  650. # endif
  651.         break;
  652. #endif
  653.     case 'x':
  654.         extern_in = MAX_INC_DEPTH;
  655.         break;
  656.     default:
  657.         usage();
  658.     }
  659.     }
  660.  
  661. #ifdef    vms
  662.     add_option("includes", cpp_include);
  663.     add_option("define",   cpp_defines);
  664.     add_option("undefine", cpp_undefns);
  665. #endif
  666.  
  667.     *pargc = argc;
  668.     *pargv = argv;
  669. }
  670.  
  671. int
  672. main (argc, argv)
  673. int argc;
  674. char *argv[];
  675. {
  676.     int i;
  677.     FILE *inf;
  678.     char *argv0;
  679.  
  680. #ifdef __EMX__
  681.     /* Expand file wild cards. */
  682.     _wildcard(&argc, &argv);
  683. #endif
  684.  
  685.     /* Get the program name from the 0th argument, stripping the pathname
  686.      * for readability.
  687.      */
  688.     progname = argv0 = xstrdup(argv[0]);
  689. #ifdef vms
  690.     for (i = strlen(progname)-1; i >= 0; i--) {
  691.         if (progname[i] == SQUARE_R
  692.      || progname[i] == ':') {
  693.         progname += (i + 1);
  694.         break;
  695.     } else if (progname[i] == '.') {
  696.         progname[i] = '\0';
  697.     }
  698.     }
  699. #else
  700.     for (i = strlen(progname)-1; i >= 0; i--) {
  701.     if (is_path_sep(progname[i])) {
  702.         progname += (i + 1);
  703.         break;
  704. # if defined(MSDOS) || defined(OS2)
  705.     } else if (progname[i] == '.') {
  706.         progname[i] = '\0';
  707. # endif
  708.     }
  709.     }
  710. #endif
  711.     argv[0] = progname;    /* do this so getopt is consistent with us */
  712.  
  713.     process_options(&argc, &argv);
  714.  
  715. #if OPT_LINTLIBRARY
  716.     if (lintLibrary()) {
  717.         put_string(stdout, "/* LINTLIBRARY */\n");
  718.     switch (func_style) {
  719.     case FUNC_ANSI:
  720.     case FUNC_BOTH:
  721.         lint_shadowed = TRUE;    /* e.g., ctype.h */
  722.         proto_style = PROTO_ANSI_LLIB;
  723.         break;
  724.     }
  725.     func_style = FUNC_NONE;
  726.     } else if (func_style == FUNC_UNKNOWN)
  727.     func_style = FUNC_NONE;
  728. #endif
  729.  
  730.     if (proto_macro && define_macro) {
  731.     printf("#if __STDC__ || defined(__cplusplus)\n");
  732.     printf("#define %s(s) s\n", macro_name);
  733.     printf("#else\n");
  734.     printf("#define %s(s) ()\n", macro_name);
  735.     printf("#endif\n\n");
  736.     }
  737.  
  738.     init_parser();
  739.     if (optind == argc) {
  740.     if (func_style != FUNC_NONE) {
  741.         proto_style = PROTO_NONE;
  742.         variables_out = FALSE;
  743.         file_comments = FALSE;
  744.     }
  745.     process_file(stdin, "stdin");
  746.     pop_file(FALSE);
  747.     } else {
  748.     if (!optind)
  749.         optind++;
  750.     for (i = optind; i < argc; ++i) {
  751. #ifdef CPP
  752. # if CPP_DOES_ONLY_C_FILES
  753.         /*
  754.          * GCC (and possibly other compilers) don't pass-through the ".l"
  755.          * and ".y" files to the C preprocessor stage.  Fix this by
  756.          * temporarily linking the input file to a temporary-file with a
  757.          * ".c" suffix.
  758.          *
  759.          * Of course, this solution assumes that the input directory is
  760.          * writeable.
  761.          */
  762.         char temp[BUFSIZ];
  763.         char *s = strcpy(temp, argv[i]);
  764. #  if HAVE_LINK
  765.         int len = strlen(temp);
  766.         s += len - 1;
  767.         if ((len > 2)
  768.          && (s[-1] == '.')
  769.          && (*s == 'l' || *s == 'y')) {
  770.         while (s != temp && s[-1] != '/')
  771.             s--;
  772.         (void)strcpy(s, "XXXXXX.c");
  773.             mktemp(temp);
  774.             if (link(argv[i], temp) < 0)
  775.             (void)strcpy(temp, argv[i]);
  776.         }
  777. #  endif
  778. #  define FileName temp
  779. # else
  780. #  define FileName argv[i]
  781. #  ifdef vms
  782.         char temp[BUFSIZ];
  783.         (void)strcpy(temp, FileName);
  784. #  endif
  785. # endif
  786.         if (func_style == FUNC_NONE && cpp != NULL) {
  787. #ifdef vms
  788.         /*
  789.          * Assume the 'cpp' command contains a "%s" for the name of
  790.          * the file that we're writing to.
  791.          */
  792.         sprintf(cpp_cmd, cpp,
  793.             mktemp(strcpy(temp, "sys$scratch:XXXXXX.i")));
  794.         sprintf(cpp_cmd + strlen(cpp_cmd), "%s %s", cpp_opt, FileName);
  795.         system(cpp_cmd);
  796.         inf = fopen(temp, "r");
  797. #else
  798.         sprintf(cpp_cmd, "%s%s %s", cpp, cpp_opt, FileName);
  799.         inf = popen(cpp_cmd, "r");
  800. #endif
  801.         if (inf == NULL) {
  802.             fprintf(stderr, "%s: error running %s\n", progname,
  803.              cpp_cmd);
  804.             continue;
  805.         }
  806.         } else {
  807.         if ((inf = fopen(argv[i], "r")) == NULL) {
  808.             fprintf(stderr, "%s: cannot read file %s\n", progname,
  809.              argv[i]);
  810.             continue;
  811.         }
  812.         }
  813. #else
  814.         if ((inf = fopen(argv[i], "r")) == NULL) {
  815.         fprintf(stderr, "%s: cannot read file %s\n", progname, argv[i]);
  816.         continue;
  817.         }
  818. #endif
  819.         process_file(inf, argv[i]);
  820. #ifdef CPP
  821.         if (func_style == FUNC_NONE && cpp != NULL) {
  822. #ifdef vms
  823.         fclose(inf);
  824. #else
  825.         pclose(inf);
  826. #endif
  827. #if CPP_DOES_ONLY_C_FILES || defined(vms)
  828.         if (strcmp(argv[i], temp)) {
  829.             (void)unlink(temp);
  830.         }
  831.         pop_file(TRUE);
  832. #endif
  833.         } else {
  834.         pop_file(FALSE);
  835.         }
  836. #else    /* no CPP defined */
  837.         pop_file(FALSE);
  838. #endif
  839.     }
  840.     }
  841.  
  842.     if (proto_macro && define_macro) {
  843.     printf("\n#undef %s\n", macro_name);
  844.     }
  845.  
  846. #ifdef NO_LEAKS
  847. # ifdef CPP
  848.     if (cpp_opt != 0) free(cpp_opt);
  849.     if (cpp_cmd != 0) free(cpp_cmd);
  850. #  ifdef vms
  851.     if (cpp_include != 0) free(cpp_include);
  852.     if (cpp_defines != 0) free(cpp_defines);
  853.     if (cpp_undefns != 0) free(cpp_undefns);
  854. #  endif
  855. # endif
  856.     while (--num_inc_dir > 1) {
  857.     free(inc_dir[num_inc_dir]);
  858.     }
  859.     free_parser();
  860. # if OPT_LINTLIBRARY
  861.     free_lintlibs();
  862. # endif
  863.  
  864. # ifdef DOALLOC
  865.     show_alloc();
  866. # endif
  867.     free(argv0);
  868. #endif
  869.  
  870.     return EXIT_SUCCESS;
  871. }
  872.  
  873. /* Intercept 'exit()' for debugging.  (The Linux libc uses malloc/free in
  874.  * 'exit()', so we cannot get a trace unless we resort to this hack ;-)
  875.  */
  876. #if HAVE_LIBDBMALLOC
  877. #undef exit
  878. void ExitProgram(code)
  879. int code;
  880. {
  881.     extern int malloc_errfd;    /* FIXME: should be in dbmalloc.h */
  882.     malloc_dump(malloc_errfd);
  883.     exit(code);
  884. }
  885. #endif
  886.