]> git.cameronkatri.com Git - mandoc.git/commitdiff
In man(1) mode, do the search for each name independently, and
authorIngo Schwarze <schwarze@openbsd.org>
Sun, 28 Jul 2019 18:23:17 +0000 (18:23 +0000)
committerIngo Schwarze <schwarze@openbsd.org>
Sun, 28 Jul 2019 18:23:17 +0000 (18:23 +0000)
show the results in the order of the command line arguments.
Implemented by separating the code for man(1) and apropos(1)
in the main() program.
Surprisingly, the number of lines of code remains unchanged.
Issue reported by deraadt@, additional input from millert@.

main.c

diff --git a/main.c b/main.c
index 63281363f28300307b1c15a70759189820644140..7d6085e713bac3ad6a4f5d322c9e05741f271891 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/*     $Id: main.c,v 1.337 2019/07/28 13:13:03 schwarze Exp $ */
+/*     $Id: main.c,v 1.338 2019/07/28 18:23:17 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
@@ -120,7 +120,8 @@ main(int argc, char *argv[])
        struct outstate  outst;         /* Output state. */
        struct winsize   ws;            /* Result of ioctl(TIOCGWINSZ). */
        struct mansearch search;        /* Search options. */
-       struct manpage  *res, *resp;    /* Search results. */
+       struct manpage  *res;           /* Complete list of search results. */
+       struct manpage  *resn;          /* Search results for one name. */
        struct mparse   *mp;            /* Opaque parser object. */
        const char      *conf_file;     /* -C: alternate config file. */
        const char      *os_s;          /* -I: Operating system for display. */
@@ -130,8 +131,9 @@ main(int argc, char *argv[])
        char            *oarg;          /* -O: output option string. */
        char            *tagarg;        /* -O tag: default value. */
        unsigned char   *uc;
-       size_t           sz;            /* Number of elements in res[]. */
-       size_t           i, ssz;
+       size_t           ressz;         /* Number of elements in res[]. */
+       size_t           resnsz;        /* Number of elements in resn[]. */
+       size_t           i, ib, ssz;
        int              options;       /* Parser options. */
        int              show_usage;    /* Invalid argument: give up. */
        int              prio, best_prio;
@@ -384,11 +386,10 @@ main(int argc, char *argv[])
                argc -= optind;
                argv += optind;
        }
