summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2021-09-04 12:52:57 +0000
committerIngo Schwarze <schwarze@openbsd.org>2021-09-04 12:52:57 +0000
commit0882dc0b36dd3ae4623b9707ee964e7ca83ae665 (patch)
tree445123f545ab78b15f849a22cc159397ce1520aa
parent85c3fdaead0d311f9f74a2da69f7ba1e8fe998fd (diff)
downloadmandoc-0882dc0b36dd3ae4623b9707ee964e7ca83ae665.tar.gz
In the fallback code to look for manual pages without using mandoc.db(5),
accept files "man<one-digit-section>/<name>.<full-section>" in addition to the already supported "man<full-section>/name.[01-9]*". Needed for example on Alpine Linux which puts its Perl manuals into "man3/<name>.3pm" and the POSIX manuals into "man3/<name>.3p". While here, allow the glob(3) at the end of fs_lookup() to add multiple matches to the result set. This improves man -w output and may also help some cases of plain man(1), allowing main() to prioritize properly rather than fs_lookup() picking a random match. Issue reported and patch tested by Soeren Tempel <soeren at soeren hyphen tempel dot net>.
-rw-r--r--main.c86
1 files changed, 65 insertions, 21 deletions
diff --git a/main.c b/main.c
index 768d7dc1..f7c1ce9a 100644
--- a/main.c
+++ b/main.c
@@ -94,9 +94,11 @@ struct outstate {
int mandocdb(int, char *[]);
static void check_xr(struct manpaths *);
-static int fs_lookup(const struct manpaths *,
- size_t ipath, const char *,
- const char *, const char *,
+static void fs_append(char **, size_t, int,
+ size_t, const char *, enum form,
+ struct manpage **, size_t *);
+static int fs_lookup(const struct manpaths *, size_t,
+ const char *, const char *, const char *,
struct manpage **, size_t *);
static int fs_search(const struct mansearch *,
const struct manpaths *, const char *,
@@ -700,6 +702,30 @@ glob_esc(char **dst, const char *src, const char *suffix)
*(*dst)++ = *suffix++;
}
+static void
+fs_append(char **file, size_t filesz, int copy, size_t ipath,
+ const char *sec, enum form form, struct manpage **res, size_t *ressz)
+{
+ struct manpage *page;
+
+ *res = mandoc_reallocarray(*res, *ressz + filesz, sizeof(**res));
+ page = *res + *ressz;
+ *ressz += filesz;
+ for (;;) {
+ page->file = copy ? mandoc_strdup(*file) : *file;
+ page->names = NULL;
+ page->output = NULL;
+ page->bits = NAME_FILE & NAME_MASK;
+ page->ipath = ipath;
+ page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+ page->form = form;
+ if (--filesz == 0)
+ break;
+ file++;
+ page++;
+ }
+}
+
static int
fs_lookup(const struct manpaths *paths, size_t ipath,
const char *sec, const char *arch, const char *name,
@@ -707,16 +733,19 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
{
struct stat sb;
glob_t globinfo;
- struct manpage *page;
- char *file, *cp;
+ char *file, *cp, secnum[2];
int globres;
enum form form;
const char *const slman = "/man";
const char *const slash = "/";
const char *const sglob = ".[01-9]*";
+ const char *const dot = ".";
+ const char *const aster = "*";
+ memset(&globinfo, 0, sizeof(globinfo));
form = FORM_SRC;
+
mandoc_asprintf(&file, "%s/man%s/%s.%s",
paths->paths[ipath], sec, name, sec);
if (stat(file, &sb) != -1)
@@ -751,14 +780,34 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
mandoc_msg(MANDOCERR_GLOB, 0, 0,
"%s: %s", file, strerror(errno));
free(file);
+ file = NULL;
if (globres == 0)
- file = mandoc_strdup(*globinfo.gl_pathv);
+ goto found;
globfree(&globinfo);
- if (globres == 0) {
- if (stat(file, &sb) != -1)
- goto found;
+
+ if (sec[1] != '\0' && *ressz == 0) {
+ secnum[0] = sec[0];
+ secnum[1] = '\0';
+ cp = file = mandoc_malloc(strlen(paths->paths[ipath]) * 2 +
+ strlen(slman) + strlen(secnum) * 2 + strlen(slash) +
+ strlen(name) * 2 + strlen(dot) +
+ strlen(sec) * 2 + strlen(aster) + 1);
+ glob_esc(&cp, paths->paths[ipath], slman);
+ glob_esc(&cp, secnum, slash);
+ glob_esc(&cp, name, dot);
+ glob_esc(&cp, sec, aster);
+ *cp = '\0';
+ globres = glob(file, 0, NULL, &globinfo);
+ if (globres != 0 && globres != GLOB_NOMATCH)
+ mandoc_msg(MANDOCERR_GLOB, 0, 0,
+ "%s: %s", file, strerror(errno));
free(file);
+ file = NULL;
+ if (globres == 0)
+ goto found;
+ globfree(&globinfo);
}
+
if (res != NULL || ipath + 1 != paths->sz)
return -1;
@@ -770,19 +819,14 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
found:
warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
- if (res == NULL) {
+ if (res == NULL)
free(file);
- return 0;
- }
- *res = mandoc_reallocarray(*res, ++*ressz, sizeof(**res));
- page = *res + (*ressz - 1);
- page->file = file;
- page->names = NULL;
- page->output = NULL;
- page->bits = NAME_FILE & NAME_MASK;
- page->ipath = ipath;
- page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
- page->form = form;
+ else if (file == NULL)
+ fs_append(globinfo.gl_pathv, globinfo.gl_pathc, 1,
+ ipath, sec, form, res, ressz);
+ else
+ fs_append(&file, 1, 0, ipath, sec, form, res, ressz);
+ globfree(&globinfo);
return 0;
}