home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / c2man-2.0pl33.lha / c2man-2.0 / amiga / c2man.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-24  |  25.3 KB  |  907 lines

  1. /* $Id: c2man.c,v 2.0.1.35 1994/10/06 06:05:26 greyham Exp $
  2.  *
  3.  * C Manual page generator.
  4.  * Reads C source code and outputs manual pages.
  5.  */
  6. #include <ctype.h>
  7. #include <errno.h>
  8.  
  9. #include "c2man.h"
  10. #include "enum.h"
  11. #include "strconcat.h"
  12. #include "strappend.h"
  13. #include "manpage.h"
  14. #include "output.h"
  15. #include "patchlevel.h"
  16.  
  17. #ifdef I_FCNTL
  18. #include <fcntl.h>
  19. #endif
  20.  
  21. #ifdef I_SYS_FILE
  22. #include <sys/file.h>
  23. #endif
  24.  
  25. #include <sys/stat.h>
  26. #include <signal.h>
  27.  
  28. /* getopt declarations */
  29. extern int getopt();
  30. extern char *optarg;
  31. extern int optind;
  32.  
  33. /* lex declarations */
  34. extern FILE *yyin;      /* lex input stream */
  35.  
  36. /* Name of the program */
  37. const char *progname = "c2man";
  38.  
  39. /* Program options */
  40.  
  41. /* TRUE if static declarations are also output. */
  42. boolean static_out = FALSE;
  43.  
  44. /* TRUE if variable declarations are output. */
  45. boolean variables_out = FALSE;
  46.  
  47. /* TRUE if formal parameter promotion is enabled. */
  48. boolean promote_param = TRUE;
  49.  
  50. /* String output before prototype declaration specifiers */
  51. const char *decl_spec_prefix = "";
  52.  
  53. /* String output before prototype declarator */
  54. const char *declarator_prefix = " ";
  55.  
  56. /* String output after prototype declarator */
  57. const char *declarator_suffix = "\n";
  58.  
  59. /* String output before the first parameter in a function prototype */
  60. const char *first_param_prefix = "\n\t";
  61.  
  62. /* String output before each subsequent parameter in a function prototype */
  63. const char *middle_param_prefix = "\n\t";
  64.  
  65. /* String output after the last parameter in a function prototype */
  66. const char *last_param_suffix = "\n";
  67.  
  68. /* Directory to write output files in */
  69. char *output_dir = NULL;
  70.  
  71. /* Name of the manual */
  72. char *manual_name = NULL;
  73.  
  74. /* Section for manual page */
  75. const char *manual_section = NULL;
  76.  
  77. /* prefix for generated #include lines */
  78. char *header_prefix = NULL;
  79.  
  80. /* list of include file specified by user */
  81. IncludeFile *first_include;
  82. static IncludeFile **last_next_include = &first_include;
  83.  
  84. /* list of excluded sections specified by user */
  85. ExcludeSection *first_excluded_section;
  86. static ExcludeSection **last_next_excluded_section = &first_excluded_section;
  87.  
  88. /* do we group related stuff into one file? */
  89. boolean group_together;
  90.  
  91. /* was terse description read from file or command line option? */
  92. boolean terse_specified;
  93.  
  94. /* terse description when grouped together */
  95. char *group_terse = NULL;
  96.  
  97. /* should we always document parameters, even if it's only "Not Documented" */
  98. boolean always_document_params = TRUE;
  99.  
  100. /* default output info for each object type */
  101. struct Output_Object_Info output_object[_OBJECT_NUM] =
  102. {
  103. #if 0
  104.     {'c', "class"},
  105.     {'s', "struct"},
  106.     {'e', "enum"},
  107.     {'t', "typedef"},
  108. #endif
  109.     {'f', "function"},
  110.     {'v', "variable"},
  111.     {'F', "static function"},
  112.     {'V', "static variable"}
  113. };
  114.  
  115. /* Include file directories */
  116. #ifdef MSDOS
  117. int num_inc_dir = 1;
  118. const char *inc_dir[MAX_INC_DIR] = { ".\\" };
  119. #elif AMIGA
  120. int num_inc_dir = 1;
  121. const char *inc_dir[MAX_INC_DIR] = { "include:" };
  122. #else
  123. int num_inc_dir = 2;
  124. const char *inc_dir[MAX_INC_DIR] = { "./", "/usr/include/" };
  125. #endif
  126.  
  127. /* total number of errors encountered */
  128. int errors;
  129.  
  130. /* name of the base file being processed; NULL = stdin */
  131. const char *basefile;
  132. Time_t basetime;        /* modification time of base file */
  133. boolean inbasefile;     /* are we parsing in that base file? */
  134.  
  135. /* is the base file a header file? */
  136. boolean header_file;
  137.  
  138. #ifdef AMIGA
  139. struct Output *output = &autodoc_output;
  140. #else
  141. /* use nroff output by default */
  142. struct Output *output = &nroff_output;
  143. #endif
  144. /* should we generate the output file named after the input file? */
  145. boolean use_input_name = FALSE;
  146.  
  147. /* should we generate embeddable files? */
  148. boolean make_embeddable = FALSE;
  149.  
  150. #define USE_CPP
  151. #ifdef USE_CPP
  152. const char *cpp_cmd = CPP_FILE_COM;
  153. #if defined(MSDOS)
  154. #include "popen.h"
  155. #define popen(c,m)      os_popen(c,m)
  156. #define pclose(f)       os_pclose(f)
  157. #else
  158. #if defined (_MSC_VER)
  159. #define popen(c,m)      _popen(c,m)
  160. #define pclose(f)       _pclose(f)
  161. #endif
  162. #endif
  163. #endif
  164.  
  165. boolean verbose = FALSE;
  166.  
  167. /* can cpp read standard input? */
  168. static boolean cppcanstdin
  169. #ifdef CPP_CAN_STDIN
  170.                             = 1
  171. #endif
  172. ;
  173. /* does cpp ignore header files */
  174. static boolean cppignhdrs
  175. #ifdef CPP_IGN_HDRS
  176.                             = 1
  177. #endif
  178. ;
  179.  
  180. /* nifty little function for handling I/O errors */
  181. void my_perror(action, filename)
  182. const char *action, *filename;
  183. {
  184.     int err = errno;
  185.     fprintf(stderr,"%s: %s ", progname, action);
  186.     errno = err;
  187.     perror(filename);
  188. }
  189.  
  190. /* write the #include lines as specified by the user */
  191. void print_includes(f)
  192. FILE *f;
  193. {
  194.     IncludeFile *incfile;
  195.     
  196.     for (incfile = first_include; incfile; incfile=incfile->next)
  197.     {
  198.         char *name = incfile->name;
  199.         boolean surrounded = *name == '"' || *name == '<';
  200.         
  201.         fputs("#include ", f);
  202.         if (!surrounded)        fputc('<',f);
  203.         fputs(name, f);
  204.         if (!surrounded)        fputc('>',f);
  205.         fputc('\n',f);
  206.     }
  207. }
  208.  
  209. void outmem()
  210. {
  211.     fprintf(stderr,"%s: Out of memory!\n", progname);
  212.     exit(1);
  213. }
  214.  
  215. #ifndef DBMALLOC
  216. void *safe_malloc(size)
  217. size_t size;
  218. {
  219.     void *mem;
  220.  
  221.     if ((mem = (void *)malloc(size)) == NULL)
  222.         outmem();
  223.  
  224.     return mem;
  225. }
  226. #endif
  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 = strduplicate(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 't':
  249.                 *put++ = '\t';
  250.                 ++get;
  251.                 break;
  252.             default:
  253.                 if (*get != '\0')
  254.                     *put++ = *get++;
  255.             }
  256.         } else {
  257.             *put++ = *get++;
  258.         }
  259.     }
  260.     *put = *get;
  261.     return result;
  262. }
  263.  
  264. /* Output usage message and exit.
  265.  */
  266. static void
  267. usage ()
  268. {
  269.     int i;
  270.  
  271.     fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
  272.     fputs(" -o directory\twrite output files in directory\n",stderr);
  273.     fputs(" -p\t\tdisable prototype promotion\n", stderr);
  274.     fputs(" -s\t\toutput static declarations\n", stderr);
  275.     fputs(" -v\t\toutput variable declarations\n", stderr);
  276.     fputc('\n', stderr);
  277.     fputs(" -i incfile\n", stderr);
  278.     fputs(" -i \"incfile\"\n", stderr);
  279.     fputs(" -i <incfile>\tadd #include for incfile to SYNOPSIS\n",
  280.                                                                     stderr);
  281.     fputc('\n', stderr);
  282.     fputs(" -H prefix\tspecify prefix for #include in SYNOPSIS\n", stderr);
  283.     fputc('\n', stderr);
  284.     fputs(" -g\n", stderr);
  285.     fputs(" -G terse\tgroup info from each file into a single page\n",
  286.                                                                     stderr);
  287.     fputs(" -e\t\tmake embeddable files\n", stderr);
  288.     fputc('\n', stderr);
  289.     fputs(" -l ", stderr);
  290. #ifdef HAS_LINK
  291.     fputs("h|", stderr);
  292. #endif
  293. #ifdef HAS_SYMLINK
  294.     fputs("s|", stderr);
  295. #endif
  296.     fputs("f|n|r\t", stderr);
  297.     fputs("linking for grouped pages: ", stderr);
  298. #ifdef HAS_LINK
  299.                   fputs("hard, ", stderr);
  300. #endif
  301. #ifdef HAS_SYMLINK
  302.                                         fputs("soft, ", stderr);
  303. #endif
  304.                                         fputs("file, none or remove\n", stderr);
  305.     fputs(" -n\t\tName output file after input source file\n", stderr);
  306.     fputs(" -L\t\tLazy: Be silent about undocumented parameters\n",
  307.                                                                     stderr);
  308. #ifdef AMIGA
  309.     fputs(" -T n|l|h|t|a[,options]\tselect typesetting output format: nroff, LaTeX, HTML ,TeXinfo or AutoDoc\n",
  310.                                                                     stderr);
  311.     autodoc_output.print_options();
  312. #else
  313.     fputs(" -T n|l|h|t[,options]\tselect typesetting output format: nroff, LaTeX, HTML or TeXinfo\n",
  314.                                                                     stderr);
  315. #endif
  316.     nroff_output.print_options();
  317.     latex_output.print_options();
  318.     html_output.print_options();
  319.     texinfo_output.print_options();
  320.  
  321.     fputs(" -M name\tset name of the manual in which the page goes\n",
  322.                                                                     stderr);
  323.     fputs(" -x section\texclude section from ouput\n", stderr);
  324.     fputc('\n', stderr);
  325.     fputs(" -D name[=value]\n", stderr);
  326.     fputs(" -U name\n", stderr);
  327.     fputs(" -I directory\tC preprocessor options\n", stderr);
  328.     fputc('\n', stderr);
  329.     fputs(" -F template\tset prototype template in the form ", stderr);
  330.                                     fputs("\"int f (a, b)\"\n",stderr);
  331.     fputs(" -P preprocessor\tAlternate C preprocessor ", stderr);
  332.                                     fputs("(e.g., \"gcc -E -C\")\n", stderr);
  333.     fputs(" -V\t\tbe verbose and print version information\n", stderr);
  334.     fputs(" -S section\tset the section for the manual page (default = 3)\n",
  335.                                                                     stderr);
  336.     fputs(" -O ", stderr);
  337.     for (i = 0; i < _OBJECT_NUM; i++)
  338.         fputc(output_object[i].flag, stderr);
  339.     fputs("[subdir][.ext]", stderr);
  340.     fputs("\tOutput control over different object types:\n\t\t", stderr);
  341.     for (i = 0; i < _OBJECT_NUM; i++)
  342.     {
  343.         fputs(output_object[i].name, stderr);
  344.         if (i <= _OBJECT_NUM - 2)
  345.             fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  346.     }
  347.     fputs(".\n", stderr);
  348.     exit(1);
  349. }
  350.  
  351. /* name of the temporary file; kept here so we can blast it if hit with ctrl-C
  352.  */
  353. static char temp_name[20];
  354. Signal_t (*old_interrupt_handler)();
  355.  
  356. /* ctrl-C signal handler for use when we have a temporary file */
  357. static Signal_t interrupt_handler(sig)
  358. int sig;
  359. {
  360.     unlink(temp_name);
  361.     exit(128 + sig);
  362. }
  363.  
  364. /* open a unique temporary file.
  365.  * To be universally accepted by cpp's, the file's name must end in .c; so we
  366.  * can't use mktemp, tmpnam or tmpfile.
  367.  * returns an open stream & sets ret_name to the name.
  368.  */
  369. FILE *open_temp_file()
  370. {
  371.     int fd;
  372.     long n = getpid();
  373.     FILE *tempf;
  374.     boolean remove_temp_file();
  375.  
  376.     /* keep generating new names until we hit one that does not exist */
  377.     do
  378.     {
  379.         /* ideally we'd like to put the temporary file in /tmp, but it must go
  380.          * in the current directory because when cpp processes a #include, it
  381.          * looks in the same directory as the file doing the include; so if we
  382.          * use /tmp/blah.c to fake reading fred.h via `#include "fred.h"', cpp
  383.          * will look for /tmp/fred.h, and fail.
  384.          */
  385.         sprintf(temp_name,"c2man%ld.c",n++ % 1000000);
  386.     }
  387.     while((fd =
  388. #ifdef HAS_OPEN3
  389.         open(temp_name,O_WRONLY|O_CREAT|O_EXCL,0666)
  390. #else
  391.         creat(temp_name,O_EXCL|0666)            /* do it the old way */
  392. #endif
  393.                                                 ) == -1
  394.                                                         && errno == EEXIST);
  395.  
  396.     /* install interrupt handler to remove the temporary file */
  397.     old_interrupt_handler = signal(SIGINT, interrupt_handler);
  398.  
  399.     /* convert it to a stream */
  400.     if ((fd == -1 && errno != EEXIST) || (tempf = fdopen(fd, "w")) == NULL)
  401.     {
  402.         my_perror("error fdopening temp file",temp_name);
  403.         remove_temp_file();
  404.         return NULL;
  405.     }
  406.  
  407.     return tempf;
  408. }
  409.  
  410. /* remove the temporary file & restore ctrl-C handler.
  411.  * returns FALSE in the event of failure.
  412.  */
  413. boolean remove_temp_file()
  414. {
  415.     int ok = unlink(temp_name) == 0;    /* this should always succeed */
  416.     signal(SIGINT, old_interrupt_handler);
  417.     return ok;
  418. }
  419.  
  420. /* process the specified source file through the pre-processor.
  421.  * This is a lower level routine called by both process_stdin and process_file
  422.  * to actually get the work done once any required temporary files have been
  423.  * generated.
  424.  */
  425. int process_file_directly(base_cpp_cmd, name)
  426. const char *base_cpp_cmd;
  427. const char *name;
  428. {
  429.     char *full_cpp_cmd;
  430.  
  431. #ifdef DEBUG
  432.     fprintf(stderr,"process_file_directly: %s, %s\n", base_cpp_cmd, name);
  433. #endif
  434.  
  435. #ifdef USE_CPP
  436.     full_cpp_cmd = strconcat(base_cpp_cmd, " ", name, NULLCP);
  437.     if (verbose)
  438.         fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  439.  
  440.     if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  441.         my_perror("error running", base_cpp_cmd);
  442.         free(full_cpp_cmd);
  443.         return 0;
  444.     }
  445. #else
  446.     if (verbose)        fprintf(stderr,"%s: reading %s\n", progname, name);
  447.     if (name && freopen(name, "r", yyin) == NULL)
  448.     {
  449.         my_perror("cannot open", name);
  450.         return 0;
  451.     }
  452. #endif
  453.  
  454.     parse_file(name);
  455.  
  456. #ifdef USE_CPP
  457.     free(full_cpp_cmd);
  458.     if (pclose(yyin) & 0xFF00)
  459.         return 0;
  460. #else
  461.     if (fclose(yyin))
  462.     {
  463.         my_perror("error closing", name);
  464.         return 0;
  465.     }
  466. #endif
  467.  
  468.     return !errors;
  469. }
  470.  
  471. /* process a specified file */
  472. int process_file(base_cpp_cmd, name)
  473. const char *base_cpp_cmd;
  474. const char *name;
  475. {
  476.     char *period;
  477.     struct stat statbuf;
  478.     
  479. #ifdef DEBUG
  480.     fprintf(stderr,"process_file: %s, %s\n", base_cpp_cmd, name);
  481. #endif
  482.     basefile = name;
  483.     header_file = (period = strrchr(name,'.')) &&
  484.                                         (period[1] == 'h' || period[1] == 'H');
  485.  
  486.     /* use the file's date as the date in the manual page */
  487.     if (stat(name,&statbuf) != 0)
  488.     {
  489.         my_perror("can't stat", name);
  490.         return 0;
  491.     }
  492.     basetime = statbuf.st_mtime;
  493.  
  494.     /* should we do this via a temporary file?
  495.      * Only if it's a header file and either CPP ignores them, or the user
  496.      * has specified files to include.
  497.      *
  498.      * For HP/Apollo (SR10.3, CC 6.8), we must always use a temporary file,
  499.      * because its compiler recognizes the special macro "__attribute(p)",
  500.      * which we cannot redefine in the command line because it has parameters.
  501.      */
  502. #ifndef apollo
  503.     if (header_file && (cppignhdrs || first_include))
  504. #endif
  505.     {
  506.         FILE *tempf;
  507.         int ret;
  508.  
  509.         if (verbose)
  510.             fprintf(stderr, "%s: preprocessing via temporary file\n", progname);
  511.  
  512.         if ((tempf = open_temp_file()) == NULL)
  513.             return 0;
  514.  
  515.         print_includes(tempf);
  516.         if (verbose)    print_includes(stderr);
  517.  
  518. #ifdef apollo
  519.         fprintf(tempf,"#define __attribute(p)\n", basefile);
  520. #endif
  521.         fprintf(tempf,"#include \"%s\"\n", basefile);
  522.         if (verbose)    fprintf(stderr,"#include \"%s\"\n", basefile);
  523.  
  524.         if (fclose(tempf) == EOF)
  525.         {
  526.             my_perror("error closing temp file", temp_name);
  527.             remove_temp_file();
  528.             return 0;
  529.         }
  530.  
  531.         /* since we're using a temporary file, it's not the base file */
  532.         inbasefile = 0;
  533.         ret = process_file_directly(base_cpp_cmd, temp_name);
  534.         remove_temp_file();
  535.         return ret;
  536.     }
  537.  
  538.     /* otherwise, process it directly */
  539.     inbasefile = 1;
  540.  
  541.     return process_file_directly(base_cpp_cmd,name);
  542. }
  543.  
  544. /* process the thing on the standard input */
  545. int process_stdin(base_cpp_cmd)
  546. const char *base_cpp_cmd;
  547. {
  548.     if (isatty(fileno(stdin)))
  549.         fprintf(stderr,"%s: reading standard input\n", progname);
  550.  
  551.     header_file = 0;    /* assume it's not since it's from stdin */
  552.     basefile = NULL;
  553.  
  554.     /* use the current date in the man page */
  555.     basetime = time((Time_t *)NULL);
  556.  
  557.     inbasefile = 1;             /* reading stdin, we start in the base file */
  558.  
  559.     /* always use a temp file if the preprocessor can't read stdin, otherwise
  560.      * only use one if the user specified files for inclusion.
  561.      */
  562.     if (!cppcanstdin || first_include)  /* did user specify include files? */
  563.     {
  564.         FILE *tempf;
  565.         int c, ret;
  566.  
  567.         if (verbose)
  568.             fprintf(stderr,"%s: reading stdin to a temporary file\n", progname);
  569.  
  570.         if ((tempf = open_temp_file()) == NULL)
  571.             return 0;
  572.  
  573.         print_includes(tempf);
  574.         if (verbose)    print_includes(stderr);
  575.         fprintf(tempf,"#line 1 \"stdin\"\n");
  576.  
  577.         while ((c = getchar()) != EOF)
  578.             putc(c,tempf);
  579.  
  580.         if (fclose(tempf) == EOF)
  581.         {
  582.             my_perror("error closing temp file", temp_name);
  583.             remove_temp_file();
  584.             return 0;
  585.         }
  586.         ret = process_file_directly(base_cpp_cmd, temp_name);
  587.         remove_temp_file();
  588.         return ret;
  589.     }
  590.     else
  591.     {
  592.         char *full_cpp_cmd = strconcat(base_cpp_cmd," ", CPP_STDIN_FLAGS,
  593.                                                                    NULLCP);
  594.     
  595.         if (verbose)
  596.             fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  597.     
  598.         if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  599.             my_perror("error running", full_cpp_cmd);
  600.             return 0;
  601.         }
  602.     
  603.         parse_file(basefile);
  604.     
  605.         free(full_cpp_cmd);
  606.         if (pclose(yyin) & 0xFF00)
  607.             return 0;
  608.     
  609.         return !errors;
  610.     }
  611. }
  612.  
  613. int
  614. main (argc, argv)
  615. int argc;
  616. char **argv;
  617. {
  618.     int i, c, ok = 0;
  619.     char *s, cbuf[2];
  620.     const char *base_cpp_cmd;
  621.     IncludeFile *includefile;
  622.     ExcludeSection *excludesection;
  623.     char *cpp_opts;
  624.     const char *default_section = "3";
  625. #ifdef HAS_LINK
  626.     enum LinkType link_type = LINK_HARD;        /* for -g/G */
  627. #else
  628.     enum LinkType link_type = LINK_FILE;
  629. #endif
  630.  
  631. #ifdef YYDEBUG
  632.     extern int yydebug;
  633. #endif
  634.  
  635.     /* initialise CPP options with -D__C2MAN__ */
  636.     cbuf[0] = VERSION + '0';
  637.     cbuf[1] = '\0';
  638. #ifdef VMS
  639.     cpp_opts = strconcat("-\"D__C2MAN__=", cbuf, "\"",NULLCP);
  640. #else
  641.     cpp_opts = strconcat("-D__C2MAN__=", cbuf, NULLCP);
  642. #ifdef NeXT
  643.     cpp_opts = strappend(cpp_opts, " -D_NEXT_SOURCE", NULLCP);
  644. #endif /* !NeXT */
  645. #endif /* !VMS  */
  646.  
  647.     /* Scan command line options. */
  648.     while ((c = getopt(argc, argv, "P:D:F:I:psU:Vvo:eM:H:G:gi:x:S:l:LT:nO:"))
  649.                                                                     != EOF)
  650.     {
  651.         switch (c) {
  652.         case 'I':
  653.         case 'D':
  654.         case 'U':
  655.             cbuf[0] = c; cbuf[1] = '\0';
  656.             if (cpp_opts)
  657.                 cpp_opts = strappend(cpp_opts," -",cbuf,optarg,NULLCP);
  658.             else
  659.                 cpp_opts = strconcat("-",cbuf,optarg,NULLCP);
  660.             break;
  661.         case 'P':
  662.             cpp_cmd = optarg;
  663.  
  664.             /* with no better info to go on, we have to assume that this
  665.              * preprocessor is minimally capable.
  666.              */
  667.             cppcanstdin = 0;
  668.             cppignhdrs = 1;
  669.             break;
  670.         case 'G':
  671.             group_terse = optarg;
  672.             terse_specified = TRUE;
  673.             /* FALLTHROUGH */
  674.         case 'g':
  675.             group_together = TRUE;
  676.             break;
  677.         case 'F':
  678.             s = escape_string(optarg);
  679.  
  680.             decl_spec_prefix = s;
  681.             while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  682.             if (*s == '\0') usage();
  683.             *s++ = '\0';
  684.             while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  685.             if (*s == '\0') usage();
  686.  
  687.             declarator_prefix = s;
  688.             while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  689.             if (*s == '\0') usage();
  690.             *s++ = '\0';
  691.             while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  692.             if (*s == '\0') usage();
  693.  
  694.             declarator_suffix = s;
  695.             while (*s != '\0' && *s != '(') ++s;
  696.             if (*s == '\0') usage();
  697.             *s++ = '\0';
  698.  
  699.             first_param_prefix = s;
  700.             while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  701.             if (*s == '\0') usage();
  702.             *s++ = '\0';
  703.             while (*s != '\0' && *s != ',') ++s;
  704.             if (*s == '\0') usage();
  705.  
  706.             middle_param_prefix = ++s;
  707.             while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  708.             if (*s == '\0') usage();
  709.             *s++ = '\0';
  710.             while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  711.             if (*s == '\0') usage();
  712.  
  713.             last_param_suffix = s;
  714.             while (*s != '\0' && *s != ')') ++s;
  715.             *s = '\0';
  716.  
  717.             break;
  718.         case 'p':
  719.             promote_param = FALSE;
  720.             break;
  721.         case 's':
  722.             static_out = TRUE;
  723.             break;
  724.         case 'V':
  725.             verbose = TRUE;
  726.             fprintf(stderr, "%s: Version %d, Patchlevel %d\n",
  727.                                         progname, VERSION, PATCHLEVEL);
  728.             break;
  729.         case 'v':
  730.             variables_out = TRUE;
  731.             break;
  732.         case 'o':
  733.             output_dir = optarg;
  734.             break;
  735.         case 'M':
  736.             manual_name = optarg;
  737.             break;
  738.         case 'H':
  739.             header_prefix = optarg;
  740.             break;
  741.         case 'i':
  742.             *last_next_include = includefile =
  743.                             (IncludeFile *)safe_malloc(sizeof *includefile);
  744.             includefile->name = optarg;
  745.             includefile->next = NULL;
  746.             last_next_include = &includefile->next;
  747.             break;
  748.         case 'x':
  749.             *last_next_excluded_section = excludesection =
  750.                             (ExcludeSection *)safe_malloc(sizeof *excludesection);
  751.             excludesection->name = optarg;
  752.             excludesection->next = NULL;
  753.             last_next_excluded_section = &excludesection->next;
  754.             break;
  755.         case 'S':
  756.             manual_section = optarg;
  757.             break;
  758.         case 'l':
  759.             switch(optarg[0])
  760.             {
  761. #ifdef HAS_LINK
  762.             case 'h':   link_type = LINK_HARD;  break;
  763. #endif
  764. #ifdef HAS_SYMLINK
  765.             case 's':   link_type = LINK_SOFT;  break;
  766. #endif
  767.             case 'f':   link_type = LINK_FILE;  break;
  768.             case 'n':   link_type = LINK_NONE;  break;
  769.             case 'r':   link_type = LINK_REMOVE;break;
  770.             default:    usage();
  771.             }
  772.             break;
  773.         case 'e':
  774.             make_embeddable = TRUE;
  775.             break;
  776.         case 'n':
  777.             use_input_name = TRUE;
  778.             break;
  779.         case 'L':
  780.             always_document_params = FALSE;
  781.             break;
  782.         case 'T':
  783.             switch(optarg[0])
  784.             {
  785.             case 'n':   output = &nroff_output; default_section = "3";
  786.                         break;
  787.             case 'l':   output = &latex_output; default_section = "tex";
  788.                         break;
  789.             case 't':   output = &texinfo_output; default_section = "texi";
  790.                         break;
  791.             case 'h':   output = &html_output; default_section = "html";
  792.                         break;
  793.             case 'a':   output = &autodoc_output; default_section = "doc";
  794.                         break;
  795.             default:    usage();
  796.             }
  797.             s = strtok(&optarg[1], ",");
  798.             if (s && *output->parse_option == NULL) usage();
  799.             while(s)
  800.             {
  801.               if (output->parse_option(s)) usage();
  802.               s = strtok(NULL, ",");
  803.             }
  804.             break;
  805.         case 'O':
  806.             for (i = 0; i < _OBJECT_NUM; i++)
  807.                 if (output_object[i].flag == optarg[0])
  808.                     break;
  809.  
  810.             if (i == _OBJECT_NUM)
  811.             {
  812.                 fprintf(stderr,"%s: -O option must specify one of:\n\t",
  813.                                                                 progname);
  814.                 for (i = 0; i < _OBJECT_NUM; i++)
  815.                 {
  816.                     fprintf(stderr,"%c (%s)", output_object[i].flag,
  817.                         output_object[i].name);
  818.                     if (i <= _OBJECT_NUM - 2)
  819.                         fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  820.                 }
  821.                 fprintf(stderr, ".\n");
  822.                 exit(1);
  823.             }
  824.  
  825.             if ((s = strchr(++optarg,'.')))     /* look for an extension */
  826.             {
  827.                 output_object[i].subdir = alloc_string(optarg, s);
  828.                 output_object[i].extension = strduplicate(s+1);
  829.             }
  830.             else
  831.                 output_object[i].subdir = strduplicate(optarg);
  832.  
  833.             break;
  834.         case '?':
  835.         default:
  836.             usage();
  837.         }
  838.     }
  839.  
  840.     /* make sure we have a manual section */
  841.     if (manual_section == NULL) manual_section = default_section;
  842.  
  843. #ifdef MALLOC_DEBUG
  844.     getchar();  /* wait so we can start up NeXT MallocDebug tool */
  845. #endif
  846. #ifdef YYDEBUG
  847.     yydebug = 1;
  848. #endif
  849.  
  850.     if (cpp_opts)
  851.     {
  852.         base_cpp_cmd = strconcat(cpp_cmd, " ", cpp_opts, NULLCP);
  853.         free(cpp_opts);
  854.     }
  855.     else
  856.         base_cpp_cmd = cpp_cmd;
  857.  
  858.     if (optind == argc) {
  859.         if (use_input_name)
  860.         {
  861.             fprintf(stderr,"%s: %s\n", progname,
  862.                 "cannot name output after input file if there isn't one!");
  863.             usage();
  864.         }
  865.         ok = process_stdin(base_cpp_cmd);
  866.     }    
  867.     else
  868.         for (i = optind; i < argc; ++i)
  869.             if (!(ok = process_file(base_cpp_cmd,argv[i])))     break;
  870.  
  871.     if (ok && firstpage)
  872.         output_manual_pages(firstpage,argc - optind, link_type);
  873.     free_manual_pages(firstpage);
  874.     destroy_enum_lists();
  875.  
  876.     if (cpp_opts)       free((char *)base_cpp_cmd);
  877.  
  878.     for (includefile = first_include; includefile;)
  879.     {
  880.         IncludeFile *next = includefile->next;
  881.         free(includefile);
  882.         includefile = next;
  883.     }
  884.  
  885.     for (excludesection = first_excluded_section; excludesection;)
  886.     {
  887.         ExcludeSection *next = excludesection->next;
  888.         free(excludesection);
  889.         excludesection = next;
  890.     }
  891.  
  892.     for (i = 0; i < _OBJECT_NUM; i++)
  893.     {
  894.         safe_free(output_object[i].subdir);
  895.         safe_free(output_object[i].extension);
  896.     }
  897.  
  898. #ifdef DBMALLOC
  899.     malloc_dump(2);
  900.     malloc_chain_check(1);
  901. #endif
  902. #ifdef MALLOC_DEBUG
  903.     sleep(1000000);
  904. #endif
  905.     return !ok;
  906. }
  907.