Print this page
-T on the wrong command!
Latest round of fixes per RM and AL.  Fix bugs found in man.c.


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved.
  25  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.

  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.       */
  29 /*              All rights reserved.                                    */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 /*
  42  * Find and display reference manual pages. This version includes makewhatis
  43  * functionality as well.
  44  */
  45 


  65 #include <unistd.h>
  66 
  67 #include "man.h"
  68 
  69 
  70 /* Mapping of old directories to new directories */
  71 static const struct map_entry {
  72         char    *old_name;
  73         char    *new_name;
  74 } map[] = {
  75         { "3b",         "3ucb"          },
  76         { "3e",         "3elf"          },
  77         { "3g",         "3gen"          },
  78         { "3k",         "3kstat"        },
  79         { "3n",         "3socket"       },
  80         { "3r",         "3rt"           },
  81         { "3s",         "3c"            },
  82         { "3t",         "3thr"          },
  83         { "3x",         "3curses"       },
  84         { "3xc",        "3xcurses"      },
  85         { "3xn",        "3xnet"         }

  86 };
  87 
  88 struct suffix {
  89         char *ds;
  90         char *fs;
  91 };
  92 
  93 /*
  94  * Flags that control behavior of build_manpath()
  95  *
  96  *   BMP_ISPATH                 pathv is a vector constructed from PATH.
  97  *                              Perform appropriate path translations for
  98  *                              manpath.
  99  *   BMP_APPEND_DEFMANDIR       Add DEFMANDIR to the end if it hasn't
 100  *                              already appeared earlier.
 101  *   BMP_FALLBACK_DEFMANDIR     Append /usr/share/man only if no other
 102  *                              manpath (including derived from PATH)
 103  *                              elements are valid.
 104  */
 105 #define BMP_ISPATH              1


 141         { NULL,                 NULL,                           0, 0 }
 142 };
 143 
 144 struct man_node {
 145         char            *path;          /* mandir path */
 146         char            **secv;         /* submandir suffices */
 147         int             defsrch;        /* hint for man -p */
 148         int             frompath;       /* hint for man -d */
 149         struct man_node *next;
 150 };
 151 
 152 static int      all = 0;
 153 static int      apropos = 0;
 154 static int      debug = 0;
 155 static int      found = 0;
 156 static int      list = 0;
 157 static int      makewhatis = 0;
 158 static int      printmp = 0;
 159 static int      sargs = 0;
 160 static int      psoutput = 0;

 161 static int      whatis = 0;
 162 static int      makewhatishere = 0;
 163 
 164 static char     *mansec;
 165 static char     *pager;
 166 
 167 static char     *addlocale(char *);
 168 static struct man_node *build_manpath(char **, int);
 169 static void     do_makewhatis(struct man_node *);
 170 static char     *check_config(char *);
 171 static int      cmp(const void *, const void *);
 172 static int      dupcheck(struct man_node *, struct dupnode **);
 173 static int      format(char *, char *, char *, char *);
 174 static void     free_dupnode(struct dupnode *);
 175 static void     free_manp(struct man_node *manp);
 176 static void     freev(char **);
 177 static void     fullpaths(struct man_node **);
 178 static void     get_all_sect(struct man_node *);
 179 static int      getdirs(char *, char ***, int);
 180 static void     getpath(struct man_node *, char **);
 181 static void     getsect(struct man_node *, char **);
 182 static void     init_bintoman(void);
 183 static void     lower(char *);
 184 static void     mandir(char **, char *, char *, int);
 185 static int      manual(struct man_node *, char *);


 221         (void) setlocale(LC_ALL, "");
 222         (void) strcpy(language, setlocale(LC_MESSAGES, (char *)NULL));
 223         if (strcmp("C", language) != 0)
 224                 (void) strlcpy(localedir, language, MAXPATHLEN);
 225 
 226 #if !defined(TEXT_DOMAIN)
 227 #define TEXT_DOMAIN "SYS_TEST"
 228 #endif
 229         (void) textdomain(TEXT_DOMAIN);
 230 
 231         if (strcmp(__progname, "apropos") == 0) {
 232                 apropos++;
 233                 opts = "M:ds:";
 234         } else if (strcmp(__progname, "whatis") == 0) {
 235                 apropos++;
 236                 whatis++;
 237                 opts = "M:ds:";
 238         } else if (strcmp(__progname, "catman") == 0) {
 239                 catman++;
 240                 makewhatis++;
 241                 opts = "M:w";
 242         } else if (strcmp(__progname, "makewhatis") == 0) {
 243                 makewhatis++;
 244                 makewhatishere++;
 245                 manpath = ".";
 246                 opts = "";
 247         } else {
 248                 opts = "M:adfklps:tw";



 249         }

 250 
 251         opterr = 0;
 252         while ((c = getopt(argc, argv, opts)) != -1) {
 253                 switch (c) {
 254                 case 'M':       /* Respecify path for man pages */
 255                         manpath = optarg;
 256                         break;
 257                 case 'a':
 258                         all++;
 259                         break;
 260                 case 'd':
 261                         debug++;
 262                         break;
 263                 case 'f':
 264                         whatis++;
 265                         /*FALLTHROUGH*/
 266                 case 'k':
 267                         apropos++;
 268                         break;
 269                 case 'l':
 270                         list++;
 271                         /*FALLTHROUGH*/

 272                 case 'p':
 273                         printmp++;
 274                         break;
 275                 case 's':
 276                         mansec = optarg;
 277                         sargs++;
 278                         break;



 279                 case 't':
 280                         psoutput++;
 281                         break;





 282                 case 'w':
 283                         makewhatis++;
 284                         break;
 285                 case '?':
 286                 default:
 287                         if (apropos)
 288                                 usage_whatapro();
 289                         else if (catman)
 290                                 usage_catman();
 291                         else if (makewhatishere)
 292                                 usage_makewhatis();
 293                         else
 294                                 usage_man();
 295                 }
 296         }
 297         argc -= optind;
 298         argv += optind;
 299 
 300         if (argc == 0) {
 301                 if (apropos) {


 334         /* Collect environment information */
 335         if (isatty(STDOUT_FILENO) && (mwstr = getenv("MANWIDTH")) != NULL &&
 336             *mwstr != '\0') {
 337                 if (strcasecmp(mwstr, "tty") == 0) {
 338                         struct winsize  ws;
 339 
 340                         if (ioctl(0, TIOCGWINSZ, &ws) != 0)
 341                                 warn("TIOCGWINSZ");
 342                         else
 343                                 manwidth = ws.ws_col;
 344                 } else {
 345                         manwidth = (int)strtol(mwstr, (char **)NULL, 10);
 346                         if (manwidth < 0)
 347                                 manwidth = 0;
 348                 }
 349         }
 350         if (manwidth != 0) {
 351                 DPRINTF("-- Using non-standard page width: %d\n", manwidth);
 352         }
 353 

 354         if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
 355                 pager = PAGER;

 356         DPRINTF("-- Using pager: %s\n", pager);
 357 
 358         for (i = 0; i < argc; i++) {
 359                 char            *cmd;
 360                 static struct man_node *mp;
 361                 char            *pv[2];
 362 
 363                 /*
 364                  * If full path to command specified, customize
 365                  * the manpath accordingly.
 366                  */
 367                 if ((cmd = strrchr(argv[i], '/')) != NULL) {
 368                         *cmd = '\0';
 369                         if ((pv[0] = strdup(argv[i])) == NULL)
 370                                 err(1, "strdup");
 371                         pv[1] = NULL;
 372                         *cmd = '/';
 373                         mp = build_manpath(pv,
 374                             BMP_ISPATH | BMP_FALLBACK_DEFMANDIR);
 375                 } else {


1129                         (void) format(path, dir, name, sd->d_name);
1130                         (void) closedir(sdp);
1131                         free(pname);
1132                         return (1);
1133                 }
1134                 free(pname);
1135         }
1136         (void) closedir(sdp);
1137 
1138         return (0);
1139 }
1140 
1141 /*
1142  * Check the hash table of old directory names to see if there is a
1143  * new directory name.
1144  */
1145 static char *
1146 map_section(char *section, char *path)
1147 {
1148         int     i;
1149         int     len;
1150         char    fullpath[MAXPATHLEN];
1151 
1152         if (list)  /* -l option fall through */
1153                 return (NULL);
1154 
1155         for (i = 0; i <= ((sizeof (map)/sizeof (map[0]) - 1)); i++) {
1156                 if (strlen(section) > strlen(map[i].new_name)) {
1157                         len = strlen(section);
1158                 } else {
1159                         len = strlen(map[i].new_name);
1160                 }
1161                 if (strncmp(section, map[i].old_name, len) == 0) {
1162                         (void) snprintf(fullpath, sizeof (fullpath),
1163                             "%s/sman%s", path, map[i].new_name);
1164                         if (!access(fullpath, R_OK | X_OK)) {
1165                                 return (map[i].new_name);
1166                         } else {
1167                                 return (NULL);
1168                         }
1169                 }
1170         }
1171 
1172         return (NULL);
1173 }
1174 
1175 /*
1176  * Format the manpage.
1177  */
1178 static int
1179 format(char *path, char *dir, char *name, char *pg)
1180 {
1181         char            manpname[MAXPATHLEN], catpname[MAXPATHLEN];
1182         char            cmdbuf[BUFSIZ], tmpbuf[BUFSIZ];
1183         char            *cattool;
1184         int             utf8 = 0;
1185         struct stat     sbman, sbcat;
1186 
1187         found++;
1188 
1189         if (list) {
1190                 (void) printf(gettext("%s(%s)\t-M %s\n"), name, dir + 3, path);
1191                 return (-1);
1192         }
1193 
1194         (void) snprintf(manpname, sizeof (manpname), "%s/man%s/%s", path,
1195             dir + 3, pg);
1196         (void) snprintf(catpname, sizeof (catpname), "%s/cat%s/%s", path,
1197             dir + 3, pg);
1198 
1199         /* Can't do PS output if manpage doesn't exist */
1200         if (stat(manpname, &sbman) != 0 && psoutput)
1201                 return (-1);
1202 
1203         /*
1204          * If both manpage and catpage do not exist, manpname is
1205          * broken symlink, most likely.
1206          */
1207         if (stat(catpname, &sbcat) != 0 && stat(manpname, &sbman) != 0)
1208                 err(1, "%s", manpname);
1209 
1210         /* Setup cattool */
1211         if (fnmatch("*.gz", manpname, 0) == 0)
1212                 cattool = "gzcat";
1213         else if (fnmatch("*.bz2", manpname, 0) == 0)
1214                 cattool = "bzcat";
1215         else
1216                 cattool = "gzcat -f";
1217 
1218         /* Preprocess UTF-8 input with preconv (could be smarter) */
1219         if (strstr(path, "UTF-8") != NULL)
1220                 utf8 = 1;
1221 
1222         if (psoutput) {
1223                 (void) snprintf(cmdbuf, BUFSIZ,
1224                     "cd %s; %s %s%s | mandoc -Tps | lp -Tpostscript",
1225                     path, cattool, manpname,
1226                     utf8 ? " | " PRECONV " -e UTF-8" : "");
1227                 DPRINTF("-- Using manpage: %s\n", manpname);
1228                 goto cmd;







1229         }
1230 
1231         /*
1232          * Output catpage if:
1233          * - manpage doesn't exist
1234          * - output width is standard and catpage is recent enough
1235          */
1236         if (stat(manpname, &sbman) != 0 || (manwidth == 0 &&
1237             stat(catpname, &sbcat) == 0 && sbcat.st_mtime >= sbman.st_mtime)) {
1238                 DPRINTF("-- Using catpage: %s\n", catpname);
1239                 (void) snprintf(cmdbuf, BUFSIZ, "%s %s", pager, catpname);
1240                 goto cmd;
1241         }
1242 
1243         DPRINTF("-- Using manpage: %s\n", manpname);
1244         if (manwidth > 0)
1245                 (void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth);
1246         (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s%s | mandoc -T%s %s| %s",
1247             path, cattool, manpname,
1248             utf8 ? " | " PRECONV " -e UTF-8 " : "",


1551 
1552                 for (secp = manp->secv; *secp != NULL; secp++) {
1553                         /*
1554                          * Section deduplication may have eliminated some
1555                          * sections from the vector. Avoid displaying this
1556                          * detail which would appear as ",," in output
1557                          */
1558                         if ((*secp)[0] != '\0')
1559                                 (void) printf(",%s", *secp);
1560                 }
1561         }
1562         (void) printf("\n");
1563 }
1564 
1565 static void
1566 usage_man(void)
1567 {
1568 
1569         (void) fprintf(stderr, gettext(
1570 "usage: man [-alptw] [-M path] [-s section] name ...\n"
1571 "       man [-M path] [-s section] -k keyword -- emulate apropos\n"
1572 "       man [-M path] [-s section] -f keyword -- emulate whatis\n"));
1573 
1574         exit(1);
1575 }
1576 
1577 static void
1578 usage_whatapro(void)
1579 {
1580 
1581         (void) fprintf(stderr, gettext(
1582 "usage: %s [-M path] [-s section] keyword ...\n"),
1583             whatis ? "whatis" : "apropos");
1584 
1585         exit(1);
1586 }
1587 
1588 static void
1589 usage_catman(void)
1590 {
1591         (void) fprintf(stderr, gettext(
1592 "usage: catman [-M path] [-w]\n"));


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved.
  25  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  26  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  27  */
  28 
  29 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.       */
  30 /*              All rights reserved.                                    */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  */
  41 
  42 /*
  43  * Find and display reference manual pages. This version includes makewhatis
  44  * functionality as well.
  45  */
  46 


  66 #include <unistd.h>
  67 
  68 #include "man.h"
  69 
  70 
  71 /* Mapping of old directories to new directories */
  72 static const struct map_entry {
  73         char    *old_name;
  74         char    *new_name;
  75 } map[] = {
  76         { "3b",         "3ucb"          },
  77         { "3e",         "3elf"          },
  78         { "3g",         "3gen"          },
  79         { "3k",         "3kstat"        },
  80         { "3n",         "3socket"       },
  81         { "3r",         "3rt"           },
  82         { "3s",         "3c"            },
  83         { "3t",         "3thr"          },
  84         { "3x",         "3curses"       },
  85         { "3xc",        "3xcurses"      },
  86         { "3xn",        "3xnet"         },
  87         { NULL,         NULL            }
  88 };
  89 
  90 struct suffix {
  91         char *ds;
  92         char *fs;
  93 };
  94 
  95 /*
  96  * Flags that control behavior of build_manpath()
  97  *
  98  *   BMP_ISPATH                 pathv is a vector constructed from PATH.
  99  *                              Perform appropriate path translations for
 100  *                              manpath.
 101  *   BMP_APPEND_DEFMANDIR       Add DEFMANDIR to the end if it hasn't
 102  *                              already appeared earlier.
 103  *   BMP_FALLBACK_DEFMANDIR     Append /usr/share/man only if no other
 104  *                              manpath (including derived from PATH)
 105  *                              elements are valid.
 106  */
 107 #define BMP_ISPATH              1


 143         { NULL,                 NULL,                           0, 0 }
 144 };
 145 
 146 struct man_node {
 147         char            *path;          /* mandir path */
 148         char            **secv;         /* submandir suffices */
 149         int             defsrch;        /* hint for man -p */
 150         int             frompath;       /* hint for man -d */
 151         struct man_node *next;
 152 };
 153 
 154 static int      all = 0;
 155 static int      apropos = 0;
 156 static int      debug = 0;
 157 static int      found = 0;
 158 static int      list = 0;
 159 static int      makewhatis = 0;
 160 static int      printmp = 0;
 161 static int      sargs = 0;
 162 static int      psoutput = 0;
 163 static int      lintout = 0;
 164 static int      whatis = 0;
 165 static int      makewhatishere = 0;
 166 
 167 static char     *mansec;
 168 static char     *pager = NULL;
 169 
 170 static char     *addlocale(char *);
 171 static struct man_node *build_manpath(char **, int);
 172 static void     do_makewhatis(struct man_node *);
 173 static char     *check_config(char *);
 174 static int      cmp(const void *, const void *);
 175 static int      dupcheck(struct man_node *, struct dupnode **);
 176 static int      format(char *, char *, char *, char *);
 177 static void     free_dupnode(struct dupnode *);
 178 static void     free_manp(struct man_node *manp);
 179 static void     freev(char **);
 180 static void     fullpaths(struct man_node **);
 181 static void     get_all_sect(struct man_node *);
 182 static int      getdirs(char *, char ***, int);
 183 static void     getpath(struct man_node *, char **);
 184 static void     getsect(struct man_node *, char **);
 185 static void     init_bintoman(void);
 186 static void     lower(char *);
 187 static void     mandir(char **, char *, char *, int);
 188 static int      manual(struct man_node *, char *);


 224         (void) setlocale(LC_ALL, "");
 225         (void) strcpy(language, setlocale(LC_MESSAGES, (char *)NULL));
 226         if (strcmp("C", language) != 0)
 227                 (void) strlcpy(localedir, language, MAXPATHLEN);
 228 
 229 #if !defined(TEXT_DOMAIN)
 230 #define TEXT_DOMAIN "SYS_TEST"
 231 #endif
 232         (void) textdomain(TEXT_DOMAIN);
 233 
 234         if (strcmp(__progname, "apropos") == 0) {
 235                 apropos++;
 236                 opts = "M:ds:";
 237         } else if (strcmp(__progname, "whatis") == 0) {
 238                 apropos++;
 239                 whatis++;
 240                 opts = "M:ds:";
 241         } else if (strcmp(__progname, "catman") == 0) {
 242                 catman++;
 243                 makewhatis++;
 244                 opts = "P:M:w";
 245         } else if (strcmp(__progname, "makewhatis") == 0) {
 246                 makewhatis++;
 247                 makewhatishere++;
 248                 manpath = ".";
 249                 opts = "";
 250         } else {
 251                 opts = "FM:P:T:adfklprs:tw";
 252                 if (argc > 1 && strcmp(argv[1], "-") == 0) {
 253                         pager = "cat";
 254                         optind++;
 255                 }
 256         }
 257 
 258         opterr = 0;
 259         while ((c = getopt(argc, argv, opts)) != -1) {
 260                 switch (c) {
 261                 case 'M':       /* Respecify path for man pages */
 262                         manpath = optarg;
 263                         break;
 264                 case 'a':
 265                         all++;
 266                         break;
 267                 case 'd':
 268                         debug++;
 269                         break;
 270                 case 'f':
 271                         whatis++;
 272                         /*FALLTHROUGH*/
 273                 case 'k':
 274                         apropos++;
 275                         break;
 276                 case 'l':
 277                         list++;
 278                         all++;
 279                         break;
 280                 case 'p':
 281                         printmp++;
 282                         break;
 283                 case 's':
 284                         mansec = optarg;
 285                         sargs++;
 286                         break;
 287                 case 'r':
 288                         lintout++;
 289                         break;
 290                 case 't':
 291                         psoutput++;
 292                         break;
 293                 case 'T':
 294                 case 'P':
 295                 case 'F':
 296                         /* legacy options, compatibility only and ignored */
 297                         break;
 298                 case 'w':
 299                         makewhatis++;
 300                         break;
 301                 case '?':
 302                 default:
 303                         if (apropos)
 304                                 usage_whatapro();
 305                         else if (catman)
 306                                 usage_catman();
 307                         else if (makewhatishere)
 308                                 usage_makewhatis();
 309                         else
 310                                 usage_man();
 311                 }
 312         }
 313         argc -= optind;
 314         argv += optind;
 315 
 316         if (argc == 0) {
 317                 if (apropos) {


 350         /* Collect environment information */
 351         if (isatty(STDOUT_FILENO) && (mwstr = getenv("MANWIDTH")) != NULL &&
 352             *mwstr != '\0') {
 353                 if (strcasecmp(mwstr, "tty") == 0) {
 354                         struct winsize  ws;
 355 
 356                         if (ioctl(0, TIOCGWINSZ, &ws) != 0)
 357                                 warn("TIOCGWINSZ");
 358                         else
 359                                 manwidth = ws.ws_col;
 360                 } else {
 361                         manwidth = (int)strtol(mwstr, (char **)NULL, 10);
 362                         if (manwidth < 0)
 363                                 manwidth = 0;
 364                 }
 365         }
 366         if (manwidth != 0) {
 367                 DPRINTF("-- Using non-standard page width: %d\n", manwidth);
 368         }
 369 
 370         if (pager == NULL) {
 371                 if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
 372                         pager = PAGER;
 373         }
 374         DPRINTF("-- Using pager: %s\n", pager);
 375 
 376         for (i = 0; i < argc; i++) {
 377                 char            *cmd;
 378                 static struct man_node *mp;
 379                 char            *pv[2];
 380 
 381                 /*
 382                  * If full path to command specified, customize
 383                  * the manpath accordingly.
 384                  */
 385                 if ((cmd = strrchr(argv[i], '/')) != NULL) {
 386                         *cmd = '\0';
 387                         if ((pv[0] = strdup(argv[i])) == NULL)
 388                                 err(1, "strdup");
 389                         pv[1] = NULL;
 390                         *cmd = '/';
 391                         mp = build_manpath(pv,
 392                             BMP_ISPATH | BMP_FALLBACK_DEFMANDIR);
 393                 } else {


1147                         (void) format(path, dir, name, sd->d_name);
1148                         (void) closedir(sdp);
1149                         free(pname);
1150                         return (1);
1151                 }
1152                 free(pname);
1153         }
1154         (void) closedir(sdp);
1155 
1156         return (0);
1157 }
1158 
1159 /*
1160  * Check the hash table of old directory names to see if there is a
1161  * new directory name.
1162  */
1163 static char *
1164 map_section(char *section, char *path)
1165 {
1166         int     i;

1167         char    fullpath[MAXPATHLEN];
1168 
1169         if (list)  /* -l option fall through */
1170                 return (NULL);
1171 
1172         for (i = 0; map[i].new_name != NULL; i++) {
1173                 if (strcmp(section, map[i].old_name) == 0) {





1174                         (void) snprintf(fullpath, sizeof (fullpath),
1175                             "%s/man%s", path, map[i].new_name);
1176                         if (!access(fullpath, R_OK | X_OK)) {
1177                                 return (map[i].new_name);
1178                         } else {
1179                                 return (NULL);
1180                         }
1181                 }
1182         }
1183 
1184         return (NULL);
1185 }
1186 
1187 /*
1188  * Format the manpage.
1189  */
1190 static int
1191 format(char *path, char *dir, char *name, char *pg)
1192 {
1193         char            manpname[MAXPATHLEN], catpname[MAXPATHLEN];
1194         char            cmdbuf[BUFSIZ], tmpbuf[BUFSIZ];
1195         char            *cattool;
1196         int             utf8 = 0;
1197         struct stat     sbman, sbcat;
1198 
1199         found++;
1200 
1201         if (list) {
1202                 (void) printf(gettext("%s(%s)\t-M %s\n"), name, dir + 3, path);
1203                 return (-1);
1204         }
1205 
1206         (void) snprintf(manpname, sizeof (manpname), "%s/man%s/%s", path,
1207             dir + 3, pg);
1208         (void) snprintf(catpname, sizeof (catpname), "%s/cat%s/%s", path,
1209             dir + 3, pg);
1210 
1211         /* Can't do PS output if manpage doesn't exist */
1212         if (stat(manpname, &sbman) != 0 && (psoutput|lintout))
1213                 return (-1);
1214 
1215         /*
1216          * If both manpage and catpage do not exist, manpname is
1217          * broken symlink, most likely.
1218          */
1219         if (stat(catpname, &sbcat) != 0 && stat(manpname, &sbman) != 0)
1220                 err(1, "%s", manpname);
1221 
1222         /* Setup cattool */
1223         if (fnmatch("*.gz", manpname, 0) == 0)
1224                 cattool = "gzcat";
1225         else if (fnmatch("*.bz2", manpname, 0) == 0)
1226                 cattool = "bzcat";
1227         else
1228                 cattool = "cat";
1229 
1230         /* Preprocess UTF-8 input with preconv (could be smarter) */
1231         if (strstr(path, "UTF-8") != NULL)
1232                 utf8 = 1;
1233 
1234         if (psoutput) {
1235                 (void) snprintf(cmdbuf, BUFSIZ,
1236                     "cd %s; %s %s%s | mandoc -Tps | lp -Tpostscript",
1237                     path, cattool, manpname,
1238                     utf8 ? " | " PRECONV " -e UTF-8" : "");
1239                 DPRINTF("-- Using manpage: %s\n", manpname);
1240                 goto cmd;
1241         } else if (lintout) {
1242                 (void) snprintf(cmdbuf, BUFSIZ,
1243                     "cd %s; %s %s%s | mandoc -Tlint",
1244                     path, cattool, manpname,
1245                     utf8 ? " | " PRECONV " -e UTF-8" : "");
1246                 DPRINTF("-- Linting manpage: %s\n", manpname);
1247                 goto cmd;
1248         }
1249 
1250         /*
1251          * Output catpage if:
1252          * - manpage doesn't exist
1253          * - output width is standard and catpage is recent enough
1254          */
1255         if (stat(manpname, &sbman) != 0 || (manwidth == 0 &&
1256             stat(catpname, &sbcat) == 0 && sbcat.st_mtime >= sbman.st_mtime)) {
1257                 DPRINTF("-- Using catpage: %s\n", catpname);
1258                 (void) snprintf(cmdbuf, BUFSIZ, "%s %s", pager, catpname);
1259                 goto cmd;
1260         }
1261 
1262         DPRINTF("-- Using manpage: %s\n", manpname);
1263         if (manwidth > 0)
1264                 (void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth);
1265         (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s%s | mandoc -T%s %s| %s",
1266             path, cattool, manpname,
1267             utf8 ? " | " PRECONV " -e UTF-8 " : "",


1570 
1571                 for (secp = manp->secv; *secp != NULL; secp++) {
1572                         /*
1573                          * Section deduplication may have eliminated some
1574                          * sections from the vector. Avoid displaying this
1575                          * detail which would appear as ",," in output
1576                          */
1577                         if ((*secp)[0] != '\0')
1578                                 (void) printf(",%s", *secp);
1579                 }
1580         }
1581         (void) printf("\n");
1582 }
1583 
1584 static void
1585 usage_man(void)
1586 {
1587 
1588         (void) fprintf(stderr, gettext(
1589 "usage: man [-alptw] [-M path] [-s section] name ...\n"
1590 "       man [-M path] [-s section] -k keyword ...\n"
1591 "       man [-M path] [-s section] -f keyword ...\n"));
1592 
1593         exit(1);
1594 }
1595 
1596 static void
1597 usage_whatapro(void)
1598 {
1599 
1600         (void) fprintf(stderr, gettext(
1601 "usage: %s [-M path] [-s section] keyword ...\n"),
1602             whatis ? "whatis" : "apropos");
1603 
1604         exit(1);
1605 }
1606 
1607 static void
1608 usage_catman(void)
1609 {
1610         (void) fprintf(stderr, gettext(
1611 "usage: catman [-M path] [-w]\n"));