home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / OS2 / MAN11A.ZIP / src / man.c < prev    next >
C/C++ Source or Header  |  1994-01-05  |  29KB  |  1,424 lines

  1. /*
  2.  * man.c
  3.  *
  4.  * Copyright (c) 1990, 1991, John W. Eaton.
  5.  *
  6.  * You may distribute under the terms of the GNU General Public
  7.  * License as specified in the file COPYING that comes with the man
  8.  * distribution.  
  9.  *
  10.  * John W. Eaton
  11.  * jwe@che.utexas.edu
  12.  * Department of Chemical Engineering
  13.  * The University of Texas at Austin
  14.  * Austin, Texas  78712
  15.  */
  16.  
  17. #define MAN_MAIN
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <string.h>
  22. #ifndef _MSC_VER
  23. #include <sys/file.h>
  24. #endif
  25. #include <signal.h>
  26. #include "config.h"
  27. #include "gripes.h"
  28. #include "version.h"
  29.  
  30. #ifndef POSIX
  31. #include <unistd.h>
  32. #else
  33. #ifndef R_OK
  34. #define R_OK 4
  35. #endif
  36. #endif
  37.  
  38. #ifdef SECURE_MAN_UID
  39. extern uid_t getuid ();
  40. extern int setuid ();
  41. #endif
  42.  
  43. #ifdef STDC_HEADERS
  44. #include <stdlib.h>
  45. #else
  46. extern char *malloc ();
  47. extern char *getenv ();
  48. extern void free ();
  49. extern int system ();
  50. extern int strcmp ();
  51. extern int strncmp ();
  52. extern int exit ();
  53. extern int fflush ();
  54. extern int printf ();
  55. extern int fprintf ();
  56. extern FILE *fopen ();
  57. extern int fclose ();
  58. extern char *sprintf ();
  59. #endif
  60.  
  61. extern char *strdup ();
  62.  
  63. extern char **glob_vector ();
  64. extern char **glob_filename ();
  65. extern int access ();
  66. extern int unlink ();
  67. extern int system ();
  68. extern int chmod ();
  69. extern int is_newer ();
  70. extern int is_directory ();
  71. extern int do_system_command ();
  72.  
  73. char *prognam;
  74. static char *pager;
  75. static char *manp;
  76. static char *manpathlist[MAXDIRS];
  77. static char *section;
  78. static char *colon_sep_section_list;
  79. static char **section_list;
  80. static char *roff_directive;
  81. static int apropos;
  82. static int whatis;
  83. static int findall;
  84. static int print_where;
  85. static char nroff_cmd[] = NROFF;
  86. static char *nroff = nroff_cmd;
  87.  
  88. #ifdef ALT_SYSTEMS
  89. static int alt_system;
  90. static char *alt_system_name;
  91. #endif
  92.  
  93. static int troff = 0;
  94.  
  95. int debug;
  96.  
  97. #ifdef HAS_TROFF
  98. #ifdef ALT_SYSTEMS
  99. static char args[] = "M:P:S:adfhkm:p:tw?";
  100. #else
  101. #ifdef OS2
  102. static char args[] = "M:N:P:S:adfhkp:tw?";
  103. #else
  104. static char args[] = "M:P:S:adfhkp:tw?";
  105. #endif
  106. #endif
  107. #else
  108. #ifdef ALT_SYSTEMS
  109. static char args[] = "M:P:S:adfhkm:p:w?";
  110. #else
  111. static char args[] = "M:P:S:adfhkp:w?";
  112. #endif
  113. #endif
  114.  
  115. int
  116. main (argc, argv)
  117.      int argc;
  118.      char **argv;
  119. {
  120.   int status = 0;
  121.   char *nextarg;
  122.   char *tmp;
  123.   extern int optind;
  124.   extern char *mkprogname ();
  125.   char *is_section ();
  126.   char **get_section_list ();
  127.   void man_getopt ();
  128.   void do_apropos ();
  129.   void do_whatis ();
  130.   int man ();
  131.  
  132.   prognam = mkprogname (argv[0]);
  133.  
  134.   man_getopt (argc, argv);
  135.  
  136.   if (optind == argc)
  137.     gripe_no_name ((char *)NULL);
  138.  
  139.   section_list = get_section_list ();
  140.  
  141.   if (optind == argc - 1)
  142.     {
  143.       tmp = is_section (argv[optind]);
  144.  
  145.       if (tmp != NULL)
  146.     gripe_no_name (tmp);
  147.     }
  148.  
  149.   while (optind < argc)
  150.     {
  151.       nextarg = argv[optind++];
  152.  
  153.       /*
  154.        * See if this argument is a valid section name.  If not,
  155.        * is_section returns NULL.
  156.        */
  157.       tmp = is_section (nextarg);
  158.  
  159.       if (tmp != NULL)
  160.     {
  161.       section = tmp;
  162.  
  163.       if (debug)
  164.         fprintf (stderr, "\nsection: %s\n", section);
  165.  
  166.       continue;
  167.     }
  168.  
  169.       if (apropos)
  170.     do_apropos (nextarg);
  171.       else if (whatis)
  172.     do_whatis (nextarg);
  173.       else
  174.     {
  175.       status = man (nextarg);
  176.  
  177.       if (status == 0)
  178.         gripe_not_found (nextarg, section);
  179.     }
  180.     }
  181.   return status;
  182. }
  183.  
  184. void
  185. usage ()
  186. {
  187.   static char usage_string[1024] = "%s, version %s\n\n";
  188.  
  189. #ifdef HAS_TROFF
  190. #ifdef ALT_SYSTEMS
  191.   static char s1[] =
  192.     "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
  193.            [-m system] [-p string] name ...\n\n";
  194. #else
  195. #ifdef OS2
  196.   static char s1[] =
  197.     "usage: %s [-adfhktw] [section] [-M path] [-N nroff] [-P pager] [-S list]\n\
  198.            [-p string] name ...\n\n";
  199. #else
  200.   static char s1[] =
  201.     "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
  202.            [-p string] name ...\n\n";
  203. #endif
  204. #endif
  205. #else
  206. #ifdef ALT_SYSTEMS
  207.   static char s1[] =
  208.     "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
  209.            [-m system] [-p string] name ...\n\n";
  210. #else
  211.   static char s1[] =
  212.     "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
  213.            [-p string] name ...\n\n";
  214. #endif
  215. #endif
  216.  
  217. static char s2[] = "  a : find all matching entries\n\
  218.   d : print gobs of debugging information\n\
  219.   f : same as whatis(1)\n\
  220.   h : print this help message\n\
  221.   k : same as apropos(1)\n";
  222.  
  223.   strcat (usage_string, s1);
  224.   strcat (usage_string, s2);
  225.  
  226. #ifdef HAS_TROFF
  227.   strcat(usage_string, "  t : use troff to format pages for printing\n");
  228. #endif
  229.  
  230.   strcat(usage_string,
  231.      "  w : print location of man page(s) that would be displayed\n\n");
  232.  
  233.   fprintf (stderr, usage_string, prognam, version, prognam);
  234.  
  235.   fprintf(stderr,
  236.      "  M path   : set search path for manual pages to `path'\n");
  237. #ifdef OS2
  238.   fprintf(stderr, 
  239.      "  N nroff  : set nroff command (%s)\n", nroff);
  240. #endif
  241.   fprintf(stderr, "\
  242.   P pager  : use program `pager' to display pages\n\
  243.   S list   : colon separated section list\n");
  244.  
  245. #ifdef ALT_SYSTEMS
  246.   fprintf(stderr,
  247.      "  m system : search for alternate system's man pages\n";
  248. #endif
  249.  
  250.   fprintf(stderr, "\
  251.   p string : string tells which preprocessors to run\n\
  252.                e - [n]eqn(1)   p - pic(1)    t - tbl(1)\n\
  253.                g - grap(1)     r - refer(1)  v - vgrind(1)\n");
  254.   exit(1);
  255. }
  256.  
  257. char **
  258. add_dir_to_mpath_list (mp, p)
  259.      char **mp;
  260.      char *p;
  261. {
  262.   int status;
  263.  
  264.   status = is_directory (p);
  265.  
  266.   if (status < 0)
  267.     {
  268.       fprintf (stderr, "Warning: couldn't stat file %s!\n", p);
  269.     }
  270.   else if (status == 0)
  271.     {
  272.       fprintf (stderr, "Warning: %s isn't a directory!\n", p);
  273.     }
  274.   else if (status == 1)
  275.     {
  276.       if (debug)
  277.     fprintf (stderr, "adding %s to manpathlist\n", p);
  278.  
  279.       *mp++ = strdup (p);
  280.     }
  281.   return mp;
  282. }
  283.  
  284. /*
  285.  * Get options from the command line and user environment.
  286.  */
  287. void
  288. man_getopt (argc, argv)
  289.      register int argc;
  290.      register char **argv;
  291. {
  292.   register int c;
  293.   register char *p;
  294.   register char *end;
  295.   register char **mp;
  296.   extern char *optarg;
  297.   extern int getopt ();
  298.   extern void downcase ();
  299.   extern char *manpath ();
  300.  
  301. #ifdef OS2
  302.   if (NULL == (nroff = getenv("NROFF")))
  303.     nroff = (_osmode == DOS_MODE || _osmajor < 20) ? NROFF16 : nroff_cmd;
  304. #endif
  305.  
  306.   while ((c = getopt (argc, argv, args)) != EOF)
  307.     {
  308.       switch (c)
  309.     {
  310.     case 'M':
  311.       manp = strdup (optarg);
  312.       break;
  313. #ifdef OS2
  314.     case 'N':
  315.       nroff = optarg;
  316.       break;
  317. #endif
  318.     case 'P':
  319.       pager = strdup (optarg);
  320.       break;
  321.     case 'S':
  322.       colon_sep_section_list = strdup (optarg); 
  323.       break;
  324.     case 'a':
  325.       findall++;
  326.       break;
  327.     case 'd':
  328.       debug++;
  329.       break;
  330.     case 'f':
  331.       if (troff)
  332.         gripe_incompatible ("-f and -t");
  333.       if (apropos)
  334.         gripe_incompatible ("-f and -k");
  335.       if (print_where)
  336.         gripe_incompatible ("-f and -w");
  337.       whatis++;
  338.       break;
  339.     case 'k':
  340.       if (troff)
  341.         gripe_incompatible ("-k and -t");
  342.       if (whatis)
  343.         gripe_incompatible ("-k and -f");
  344.       if (print_where)
  345.         gripe_incompatible ("-k and -w");
  346.       apropos++;
  347.       break;
  348. #ifdef ALT_SYSTEMS
  349.     case 'm':
  350.       alt_system++;
  351.       alt_system_name = strdup (optarg);
  352.       break;
  353. #endif
  354.     case 'p':
  355.       roff_directive = strdup (optarg);
  356.       break;
  357. #ifdef HAS_TROFF
  358.     case 't':
  359.       if (apropos)
  360.         gripe_incompatible ("-t and -k");
  361.       if (whatis)
  362.         gripe_incompatible ("-t and -f");
  363.       if (print_where)
  364.         gripe_incompatible ("-t and -w");
  365.       troff++;
  366.       break;
  367. #endif
  368.     case 'w':
  369.       if (apropos)
  370.         gripe_incompatible ("-w and -k");
  371.       if (whatis)
  372.         gripe_incompatible ("-w and -f");
  373.       if (troff)
  374.         gripe_incompatible ("-w and -t");
  375.       print_where++;
  376.       break;
  377.     case 'h':
  378.     case '?':
  379.     default:
  380.       usage();
  381.       break;
  382.     }
  383.     }
  384.  
  385.   if (pager == NULL || *pager == '\0')
  386.     if ((pager = getenv ("PAGER")) == NULL)
  387.       pager = strdup (PAGER);
  388.  
  389.   if (debug)
  390.     fprintf (stderr, "\nusing %s as pager\n", pager);
  391.  
  392.   if (manp == NULL)
  393.     {
  394.       if ((manp = manpath (0)) == NULL)
  395.     gripe_manpath ();
  396.  
  397.       if (debug)
  398.     fprintf (stderr,
  399.          "\nsearch path for pages determined by manpath is\n%s\n\n",
  400.          manp);
  401.     }
  402.  
  403. #ifdef ALT_SYSTEMS
  404.   if (alt_system_name == NULL || *alt_system_name == '\0')
  405.     if ((alt_system_name = getenv ("SYSTEM")) != NULL)
  406.       alt_system_name = strdup (alt_system_name);
  407.  
  408.   if (alt_system_name != NULL && *alt_system_name != '\0')
  409.     downcase (alt_system_name);
  410. #endif
  411.  
  412.   /*
  413.    * Expand the manpath into a list for easier handling.
  414.    */
  415. #ifdef OS2
  416.   for (p = manp; p = strchr(p, '\\'); )
  417.     *p = '/';
  418. #endif
  419.   mp = manpathlist;
  420.   for (p = manp; ; p = end+1)
  421.     {
  422.       if ((end = strchr (p, PATHSEP)) != NULL)
  423.     *end = '\0';
  424.  
  425. #ifdef ALT_SYSTEMS
  426.       if (alt_system)
  427.     {
  428.       char buf[BUFSIZ];
  429.  
  430.       if (debug)
  431.         fprintf (stderr, "Alternate system `%s' specified\n",
  432.              alt_system_name);
  433.  
  434.       strcpy (buf, p);
  435.       strcat (buf, "/");
  436.       strcat (buf, alt_system_name);
  437.  
  438.       mp = add_dir_to_mpath_list (mp, buf);
  439.     }
  440.       else
  441.     {
  442.       mp = add_dir_to_mpath_list (mp, p);
  443.     }
  444. #else
  445.       mp = add_dir_to_mpath_list (mp, p);
  446. #endif
  447.       if (end == NULL)
  448.     break;
  449.  
  450.       *end = PATHSEP;
  451.     }
  452.   *mp = NULL;
  453. }
  454.  
  455. /*
  456.  * Check to see if the argument is a valid section number.  If the
  457.  * first character of name is a numeral, or the name matches one of
  458.  * the sections listed in section_list, we'll assume that it's a section.
  459.  * The list of sections in config.h simply allows us to specify oddly
  460.  * named directories like .../man3f.  Yuk. 
  461.  */
  462. char *
  463. is_section (name)
  464.      register char *name;
  465. {
  466.   register char **vs;
  467.  
  468.   for (vs = section_list; *vs != NULL; vs++)
  469.     if ((strcmp (*vs, name) == 0) || (isdigit (name[0])))
  470.       return strdup (name);
  471.  
  472.   return NULL;
  473. }
  474.  
  475. /*
  476.  * Handle the apropos option.  Cheat by using another program.
  477.  */
  478. void
  479. do_apropos (name)
  480.      register char *name;
  481. {
  482.   register int len;
  483.   register char *command;
  484.  
  485.   len = strlen (APROPOS) + strlen (name) + 2;
  486.  
  487.   if ((command = (char *) malloc(len)) == NULL)
  488.     gripe_alloc (len, "command");
  489.  
  490.   sprintf (command, "%s %s", APROPOS, name);
  491.  
  492.   (void) do_system_command (command);
  493.  
  494.   free (command);
  495. }
  496.  
  497. /*
  498.  * Handle the whatis option.  Cheat by using another program.
  499.  */
  500. void
  501. do_whatis (name)
  502.      register char *name;
  503. {
  504.   register int len;
  505.   register char *command;
  506.  
  507.   len = strlen (WHATIS) + strlen (name) + 2;
  508.  
  509.   if ((command = (char *) malloc(len)) == NULL)
  510.     gripe_alloc (len, "command");
  511.  
  512.   sprintf (command, "%s %s", WHATIS, name);
  513.  
  514.   (void) do_system_command (command);
  515.  
  516.   free (command);
  517. }
  518.  
  519. /*
  520.  * Change a name of the form ...man/man1/name.1 to ...man/cat1/name.1
  521.  * or a name of the form ...man/cat1/name.1 to ...man/man1/name.1
  522.  */
  523. char *
  524. convert_name (name, to_cat)
  525.      register char *name;
  526.      register int to_cat;
  527. {
  528.   register char *to_name;
  529.   register char *t1;
  530.   register char *t2 = NULL;
  531.  
  532. #ifdef DO_COMPRESS
  533.   if (to_cat)
  534.     {
  535.       int len = strlen (name) + strlen(COMPRESS_EXT) + 1;
  536.       to_name = (char *) malloc (len);
  537.       if (to_name == NULL)
  538.     gripe_alloc (len, "to_name");
  539.       strcpy (to_name, name);
  540.       strcat (to_name, COMPRESS_EXT);
  541.     }
  542.   else
  543.     to_name = strdup (name);
  544. #else
  545.   to_name = strdup (name);
  546. #endif
  547.  
  548.   t1 = strrchr (to_name, '/');
  549.   if (t1 != NULL)
  550.     {
  551.       *t1 = '\0';
  552.       t2 = strrchr (to_name, '/');
  553.       *t1 = '/';
  554.     }
  555.  
  556.   if (t2 == NULL)
  557.     gripe_converting_name (name, to_cat);
  558.  
  559.   if (to_cat)
  560.     {
  561.       *(++t2) = 'c';
  562.       *(t2+2) = 't';
  563.     }
  564.   else
  565.     {
  566.       *(++t2) = 'm';
  567.       *(t2+2) = 'n';
  568.     }
  569.  
  570.   if (debug)
  571.     fprintf (stderr, "to_name in convert_name () is: %s\n", to_name);
  572.  
  573.   return to_name;
  574. }
  575.  
  576. /*
  577.  * Try to find the man page corresponding to the given name.  The
  578.  * reason we do this with globbing is because some systems have man
  579.  * page directories named man3 which contain files with names like
  580.  * XtPopup.3Xt.  Rather than requiring that this program know about
  581.  * all those possible names, we simply try to match things like
  582.  * .../man[sect]/name[sect]*.  This is *much* easier.
  583.  *
  584.  * Note that globbing is only done when the section is unspecified.
  585.  */
  586. char **
  587. glob_for_file (path, section, name, cat)
  588.      register char *path;
  589.      register char *section;
  590.      register char *name;
  591.      register int cat;
  592. {
  593.   char pathname[BUFSIZ];
  594.   char **gf;
  595.  
  596.   if (cat)
  597.     sprintf (pathname, "%s/cat%s/%s.%s*", path, section, name, section);
  598.   else
  599.     sprintf (pathname, "%s/man%s/%s.%s*", path, section, name, section);
  600.  
  601.   if (debug)
  602.     fprintf (stderr, "globbing %s\n", pathname);
  603.  
  604.   gf = glob_filename (pathname);
  605.  
  606.   if ((gf == (char **) -1 || *gf == NULL) && isdigit (*section))
  607.     {
  608.       if (cat)
  609.     sprintf (pathname, "%s/cat%s/%s.%c*", path, section, name, *section);
  610.       else
  611.     sprintf (pathname, "%s/man%s/%s.%c*", path, section, name, *section);
  612.  
  613.       gf = glob_filename (pathname);
  614.     }
  615.   return gf;
  616. }
  617.  
  618. /*
  619.  * Return an un-globbed name in the same form as if we were doing
  620.  * globbing. 
  621.  */
  622. char **
  623. make_name (path, section, name, cat)
  624.      register char *path;
  625.      register char *section;
  626.      register char *name;
  627.      register int cat;
  628. {
  629.   register int i = 0;
  630.   static char *names[3];
  631.   char buf[BUFSIZ];
  632.  
  633.   if (cat)
  634.     sprintf (buf, "%s/cat%s/%s.%s", path, section, name, section);
  635.   else
  636.     sprintf (buf, "%s/man%s/%s.%s", path, section, name, section);
  637.  
  638.   if (access (buf, R_OK) == 0)
  639.     names[i++] = strdup (buf);
  640.  
  641.   /*
  642.    * If we're given a section that looks like `3f', we may want to try
  643.    * file names like .../man3/foo.3f as well.  This seems a bit
  644.    * kludgey to me, but what the hey...
  645.    */
  646.   if (section[1] != '\0')
  647.     {
  648.       if (cat)
  649.     sprintf (buf, "%s/cat%c/%s.%s", path, section[0], name, section);
  650.       else
  651.     sprintf (buf, "%s/man%c/%s.%s", path, section[0], name, section);
  652.  
  653.       if (access (buf, R_OK) == 0)
  654.     names[i++] = strdup (buf);
  655.     }
  656.  
  657.   names[i] = NULL;
  658.  
  659.   return &names[0];
  660. }
  661.  
  662. #ifdef DO_UNCOMPRESS
  663. char *
  664. get_expander (file)
  665.      char *file;
  666. {
  667.   char *expander = NULL;
  668.   int len = strlen (file);
  669.   int i;
  670.   UNCOMPRESS *u = uncompress;
  671.  
  672.   while (u->ext) {
  673.     if (0 < (i = len - strlen(u->ext)))
  674.       if (!strcmp(file + i, u->ext)) {
  675.     expander = u->prog;
  676.     break;
  677.       }
  678.     u++;
  679.   }
  680.   return expander;
  681. }
  682. #endif
  683.  
  684. /*
  685.  * Simply display the preformatted page.
  686.  */
  687. int
  688. display_cat_file (file)
  689.      register char *file;
  690. {
  691.   register int found;
  692.   char command[BUFSIZ];
  693.  
  694.   found = 0;
  695.  
  696.   if (access (file, R_OK) == 0)
  697.     {
  698. #ifdef DO_UNCOMPRESS
  699.       char *expander = get_expander (file);
  700.  
  701.       if (expander != NULL)
  702.     sprintf (command, "%s %s | %s", expander, file, pager);
  703.       else
  704.     sprintf (command, "%s %s", pager, file);
  705. #else
  706.       sprintf (command, "%s %s", pager, file);
  707. #endif
  708.  
  709.       found = do_system_command (command);
  710.     }
  711.   return found;
  712. }
  713.  
  714. /*
  715.  * Try to find the ultimate source file.  If the first line of the
  716.  * current file is not of the form
  717.  *
  718.  *      .so man3/printf.3s
  719.  *
  720.  * the input file name is returned.
  721.  */
  722. char *
  723. ultimate_source (name, path)
  724.      char *name;
  725.      char *path;
  726. {
  727.   FILE *fp;
  728.   char buf[BUFSIZ];
  729.   char ult[BUFSIZ];
  730.   char *beg;
  731.   char *end;
  732.  
  733.   strcpy (ult, name);
  734.   strcpy (buf, name);
  735.  
  736.  next:
  737.  
  738.   if ((fp = fopen (ult, "r")) == NULL)
  739.     return buf;
  740.  
  741.   if (fgets (buf, BUFSIZ, fp) == NULL)
  742.     return ult;
  743.  
  744.   if (strlen (buf) < 5)
  745.     return ult;
  746.  
  747.   beg = buf;
  748.   if (*beg++ == '.' && *beg++ == 's' && *beg++ == 'o')
  749.     {
  750.       while ((*beg == ' ' || *beg == '\t') && *beg != '\0')
  751.     beg++;
  752.  
  753.       end = beg;
  754.       while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
  755.     end++;
  756.  
  757.       *end = '\0';
  758.  
  759.       strcpy (ult, path);
  760.       strcat (ult, "/");
  761.       strcat (ult, beg);
  762.  
  763.       strcpy (buf, ult);
  764.  
  765.       goto next;
  766.     }
  767.  
  768.   if (debug)
  769.     fprintf (stderr, "found ultimate source file %s\n", ult);
  770.  
  771.   return ult;
  772. }
  773.  
  774. void
  775. add_directive (first, d, file, buf)
  776.      int *first;
  777.      char *d;
  778.      char *file;
  779.      char *buf;
  780. {
  781.   if (strcmp (d, "") != 0)
  782.     {
  783.       if (*first)
  784.     {
  785.       *first = 0;
  786.       strcpy (buf, d);
  787.       strcat (buf, " ");
  788.       strcat (buf, file);
  789.     }
  790.       else
  791.     {
  792.       strcat (buf, " | ");
  793.       strcat (buf, d);
  794.     }
  795.     }
  796. }
  797.  
  798. int
  799. parse_roff_directive (cp, file, buf)
  800.   char *cp;
  801.   char *file;
  802.   char *buf;
  803. {
  804.   char c;
  805.   int first = 1;
  806.   int tbl_found = 0;
  807.  
  808.   while ((c = *cp++) != '\0')
  809.     {
  810.       switch (c)
  811.     {
  812.     case 'e':
  813.  
  814.       if (debug)
  815.         fprintf (stderr, "found eqn(1) directive\n");
  816.  
  817.       if (troff)
  818.         add_directive (&first, EQN, file, buf);
  819.       else
  820.         add_directive (&first, NEQN, file, buf);
  821.  
  822.       break;
  823.  
  824.     case 'g':
  825.  
  826.       if (debug)
  827.         fprintf (stderr, "found grap(1) directive\n");
  828.  
  829.       add_directive (&first, GRAP, file, buf);
  830.  
  831.       break;
  832.  
  833.     case 'p':
  834.  
  835.       if (debug)
  836.         fprintf (stderr, "found pic(1) directive\n");
  837.  
  838.       add_directive (&first, PIC, file, buf);
  839.  
  840.       break;
  841.  
  842.     case 't':
  843.  
  844.       if (debug)
  845.         fprintf (stderr, "found tbl(1) directive\n");
  846.  
  847.       tbl_found++;
  848.       add_directive (&first, TBL, file, buf);
  849.       break;
  850.  
  851.     case 'v':
  852.  
  853.       if (debug)
  854.         fprintf (stderr, "found vgrind(1) directive\n");
  855.  
  856.       add_directive (&first, VGRIND, file, buf);
  857.       break;
  858.  
  859.     case 'r':
  860.  
  861.       if (debug)
  862.         fprintf (stderr, "found refer(1) directive\n");
  863.  
  864.       add_directive (&first, REFER, file, buf);
  865.       break;
  866.  
  867.     case ' ':
  868.     case '\t':
  869.     case '\n':
  870.  
  871.       goto done;
  872.  
  873.     default:
  874.  
  875.       return -1;
  876.     }
  877.     }
  878.  
  879.  done:
  880.  
  881.   if (first)
  882.     return 1;
  883.  
  884. #ifdef HAS_TROFF
  885.   if (troff)
  886.     {
  887.       strcat (buf, " | ");
  888.       strcat (buf, TROFF);
  889.     }
  890.   else
  891. #endif
  892.     {
  893.       strcat (buf, " | ");
  894.       strcat (buf, nroff);
  895.     }
  896.  
  897.   if (tbl_found && !troff && strcmp (COL, "") != 0)
  898.     {
  899.       strcat (buf, " | ");
  900.       strcat (buf, COL);
  901.     }
  902.  
  903.   return 0;
  904. }
  905.  
  906. char *
  907. make_roff_command (file)
  908.      char *file;
  909. {
  910.   FILE *fp;
  911.   char line [BUFSIZ];
  912.   static char buf [BUFSIZ];
  913.   int status;
  914.   char *cp;
  915.  
  916.   if (roff_directive != NULL)
  917.     {
  918.       if (debug)
  919.     fprintf (stderr, "parsing directive from command line\n");
  920.  
  921.       status = parse_roff_directive (roff_directive, file, buf);
  922.  
  923.       if (status == 0)
  924.     return buf;
  925.  
  926.       if (status == -1)
  927.     gripe_roff_command_from_command_line (file);
  928.     }
  929.  
  930.   if ((fp = fopen (file, "r")) != NULL)
  931.     {
  932.       cp = &line[0];
  933.       fgets (line, 100, fp);
  934.       if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ')
  935.     {
  936.       if (debug)
  937.         fprintf (stderr, "parsing directive from file\n");
  938.  
  939.       status = parse_roff_directive (cp, file, buf);
  940.  
  941.       fclose (fp);
  942.  
  943.       if (status == 0)
  944.         return buf;
  945.  
  946.       if (status == -1)
  947.         gripe_roff_command_from_file (file);
  948.     }
  949.     }
  950.   else
  951.     {
  952.       /*
  953.        * Is there really any point in continuing to look for
  954.        * preprocessor options if we can't even read the man page source? 
  955.        */
  956.       gripe_reading_man_file (file);
  957.       return NULL;
  958.     }
  959.  
  960.   if ((cp = getenv ("MANROFFSEQ")) != NULL)
  961.     {
  962.       if (debug)
  963.     fprintf (stderr, "parsing directive from environment\n");
  964.  
  965.       status = parse_roff_directive (cp, file, buf);
  966.  
  967.       if (status == 0)
  968.     return buf;
  969.  
  970.       if (status == -1)
  971.     gripe_roff_command_from_env ();
  972.     }
  973.  
  974.   if (debug)
  975.     fprintf (stderr, "using default preprocessor sequence\n");
  976.  
  977. #ifdef HAS_TROFF
  978.   if (troff)
  979.     {
  980.       if (strcmp (TBL, "") != 0)
  981.     {
  982.       strcpy (buf, TBL);
  983.       strcat (buf, " ");
  984.       strcat (buf, file);
  985.       strcat (buf, " | ");
  986.       strcat (buf, TROFF);
  987.     }
  988.       else
  989.     {
  990.       strcpy (buf, TROFF);
  991.       strcat (buf, " ");
  992.       strcat (buf, file);
  993.     }
  994.     }
  995.   else
  996. #endif
  997.     {
  998.       if (nroff == nroff_cmd && strcmp (TBL, "") != 0)
  999.     {
  1000.       strcpy (buf, TBL);
  1001.       strcat (buf, " ");
  1002.       strcat (buf, file);
  1003.       strcat (buf, " | ");
  1004.       strcat (buf, nroff);
  1005.     }
  1006.       else
  1007.     {
  1008.       strcpy (buf, nroff);
  1009.       strcat (buf, " ");
  1010.       strcat (buf, file);
  1011.     }
  1012.  
  1013.       if (strcmp (COL, "") != 0)
  1014.     {
  1015.       strcat (buf, " | ");
  1016.       strcat (buf, COL);
  1017.     }
  1018.     }
  1019.   return buf;
  1020. }
  1021.  
  1022. char *
  1023. path_fixup(s)
  1024. char *s;
  1025. {
  1026. #if defined(OS2)
  1027.   char *p = s;
  1028.  
  1029.   if (s)
  1030.     while (p = strchr(p, '/')) *p = '\\';
  1031. #endif
  1032.   return s;
  1033. }
  1034.  
  1035. char *
  1036. chdir_fmt(path)
  1037. char *path;
  1038. {
  1039.   static char buf[MAXPATHLEN+9];
  1040.  
  1041. #ifdef OS2
  1042. /*
  1043.   sprintf(buf, "cd %s & ", path);
  1044.   path_fixup(buf+3); 
  1045. */
  1046.   *buf = '\0';
  1047. #else
  1048.   sprintf(buf, "cd %s ; ", path);
  1049. #endif
  1050.   return(buf);
  1051. }
  1052.  
  1053. /*
  1054.  * Try to format the man page and create a new formatted file.  Return
  1055.  * 1 for success and 0 for failure.
  1056.  */
  1057. int
  1058. make_cat_file (path, man_file, cat_file)
  1059.      register char *path;
  1060.      register char *man_file;
  1061.      register char *cat_file;
  1062. {
  1063.   int status;
  1064.   int mode;
  1065.   FILE *fp;
  1066.   char *roff_command;
  1067.   char command[BUFSIZ];
  1068.  
  1069.   if ((fp = fopen (cat_file, "w")) != NULL)
  1070.     {
  1071.       fclose (fp);
  1072.       unlink (cat_file);
  1073.  
  1074.       roff_command = make_roff_command (man_file, 0);
  1075.       if (roff_command == NULL)
  1076.     return 0;
  1077.       else
  1078. #ifdef DO_COMPRESS
  1079.     sprintf (command, "(%s%s | %s > %s)", chdir_fmt(path),
  1080.          roff_command, COMPRESSOR, cat_file);
  1081. #else
  1082.         sprintf (command, "(%s%s > %s)", chdir_fmt(path),
  1083.          roff_command, cat_file);
  1084. #endif
  1085.       /*
  1086.        * Don't let the user interrupt the system () call and screw up
  1087.        * the formmatted man page if we're not done yet.
  1088.        */
  1089.       signal (SIGINT, SIG_IGN);
  1090.  
  1091.       fprintf (stderr, "Formatting page, please wait...\n");
  1092.  
  1093.       status = do_system_command (command);
  1094.  
  1095.       if (status == 1)
  1096.     {
  1097.       mode = CATMODE;
  1098.       chmod (cat_file, mode);
  1099.  
  1100.       if (debug)
  1101.         fprintf (stderr, "mode of %s is now %o\n", cat_file, mode);
  1102.     }
  1103.  
  1104.       signal (SIGINT, SIG_DFL);
  1105.  
  1106.       return 1;
  1107.     }
  1108.   else
  1109.     {
  1110.       if (debug)
  1111.     fprintf (stderr, "Couldn't open %s for writing.\n", cat_file);
  1112.  
  1113.       return 0;
  1114.     }
  1115. }
  1116.  
  1117. /*
  1118.  * Try to format the man page source and save it, then display it.  If
  1119.  * that's not possible, try to format the man page source and display
  1120.  * it directly.
  1121.  *
  1122.  * Note that we've already been handed the name of the ultimate source
  1123.  * file at this point.
  1124.  */
  1125. int
  1126. format_and_display (path, man_file, cat_file)
  1127.      register char *path;
  1128.      register char *man_file;
  1129.      register char *cat_file;
  1130. {
  1131.   int status;
  1132.   register int found;
  1133.   char *roff_command;
  1134.   char command[BUFSIZ];
  1135.  
  1136.   found = 0;
  1137.  
  1138.   if (access (man_file, R_OK) != 0)
  1139.     return 0;
  1140.   
  1141.   if (troff)
  1142.     {
  1143.       roff_command = make_roff_command (man_file, 1);
  1144.       if (roff_command == NULL)
  1145.     return 0;
  1146.       else
  1147.     sprintf (command, "(%s%s)", chdir_fmt(path), roff_command);
  1148.  
  1149.       found = do_system_command (command);
  1150.     }
  1151.   else
  1152.     {
  1153.       status = is_newer (man_file, cat_file);
  1154.       if (debug)
  1155.     fprintf (stderr, "status from is_newer() = %d\n");
  1156.  
  1157.       if (status == 1 || status == -2)
  1158.     {
  1159.       /*
  1160.        * Cat file is out of date.  Try to format and save it.
  1161.        */
  1162.       if (print_where)
  1163.         {
  1164.           printf ("%s\n", man_file);
  1165.           found++;
  1166.         }
  1167.       else
  1168.         {
  1169.           found = make_cat_file (path, man_file, cat_file);
  1170. #ifdef SECURE_MAN_UID
  1171.           if (!found)
  1172.         {
  1173.           /*
  1174.            * Try again as real user.  Note that for private
  1175.            * man pages, we won't even get this far unless the
  1176.            * effective user can read the real user's man page
  1177.            * source.  Also, if we are trying to find all the
  1178.            * man pages, this will probably make it impossible
  1179.            * to make cat files in the system directories if
  1180.            * the real user's man directories are searched
  1181.            * first, because there's no way to undo this (is
  1182.            * there?).  Yikes, am I missing something obvious?
  1183.            */
  1184.           setuid (getuid ());
  1185.  
  1186.           found = make_cat_file (path, man_file, cat_file);
  1187.         }
  1188. #endif
  1189.           if (found)
  1190.         {
  1191.           /*
  1192.            * Creating the cat file worked.  Now just display it.
  1193.            */
  1194.           (void) display_cat_file (cat_file);
  1195.         }
  1196.           else
  1197.         {
  1198.           /*
  1199.            * Couldn't create cat file.  Just format it and
  1200.            * display it through the pager. 
  1201.            */
  1202.           roff_command = make_roff_command (man_file, 0);
  1203.           if (roff_command == NULL)
  1204.             return 0;
  1205.           else
  1206.             sprintf (command, "(%s%s | %s)", chdir_fmt(path),
  1207.                  roff_command, pager);
  1208.  
  1209.           found = do_system_command (command);
  1210.         }
  1211.         }
  1212.     }
  1213.       else if (access (cat_file, R_OK) == 0)
  1214.     {
  1215.       /*
  1216.        * Formatting not necessary.  Cat file is newer than source
  1217.        * file, or source file is not present but cat file is.
  1218.        */
  1219.       if (print_where)
  1220.         {
  1221.           printf ("%s (source: %s)\n", cat_file, man_file);
  1222.           found++;
  1223.         }
  1224.       else
  1225.         {
  1226.           found = display_cat_file (cat_file);
  1227.         }
  1228.     }
  1229.     }
  1230.   return found;
  1231. }
  1232.  
  1233. /*
  1234.  * See if the preformatted man page or the source exists in the given
  1235.  * section.
  1236.  */
  1237. int
  1238. try_section (path, section, name, glob)
  1239.      register char *path;
  1240.      register char *section;
  1241.      register char *name;
  1242.      register int glob;
  1243. {
  1244.   register int found = 0;
  1245.   register int to_cat;
  1246.   register int cat;
  1247.   register char **names;
  1248.   register char **np;
  1249.  
  1250.   if (debug)
  1251.     {
  1252.       if (glob)
  1253.     fprintf (stderr, "trying section %s with globbing\n", section);
  1254.       else
  1255.     fprintf (stderr, "trying section %s without globbing\n", section);
  1256.     }
  1257.  
  1258. #ifndef NROFF_MISSING
  1259.   /*
  1260.    * Look for man page source files.
  1261.    */
  1262.   cat = 0;
  1263.   if (glob)
  1264.     names = glob_for_file (path, section, name, cat);
  1265.   else
  1266.     names = make_name (path, section, name, cat);
  1267.  
  1268.   if (names == (char **) -1 || *names == NULL)
  1269.     /*
  1270.      * No files match.  See if there's a preformatted page around that
  1271.      * we can display. 
  1272.      */
  1273. #endif /* NROFF_MISSING */
  1274.     {
  1275.       if (!troff)
  1276.     {
  1277.       cat = 1;
  1278.       if (glob)
  1279.         names = glob_for_file (path, section, name, cat);
  1280.       else
  1281.         names = make_name (path, section, name, cat);
  1282.  
  1283.       if (names != (char **) -1 && *names != NULL)
  1284.         {
  1285.           for (np = names; *np != NULL; np++)
  1286.         {
  1287.           if (print_where)
  1288.             {
  1289.               printf ("%s\n", *np);
  1290.               found++;
  1291.             }
  1292.           else
  1293.             {
  1294.               found += display_cat_file (path_fixup(*np));
  1295.             }
  1296.         }
  1297.         }
  1298.     }
  1299.     }
  1300. #ifndef NROFF_MISSING
  1301.   else
  1302.     {
  1303.       for (np = names; *np != NULL; np++)
  1304.     {
  1305.       register char *cat_file = NULL;
  1306.       register char *man_file;
  1307.  
  1308.       man_file = ultimate_source (*np, path);
  1309.  
  1310.       if (!troff)
  1311.         {
  1312.           to_cat = 1;
  1313.  
  1314.           cat_file = convert_name (man_file, to_cat);
  1315.  
  1316.           if (debug)
  1317.         fprintf (stderr, "will try to write %s if needed\n", cat_file);
  1318.         }
  1319.  
  1320.       found += format_and_display (path, man_file, path_fixup(cat_file));
  1321.     }
  1322.     }
  1323. #endif /* NROFF_MISSING */
  1324.   return found;
  1325. }
  1326.  
  1327. /*
  1328.  * Search for manual pages.
  1329.  *
  1330.  * If preformatted manual pages are supported, look for the formatted
  1331.  * file first, then the man page source file.  If they both exist and
  1332.  * the man page source file is newer, or only the source file exists,
  1333.  * try to reformat it and write the results in the cat directory.  If
  1334.  * it is not possible to write the cat file, simply format and display
  1335.  * the man file.
  1336.  *
  1337.  * If preformatted pages are not supported, or the troff option is
  1338.  * being used, only look for the man page source file.
  1339.  *
  1340.  */
  1341. int
  1342. man (name)
  1343.      char *name;
  1344. {
  1345.   register int found;
  1346.   register int glob;
  1347.   register char **mp;
  1348.   register char **sp;
  1349.  
  1350.   found = 0;
  1351.  
  1352.   fflush (stdout);
  1353.   if (section != NULL)
  1354.     {
  1355.       for (mp = manpathlist; *mp != NULL; mp++)
  1356.     {
  1357.       if (debug)
  1358.         fprintf (stderr, "\nsearching in %s\n", *mp);
  1359.  
  1360.       glob = 0;
  1361.  
  1362.       found += try_section (*mp, section, name, glob);
  1363.  
  1364.       if (found && !findall)   /* i.e. only do this section... */
  1365.         return found;
  1366.     }
  1367.     }
  1368.   else
  1369.     {
  1370.       for (sp = section_list; *sp != NULL; sp++)
  1371.     {
  1372.       for (mp = manpathlist; *mp != NULL; mp++)
  1373.         {
  1374.           if (debug)
  1375.         fprintf (stderr, "\nsearching in %s\n", *mp);
  1376.  
  1377.           glob = 1;
  1378.  
  1379.           found += try_section (*mp, *sp, name, glob);
  1380.  
  1381.           if (found && !findall)   /* i.e. only do this section... */
  1382.         return found;
  1383.         }
  1384.     }
  1385.     }
  1386.   return found;
  1387. }
  1388.  
  1389. char **
  1390. get_section_list ()
  1391. {
  1392.   int i;
  1393.   char *p;
  1394.   char *end;
  1395.   static char *tmp_section_list[100];
  1396.  
  1397.   if (colon_sep_section_list == NULL)
  1398.     {
  1399.       if ((p = getenv ("MANSECT")) == NULL)
  1400.     {
  1401.       return std_sections;
  1402.     }
  1403.       else
  1404.     {
  1405.       colon_sep_section_list = strdup (p);
  1406.     }
  1407.     }
  1408.  
  1409.   i = 0;
  1410.   for (p = colon_sep_section_list; ; p = end+1)
  1411.     {
  1412.       if ((end = strchr (p, ':')) != NULL)
  1413.     *end = '\0';
  1414.  
  1415.       tmp_section_list[i++] = strdup (p);
  1416.  
  1417.       if (end == NULL)
  1418.     break;
  1419.     }
  1420.  
  1421.   tmp_section_list [i] = NULL;
  1422.   return tmp_section_list;
  1423. }
  1424.