-/* $OpenBSD: mansearch.c,v 1.50 2016/07/09 15:23:36 schwarze Exp $ */
+/* $Id: mansearch.c,v 1.82 2019/07/01 22:56:24 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <string.h>
#include <unistd.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "manconf.h"
}
cur = maxres = 0;
- *res = NULL;
+ if (res != NULL)
+ *res = NULL;
outkey = KEY_Nd;
if (search->outkey != NULL)
chdir_status = 1;
if (dbm_open(MANDOC_DB) == -1) {
- warn("%s/%s", paths->paths[i], MANDOC_DB);
+ if (errno != ENOENT)
+ warn("%s/%s", paths->paths[i], MANDOC_DB);
continue;
}
page = dbm_page_get(rp->page);
if (lstmatch(search->sec, page->sect) == 0 ||
- lstmatch(search->arch, page->arch) == 0)
+ lstmatch(search->arch, page->arch) == 0 ||
+ (search->argmode == ARG_NAME &&
+ rp->bits <= (int32_t)(NAME_SYN & NAME_MASK)))
continue;
+ if (res == NULL) {
+ cur = 1;
+ break;
+ }
if (cur + 1 > maxres) {
maxres += 1024;
*res = mandoc_reallocarray(*res,
mpage = *res + cur;
mandoc_asprintf(&mpage->file, "%s/%s",
paths->paths[i], page->file + 1);
+ if (access(chdir_status ? page->file + 1 :
+ mpage->file, R_OK) == -1) {
+ warn("%s", mpage->file);
+ warnx("outdated mandoc.db contains "
+ "bogus %s entry, run makewhatis %s",
+ page->file + 1, paths->paths[i]);
+ free(mpage->file);
+ free(rp);
+ continue;
+ }
mpage->names = buildnames(page);
mpage->output = buildoutput(outkey, page);
+ mpage->bits = search->firstmatch ? rp->bits : 0;
mpage->ipath = i;
- mpage->bits = rp->bits;
mpage->sec = *page->sect - '0';
if (mpage->sec < 0 || mpage->sec > 9)
mpage->sec = 10;
if (cur && search->firstmatch)
break;
}
- qsort(*res, cur, sizeof(struct manpage), manpage_compare);
+ if (res != NULL)
+ qsort(*res, cur, sizeof(struct manpage), manpage_compare);
if (chdir_status && getcwd_status && chdir(buf) == -1)
warn("%s", buf);
exprfree(e);
*sz = cur;
- return 1;
+ return res != NULL || cur;
}
/*
manpage_compare(const void *vp1, const void *vp2)
{
const struct manpage *mp1, *mp2;
+ const char *cp1, *cp2;
+ size_t sz1, sz2;
int diff;
mp1 = vp1;
mp2 = vp2;
- return (diff = mp2->bits - mp1->bits) ? diff :
- (diff = mp1->sec - mp2->sec) ? diff :
- strcasecmp(mp1->names, mp2->names);
+ if ((diff = mp2->bits - mp1->bits) ||
+ (diff = mp1->sec - mp2->sec))
+ return diff;
+
+ /* Fall back to alphabetic ordering of names. */
+ sz1 = strcspn(mp1->names, "(");
+ sz2 = strcspn(mp2->names, "(");
+ if (sz1 < sz2)
+ sz1 = sz2;
+ if ((diff = strncasecmp(mp1->names, mp2->names, sz1)))
+ return diff;
+
+ /* For identical names and sections, prefer arch-dependent. */
+ cp1 = strchr(mp1->names + sz1, '/');
+ cp2 = strchr(mp2->names + sz2, '/');
+ return cp1 != NULL && cp2 != NULL ? strcasecmp(cp1, cp2) :
+ cp1 != NULL ? -1 : cp2 != NULL ? 1 : 0;
}
static char *
{
size_t sz;
- for (sz = 0;; sz++) {
- if (cp[0] == '\0') {
- if (cp[1] == '\0')
- break;
- sz += sep - 1;
- } else if (cp[0] < ' ')
- sz--;
- cp++;
+ for (sz = 0; *cp != '\0'; cp++) {
+
+ /* Skip names appearing only in the SYNOPSIS. */
+ if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
+ while (*cp != '\0')
+ cp++;
+ continue;
+ }
+
+ /* Skip name class markers. */
+ if (*cp < ' ')
+ cp++;
+
+ /* Print a separator before each but the first string. */
+ if (sz)
+ sz += sep;
+
+ /* Copy one string. */
+ while (*cp != '\0') {
+ sz++;
+ cp++;
+ }
}
return sz;
}
static void
lstcat(char *buf, size_t *i, const char *cp, const char *sep)
{
- const char *s;
+ const char *s;
+ size_t i_start;
- for (;;) {
- if (cp[0] == '\0') {
- if (cp[1] == '\0')
- break;
+ for (i_start = *i; *cp != '\0'; cp++) {
+
+ /* Skip names appearing only in the SYNOPSIS. */
+ if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
+ while (*cp != '\0')
+ cp++;
+ continue;
+ }
+
+ /* Skip name class markers. */
+ if (*cp < ' ')
+ cp++;
+
+ /* Print a separator before each but the first string. */
+ if (*i > i_start) {
s = sep;
while (*s != '\0')
buf[(*i)++] = *s++;
- } else if (cp[0] >= ' ')
- buf[(*i)++] = cp[0];
- cp++;
+ }
+
+ /* Copy one string. */
+ while (*cp != '\0')
+ buf[(*i)++] = *cp++;
}
+
}
/*
return e;
}
+ if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) {
+ cs = 0;
+ ++*argi;
+ } else
+ cs = 1;
+
e = mandoc_calloc(1, sizeof(*e));
e->type = EXPR_TERM;
e->bits = 0;
* If needed, request regular expression handling.
*/
- cs = 1;
if (search->argmode == ARG_WORD) {
e->bits = TYPE_Nm;
e->match.type = DBM_REGEX;
cs = 0;
} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
e->bits = TYPE_Nm | TYPE_Nd;
- e->match.type = DBM_SUB;
- e->match.str = argv[*argi];
+ e->match.type = DBM_REGEX;
+ val = argv[*argi];
+ cs = 0;
} else {
if (val == argv[*argi])
e->bits = TYPE_Nm | TYPE_Nd;