Be developer-friendly, 'cause OpenBSD devs like to:
authorschwarze <schwarze@openbsd.org>
Tue, 13 Jan 2015 23:16:12 +0000 (23:16 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 13 Jan 2015 23:16:12 +0000 (23:16 +0000)
cd /usr/src/share/man/man4; vi newdev.4 Makefile; make install; man newdev

When a manual is missing from an outdated database, let man(1)
show it anyway, using a KISS file system lookup as a fallback.
Requested by deraadt@.

87 new lines of code doesn't seem too much bloat to me.

Of course, keeping your mandoc.db(5) files up to date with makewhatis(8)
or weekly(8) is still required for apropos(1) to find your new pages.

usr.bin/mandoc/main.c

index 5558923..b607d94 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.118 2015/01/13 13:22:13 schwarze Exp $ */
+/*     $OpenBSD: main.c,v 1.119 2015/01/13 23:16:12 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -75,6 +75,13 @@ struct       curparse {
        char              outopts[BUFSIZ]; /* buf of output opts */
 };
 
+static int               fs_lookup(const struct manpaths *,
+                               size_t ipath, const char *,
+                               const char *, const char *,
+                               struct manpage **, size_t *);
+static void              fs_search(const struct mansearch *,
+                               const struct manpaths *, int, char**,
+                               struct manpage **, size_t *);
 static int               koptions(int *, char *);
 int                      mandocdb(int, char**);
 static int               moptions(int *, char *);
@@ -313,12 +320,11 @@ main(int argc, char *argv[])
                mansearch_setup(1);
                if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
                        usage(search.argmode);
-               resp = res;
+
+               if (sz == 0 && search.argmode == ARG_NAME)
+                       fs_search(&search, &paths, argc, argv, &res, &sz);
 
                if (sz == 0) {
-                       if (search.argmode == ARG_NAME)
-                               fprintf(stderr, "%s: No entry for %s "
-                                   "in the manual.\n", progname, argv[0]);
                        rc = MANDOCLEVEL_BADARG;
                        goto out;
                }
@@ -337,6 +343,7 @@ main(int argc, char *argv[])
 
                /* Iterate all matching manuals. */
 
+               resp = res;
                for (i = 0; i < sz; i++) {
                        if (outmode == OUTMODE_FLN)
                                puts(res[i].file);
@@ -482,6 +489,96 @@ usage(enum argmode argmode)
        exit((int)MANDOCLEVEL_BADARG);
 }
 
+static int
+fs_lookup(const struct manpaths *paths, size_t ipath,
+       const char *sec, const char *arch, const char *name,
+       struct manpage **res, size_t *ressz)
+{
+       struct manpage  *page;
+       char            *file;
+       int              form;
+
+       mandoc_asprintf(&file, "%s/man%s/%s.%s",
+           paths->paths[ipath], sec, name, sec);
+       if (access(file, R_OK) != -1) {
+               form = FORM_SRC;
+               goto found;
+       }
+       free(file);
+
+       mandoc_asprintf(&file, "%s/cat%s/%s.0",
+           paths->paths[ipath], sec, name);
+       if (access(file, R_OK) != -1) {
+               form = FORM_CAT;
+               goto found;
+       }
+       free(file);
+
+       if (arch != NULL) {
+               mandoc_asprintf(&file, "%s/man%s/%s/%s.%s",
+                   paths->paths[ipath], sec, arch, name, sec);
+               if (access(file, R_OK) != -1) {
+                       form = FORM_SRC;
+                       goto found;
+               }
+               free(file);
+       }
+       return(0);
+
+found:
+       fprintf(stderr, "%s: outdated mandoc.db lacks %s(%s) entry,\n"
+           "     consider running  # makewhatis %s\n",
+           progname, name, sec, paths->paths[ipath]);
+       
+       *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
+       page = *res + (*ressz - 1);
+       page->file = file;
+       page->names = NULL;
+       page->output = NULL;
+       page->ipath = ipath;
+       page->bits = NAME_FILE & NAME_MASK;
+       page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+       page->form = form;
+       return(1);
+}
+
+static void
+fs_search(const struct mansearch *cfg, const struct manpaths *paths,
+       int argc, char **argv, struct manpage **res, size_t *ressz)
+{
+       const char *const sections[] =
+           {"1", "8", "6", "2", "3", "3p", "5", "7", "4", "9"};
+       const size_t nsec = sizeof(sections)/sizeof(sections[0]);
+
+       size_t           ipath, isec, lastsz;
+
+       assert(cfg->argmode == ARG_NAME);
+
+       *res = NULL;
+       *ressz = lastsz = 0;
+       while (argc) {
+               for (ipath = 0; ipath < paths->sz; ipath++) {
+                       if (cfg->sec != NULL) {
+                               if (fs_lookup(paths, ipath, cfg->sec,
+                                   cfg->arch, *argv, res, ressz) &&
+                                   cfg->firstmatch)
+                                       return;
+                       } else for (isec = 0; isec < nsec; isec++)
+                               if (fs_lookup(paths, ipath, sections[isec],
+                                   cfg->arch, *argv, res, ressz) &&
+                                   cfg->firstmatch)
+                                       return;
+               }
+               if (*ressz == lastsz)
+                       fprintf(stderr,
+                           "%s: No entry for %s in the manual.\n",
+                           progname, *argv);
+               lastsz = *ressz;
+               argv++;
+               argc--;
+       }
+}
+
 static void
 parse(struct curparse *curp, int fd, const char *file,
        enum mandoclevel *level)