version 1.67, 2016/07/20 00:23:14 |
version 1.77, 2017/08/22 17:50:11 |
|
|
/* $OpenBSD$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2013, 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <assert.h> |
#include <assert.h> |
|
#if HAVE_ERR |
#include <err.h> |
#include <err.h> |
|
#endif |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <glob.h> |
#include <glob.h> |
Line 65 static struct ohash *manmerge_term(struct expr *, stru |
|
Line 67 static struct ohash *manmerge_term(struct expr *, stru |
|
static struct ohash *manmerge_or(struct expr *, struct ohash *); |
static struct ohash *manmerge_or(struct expr *, struct ohash *); |
static struct ohash *manmerge_and(struct expr *, struct ohash *); |
static struct ohash *manmerge_and(struct expr *, struct ohash *); |
static char *buildnames(const struct dbm_page *); |
static char *buildnames(const struct dbm_page *); |
static char *buildoutput(size_t, int32_t); |
static char *buildoutput(size_t, struct dbm_page *); |
static size_t lstlen(const char *); |
static size_t lstlen(const char *, size_t); |
static void lstcat(char *, size_t *, const char *); |
static void lstcat(char *, size_t *, const char *, const char *); |
static int lstmatch(const char *, const char *); |
static int lstmatch(const char *, const char *); |
static struct expr *exprcomp(const struct mansearch *, |
static struct expr *exprcomp(const struct mansearch *, |
int, char *[], int *); |
int, char *[], int *); |
Line 102 mansearch(const struct mansearch *search, |
|
Line 104 mansearch(const struct mansearch *search, |
|
} |
} |
|
|
cur = maxres = 0; |
cur = maxres = 0; |
*res = NULL; |
if (res != NULL) |
|
*res = NULL; |
|
|
outkey = KEY_Nd; |
outkey = KEY_Nd; |
if (search->outkey != NULL) |
if (search->outkey != NULL) |
Line 153 mansearch(const struct mansearch *search, |
|
Line 156 mansearch(const struct mansearch *search, |
|
chdir_status = 1; |
chdir_status = 1; |
|
|
if (dbm_open(MANDOC_DB) == -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; |
continue; |
} |
} |
|
|
Line 167 mansearch(const struct mansearch *search, |
|
Line 171 mansearch(const struct mansearch *search, |
|
page = dbm_page_get(rp->page); |
page = dbm_page_get(rp->page); |
|
|
if (lstmatch(search->sec, page->sect) == 0 || |
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; |
continue; |
|
|
|
if (res == NULL) { |
|
cur = 1; |
|
break; |
|
} |
if (cur + 1 > maxres) { |
if (cur + 1 > maxres) { |
maxres += 1024; |
maxres += 1024; |
*res = mandoc_reallocarray(*res, |
*res = mandoc_reallocarray(*res, |
Line 178 mansearch(const struct mansearch *search, |
|
Line 188 mansearch(const struct mansearch *search, |
|
mpage = *res + cur; |
mpage = *res + cur; |
mandoc_asprintf(&mpage->file, "%s/%s", |
mandoc_asprintf(&mpage->file, "%s/%s", |
paths->paths[i], page->file + 1); |
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->names = buildnames(page); |
mpage->output = (int)outkey == KEY_Nd ? |
mpage->output = buildoutput(outkey, page); |
mandoc_strdup(page->desc) : |
|
buildoutput(outkey, page->addr); |
|
mpage->ipath = i; |
mpage->ipath = i; |
mpage->bits = rp->bits; |
mpage->bits = rp->bits; |
mpage->sec = *page->sect - '0'; |
mpage->sec = *page->sect - '0'; |
Line 203 mansearch(const struct mansearch *search, |
|
Line 221 mansearch(const struct mansearch *search, |
|
if (cur && search->firstmatch) |
if (cur && search->firstmatch) |
break; |
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) |
if (chdir_status && getcwd_status && chdir(buf) == -1) |
warn("%s", buf); |
warn("%s", buf); |
exprfree(e); |
exprfree(e); |
*sz = cur; |
*sz = cur; |
return 1; |
return res != NULL || cur; |
} |
} |
|
|
/* |
/* |
|
|
manpage_compare(const void *vp1, const void *vp2) |
manpage_compare(const void *vp1, const void *vp2) |
{ |
{ |
const struct manpage *mp1, *mp2; |
const struct manpage *mp1, *mp2; |
|
const char *cp1, *cp2; |
|
size_t sz1, sz2; |
int diff; |
int diff; |
|
|
mp1 = vp1; |
mp1 = vp1; |
mp2 = vp2; |
mp2 = vp2; |
return (diff = mp2->bits - mp1->bits) ? diff : |
if ((diff = mp2->bits - mp1->bits) || |
(diff = mp1->sec - mp2->sec) ? diff : |
(diff = mp1->sec - mp2->sec)) |
strcasecmp(mp1->names, mp2->names); |
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 * |
static char * |
Line 402 buildnames(const struct dbm_page *page) |
|
Line 437 buildnames(const struct dbm_page *page) |
|
char *buf; |
char *buf; |
size_t i, sz; |
size_t i, sz; |
|
|
sz = lstlen(page->name) + 1 + lstlen(page->sect) + |
sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) + |
(page->arch == NULL ? 0 : 1 + lstlen(page->arch)) + 2; |
(page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2; |
buf = mandoc_malloc(sz); |
buf = mandoc_malloc(sz); |
i = 0; |
i = 0; |
lstcat(buf, &i, page->name); |
lstcat(buf, &i, page->name, ", "); |
buf[i++] = '('; |
buf[i++] = '('; |
lstcat(buf, &i, page->sect); |
lstcat(buf, &i, page->sect, ", "); |
if (page->arch != NULL) { |
if (page->arch != NULL) { |
buf[i++] = '/'; |
buf[i++] = '/'; |
lstcat(buf, &i, page->arch); |
lstcat(buf, &i, page->arch, ", "); |
} |
} |
buf[i++] = ')'; |
buf[i++] = ')'; |
buf[i++] = '\0'; |
buf[i++] = '\0'; |
Line 421 buildnames(const struct dbm_page *page) |
|
Line 456 buildnames(const struct dbm_page *page) |
|
|
|
/* |
/* |
* Count the buffer space needed to print the NUL-terminated |
* Count the buffer space needed to print the NUL-terminated |
* list of NUL-terminated strings, when printing two separator |
* list of NUL-terminated strings, when printing sep separator |
* characters between strings. |
* characters between strings. |
*/ |
*/ |
static size_t |
static size_t |
lstlen(const char *cp) |
lstlen(const char *cp, size_t sep) |
{ |
{ |
size_t sz; |
size_t sz; |
|
|
for (sz = 0;; sz++) { |
for (sz = 0; *cp != '\0'; cp++) { |
if (cp[0] == '\0') { |
|
if (cp[1] == '\0') |
/* Skip names appearing only in the SYNOPSIS. */ |
break; |
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++; |
sz++; |
} else if (cp[0] < ' ') |
cp++; |
sz--; |
} |
cp++; |
|
} |
} |
return sz; |
return sz; |
} |
} |
|
|
/* |
/* |
* Print the NUL-terminated list of NUL-terminated strings |
* Print the NUL-terminated list of NUL-terminated strings |
* into the buffer, seperating strings with a comma and a blank. |
* into the buffer, seperating strings with sep. |
*/ |
*/ |
static void |
static void |
lstcat(char *buf, size_t *i, const char *cp) |
lstcat(char *buf, size_t *i, const char *cp, const char *sep) |
{ |
{ |
for (;;) { |
const char *s; |
if (cp[0] == '\0') { |
size_t i_start; |
if (cp[1] == '\0') |
|
break; |
for (i_start = *i; *cp != '\0'; cp++) { |
buf[(*i)++] = ','; |
|
buf[(*i)++] = ' '; |
/* Skip names appearing only in the SYNOPSIS. */ |
} else if (cp[0] >= ' ') |
if (*cp <= (char)(NAME_SYN & NAME_MASK)) { |
buf[(*i)++] = cp[0]; |
while (*cp != '\0') |
cp++; |
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++; |
|
} |
|
|
|
/* Copy one string. */ |
|
while (*cp != '\0') |
|
buf[(*i)++] = *cp++; |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
Line 480 lstmatch(const char *want, const char *have) |
|
Line 547 lstmatch(const char *want, const char *have) |
|
} |
} |
|
|
/* |
/* |
* Build a list of values taken by the macro im |
* Build a list of values taken by the macro im in the manual page. |
* in the manual page with big-endian address addr. |
|
*/ |
*/ |
static char * |
static char * |
buildoutput(size_t im, int32_t addr) |
buildoutput(size_t im, struct dbm_page *page) |
{ |
{ |
const char *oldoutput, *sep; |
const char *oldoutput, *sep, *input; |
char *output, *newoutput, *value; |
char *output, *newoutput, *value; |
|
size_t sz, i; |
|
|
|
switch (im) { |
|
case KEY_Nd: |
|
return mandoc_strdup(page->desc); |
|
case KEY_Nm: |
|
input = page->name; |
|
break; |
|
case KEY_sec: |
|
input = page->sect; |
|
break; |
|
case KEY_arch: |
|
input = page->arch; |
|
if (input == NULL) |
|
input = "all\0"; |
|
break; |
|
default: |
|
input = NULL; |
|
break; |
|
} |
|
|
|
if (input != NULL) { |
|
sz = lstlen(input, 3) + 1; |
|
output = mandoc_malloc(sz); |
|
i = 0; |
|
lstcat(output, &i, input, " # "); |
|
output[i++] = '\0'; |
|
assert(i == sz); |
|
return output; |
|
} |
|
|
output = NULL; |
output = NULL; |
dbm_macro_bypage(im - 2, addr); |
dbm_macro_bypage(im - 2, page->addr); |
while ((value = dbm_macro_next()) != NULL) { |
while ((value = dbm_macro_next()) != NULL) { |
if (output == NULL) { |
if (output == NULL) { |
oldoutput = ""; |
oldoutput = ""; |
Line 639 exprterm(const struct mansearch *search, int argc, cha |
|
Line 735 exprterm(const struct mansearch *search, int argc, cha |
|
warnx("unclosed parenthesis"); |
warnx("unclosed parenthesis"); |
return e; |
return e; |
} |
} |
|
|
|
if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) { |
|
cs = 0; |
|
++*argi; |
|
} else |
|
cs = 1; |
|
|
e = mandoc_calloc(1, sizeof(*e)); |
e = mandoc_calloc(1, sizeof(*e)); |
e->type = EXPR_TERM; |
e->type = EXPR_TERM; |