-       resp = NULL;
 
        /*
-        * Quirks for help(1)
-        * and for a man(1) section argument without -s.
+        * Quirks for help(1) and man(1),
+        * in particular for a section argument without -s.
         */
 
        if (search.argmode == ARG_NAME) {
@@ -412,6 +413,8 @@ main(int argc, char *argv[])
                if (search.arch == NULL)
                        search.arch = MACHINE;
 #endif
+               if (outmode == OUTMODE_ONE)
+                       search.firstmatch = 1;
        }
 
        /*
@@ -425,80 +428,54 @@ main(int argc, char *argv[])
                conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
        }
 
-       /* man(1), whatis(1), apropos(1) */
-
-       if (search.argmode != ARG_FILE) {
-               if (search.argmode == ARG_NAME &&
-                   outmode == OUTMODE_ONE)
-                       search.firstmatch = 1;
-
-               /* Access the mandoc database. */
+       /* Read the configuration file. */
 
+       if (search.argmode != ARG_FILE)
                manconf_parse(&conf, conf_file, defpaths, auxpaths);
-               if ( ! mansearch(&search, &conf.manpath,
-                   argc, argv, &res, &sz))
-                       usage(search.argmode);
 
-               if (sz == 0 && search.argmode == ARG_NAME)
-                       (void)fs_search(&search, &conf.manpath,
-                           argc, argv, &res, &sz);
+       /* man(1): Resolve each name individually. */
 
-               if (search.argmode == ARG_NAME) {
-                       for (c = 0; c < argc; c++) {
-                               if (strchr(argv[c], '/') == NULL)
+       if (search.argmode == ARG_NAME) {
+               if (argc < 1)
+                       usage(ARG_NAME);
+               for (res = NULL, ressz = 0; argc > 0; argc--, argv++) {
+                       (void)mansearch(&search, &conf.manpath,
+                           1, argv, &resn, &resnsz);
+                       if (resnsz == 0)
+                               (void)fs_search(&search, &conf.manpath,
+                                   1, argv, &resn, &resnsz);
+                       if (resnsz == 0) {
+                               if (strchr(*argv, '/') == NULL) {
+                                       mandoc_msg_setrc(MANDOCLEVEL_BADARG);
                                        continue;
-                               if (access(argv[c], R_OK) == -1) {
-                                       mandoc_msg_setinfilename(argv[c]);
+                               }
+                               if (access(*argv, R_OK) == -1) {
+                                       mandoc_msg_setinfilename(*argv);
                                        mandoc_msg(MANDOCERR_BADARG_BAD,
                                            0, 0, "%s", strerror(errno));
                                        mandoc_msg_setinfilename(NULL);
                                        continue;
                                }
+                               resnsz = 1;
+                               resn = mandoc_calloc(resnsz, sizeof(*res));
+                               resn->file = mandoc_strdup(*argv);
+                               resn->ipath = SIZE_MAX;
+                               resn->form = FORM_SRC;
+                       }
+                       if (outmode != OUTMODE_ONE || resnsz == 1) {
                                res = mandoc_reallocarray(res,
-                                   sz + 1, sizeof(*res));
-                               res[sz].file = mandoc_strdup(argv[c]);
-                               res[sz].names = NULL;
-                               res[sz].output = NULL;
-                               res[sz].bits = 0;
-                               res[sz].ipath = SIZE_MAX;
-                               res[sz].sec = 10;
-                               res[sz].form = FORM_SRC;
-                               sz++;
+                                   ressz + resnsz, sizeof(*res));
+                               memcpy(res + ressz, resn,
+                                   sizeof(*resn) * resnsz);
+                               ressz += resnsz;
+                               continue;
                        }
-               }
-
-               if (sz == 0) {
-                       if (search.argmode != ARG_NAME)
-                               warnx("nothing appropriate");
-                       mandoc_msg_setrc(MANDOCLEVEL_BADARG);
-                       goto out;
-               }
 
-               /*
-                * For standard man(1) and -a output mode,
-                * prepare for copying filename pointers
-                * into the program parameter array.
-                */
+                       /* Search for the best section. */
 
-               if (outmode == OUTMODE_ONE) {
-                       argc = 1;
                        best_prio = 40;
-               } else if (outmode == OUTMODE_ALL)
-                       argc = (int)sz;
-
-               /* Iterate all matching manuals. */
-
-               resp = res;
-               for (i = 0; i < sz; i++) {
-                       if (outmode == OUTMODE_FLN)
-                               puts(res[i].file);
-                       else if (outmode == OUTMODE_LST)
-                               printf("%s - %s\n", res[i].names,
-                                   res[i].output == NULL ? "" :
-                                   res[i].output);
-                       else if (outmode == OUTMODE_ONE) {
-                               /* Search for the best section. */
-                               sec = res[i].file;
+                       for (ib = i = 0; i < resnsz; i++) {
+                               sec = resn[i].file;
                                sec += strcspn(sec, "123456789");
                                if (sec[0] == '\0')
                                        continue; /* No section at all. */
@@ -519,32 +496,53 @@ main(int argc, char *argv[])
                                if (prio >= best_prio)
                                        continue;
                                best_prio = prio;
-                               resp = res + i;
+                               ib = i;
                        }
+                       res = mandoc_reallocarray(res, ressz + 1,
+                           sizeof(*res));
+                       memcpy(res + ressz++, resn + ib, sizeof(*resn));
                }
 
-               /*
-                * For man(1), -a and -i output mode, fall through
-                * to the main mandoc(1) code iterating files
-                * and running the parsers on each of them.
-                */
+       /* apropos(1), whatis(1): Process the full search expression. */
 
-               if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
+       } else if (search.argmode != ARG_FILE) {
+               if (mansearch(&search, &conf.manpath,
+                   argc, argv, &res, &ressz) == 0)
+                       usage(search.argmode);
+
+               if (ressz == 0) {
+                       warnx("nothing appropriate");
+                       mandoc_msg_setrc(MANDOCLEVEL_BADARG);
                        goto out;
+               }
+
+       /* mandoc(1): Take command line arguments as file names. */
+
        } else {
-               sz = argc > 0 ? argc : 1;
-               resp = res = mandoc_recallocarray(NULL, 0, sz, sizeof(*res));
-               for (i = 0; i < sz; i++) {
+               ressz = argc > 0 ? argc : 1;
+               res = mandoc_calloc(ressz, sizeof(*res));
+               for (i = 0; i < ressz; i++) {
                        if (argc > 0)
                                res[i].file = mandoc_strdup(argv[i]);
                        res[i].ipath = SIZE_MAX;
                        res[i].form = FORM_SRC;
                }
-               if (argc < 1)
-                       argc = 1;
        }
 
-       /* mandoc(1) */
+       switch (outmode) {
+       case OUTMODE_FLN:
+               for (i = 0; i < ressz; i++)
+                       puts(res[i].file);
+               goto out;
+       case OUTMODE_LST:
+               for (i = 0; i < ressz; i++)
+                       printf("%s - %s\n", res[i].names,
+                           res[i].output == NULL ? "" :
+                           res[i].output);
+               goto out;
+       default:
+               break;
+       }
 
 #if HAVE_PLEDGE
        if (outst.use_pager) {
@@ -581,8 +579,8 @@ main(int argc, char *argv[])
         */
        startdir = open(".", O_RDONLY | O_DIRECTORY);
 
-       while (argc-- > 0) {
-               process_onefile(mp, resp++, startdir, &outst, &conf);
+       for (i = 0; i < ressz; i++) {
+               process_onefile(mp, res + i, startdir, &outst, &conf);
                if (outst.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
                        break;
        }
@@ -614,7 +612,7 @@ main(int argc, char *argv[])
        mchars_free();
 
 out:
-       mansearch_free(res, sz);
+       mansearch_free(res, ressz);
        if (search.argmode != ARG_FILE)
                manconf_free(&conf);