Merge mdocml 1.12.3.

This commit is contained in:
joerg 2014-01-05 19:27:20 +00:00
parent 12f8f2b852
commit 603fc4ebb9
23 changed files with 1300 additions and 2771 deletions

View File

@ -1,876 +0,0 @@
/* $Vendor-Id: apropos_db.c,v 1.31 2012/03/24 01:46:25 kristaps Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <fcntl.h>
#include <regex.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(__linux__)
# include <endian.h>
# include <db_185.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# include <db.h>
#else
# include <db.h>
#endif
#include "mandocdb.h"
#include "apropos_db.h"
#include "mandoc.h"
#define RESFREE(_x) \
do { \
free((_x)->file); \
free((_x)->cat); \
free((_x)->title); \
free((_x)->arch); \
free((_x)->desc); \
free((_x)->matches); \
} while (/*CONSTCOND*/0)
struct expr {
int regex; /* is regex? */
int index; /* index in match array */
uint64_t mask; /* type-mask */
int and; /* is rhs of logical AND? */
char *v; /* search value */
regex_t re; /* compiled re, if regex */
struct expr *next; /* next in sequence */
struct expr *subexpr;
};
struct type {
uint64_t mask;
const char *name;
};
struct rectree {
struct res *node; /* record array for dir tree */
int len; /* length of record array */
};
static const struct type types[] = {
{ TYPE_An, "An" },
{ TYPE_Ar, "Ar" },
{ TYPE_At, "At" },
{ TYPE_Bsx, "Bsx" },
{ TYPE_Bx, "Bx" },
{ TYPE_Cd, "Cd" },
{ TYPE_Cm, "Cm" },
{ TYPE_Dv, "Dv" },
{ TYPE_Dx, "Dx" },
{ TYPE_Em, "Em" },
{ TYPE_Er, "Er" },
{ TYPE_Ev, "Ev" },
{ TYPE_Fa, "Fa" },
{ TYPE_Fl, "Fl" },
{ TYPE_Fn, "Fn" },
{ TYPE_Fn, "Fo" },
{ TYPE_Ft, "Ft" },
{ TYPE_Fx, "Fx" },
{ TYPE_Ic, "Ic" },
{ TYPE_In, "In" },
{ TYPE_Lb, "Lb" },
{ TYPE_Li, "Li" },
{ TYPE_Lk, "Lk" },
{ TYPE_Ms, "Ms" },
{ TYPE_Mt, "Mt" },
{ TYPE_Nd, "Nd" },
{ TYPE_Nm, "Nm" },
{ TYPE_Nx, "Nx" },
{ TYPE_Ox, "Ox" },
{ TYPE_Pa, "Pa" },
{ TYPE_Rs, "Rs" },
{ TYPE_Sh, "Sh" },
{ TYPE_Ss, "Ss" },
{ TYPE_St, "St" },
{ TYPE_Sy, "Sy" },
{ TYPE_Tn, "Tn" },
{ TYPE_Va, "Va" },
{ TYPE_Va, "Vt" },
{ TYPE_Xr, "Xr" },
{ UINT64_MAX, "any" },
{ 0, NULL }
};
static DB *btree_open(void);
static int btree_read(const DBT *, const DBT *,
const struct mchars *,
uint64_t *, recno_t *, char **);
static int expreval(const struct expr *, int *);
static void exprexec(const struct expr *,
const char *, uint64_t, struct res *);
static int exprmark(const struct expr *,
const char *, uint64_t, int *);
static struct expr *exprexpr(int, char *[], int *, int *, size_t *);
static struct expr *exprterm(char *, int);
static DB *index_open(void);
static int index_read(const DBT *, const DBT *, int,
const struct mchars *, struct res *);
static void norm_string(const char *,
const struct mchars *, char **);
static size_t norm_utf8(unsigned int, char[7]);
static int single_search(struct rectree *, const struct opts *,
const struct expr *, size_t terms,
struct mchars *, int);
/*
* Open the keyword mandoc-db database.
*/
static DB *
btree_open(void)
{
BTREEINFO info;
DB *db;
memset(&info, 0, sizeof(BTREEINFO));
info.lorder = 4321;
info.flags = R_DUP;
db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
if (NULL != db)
return(db);
return(NULL);
}
/*
* Read a keyword from the database and normalise it.
* Return 0 if the database is insane, else 1.
*/
static int
btree_read(const DBT *k, const DBT *v, const struct mchars *mc,
uint64_t *mask, recno_t *rec, char **buf)
{
uint64_t vbuf[2];
/* Are our sizes sane? */
if (k->size < 2 || sizeof(vbuf) != v->size)
return(0);
/* Is our string nil-terminated? */
if ('\0' != ((const char *)k->data)[(int)k->size - 1])
return(0);
norm_string((const char *)k->data, mc, buf);
memcpy(vbuf, v->data, v->size);
*mask = betoh64(vbuf[0]);
*rec = betoh64(vbuf[1]);
return(1);
}
/*
* Take a Unicode codepoint and produce its UTF-8 encoding.
* This isn't the best way to do this, but it works.
* The magic numbers are from the UTF-8 packaging.
* They're not as scary as they seem: read the UTF-8 spec for details.
*/
static size_t
norm_utf8(unsigned int cp, char out[7])
{
int rc;
rc = 0;
if (cp <= 0x0000007F) {
rc = 1;
out[0] = (char)cp;
} else if (cp <= 0x000007FF) {
rc = 2;
out[0] = (cp >> 6 & 31) | 192;
out[1] = (cp & 63) | 128;
} else if (cp <= 0x0000FFFF) {
rc = 3;
out[0] = (cp >> 12 & 15) | 224;
out[1] = (cp >> 6 & 63) | 128;
out[2] = (cp & 63) | 128;
} else if (cp <= 0x001FFFFF) {
rc = 4;
out[0] = (cp >> 18 & 7) | 240;
out[1] = (cp >> 12 & 63) | 128;
out[2] = (cp >> 6 & 63) | 128;
out[3] = (cp & 63) | 128;
} else if (cp <= 0x03FFFFFF) {
rc = 5;
out[0] = (cp >> 24 & 3) | 248;
out[1] = (cp >> 18 & 63) | 128;
out[2] = (cp >> 12 & 63) | 128;
out[3] = (cp >> 6 & 63) | 128;
out[4] = (cp & 63) | 128;
} else if (cp <= 0x7FFFFFFF) {
rc = 6;
out[0] = (cp >> 30 & 1) | 252;
out[1] = (cp >> 24 & 63) | 128;
out[2] = (cp >> 18 & 63) | 128;
out[3] = (cp >> 12 & 63) | 128;
out[4] = (cp >> 6 & 63) | 128;
out[5] = (cp & 63) | 128;
} else
return(0);
out[rc] = '\0';
return((size_t)rc);
}
/*
* Normalise strings from the index and database.
* These strings are escaped as defined by mandoc_char(7) along with
* other goop in mandoc.h (e.g., soft hyphens).
* This function normalises these into a nice UTF-8 string.
* Returns 0 if the database is fucked.
*/
static void
norm_string(const char *val, const struct mchars *mc, char **buf)
{
size_t sz, bsz;
char utfbuf[7];
const char *seq, *cpp;
int len, u, pos;
enum mandoc_esc esc;
static const char res[] = { '\\', '\t',
ASCII_NBRSP, ASCII_HYPH, '\0' };
/* Pre-allocate by the length of the input */
bsz = strlen(val) + 1;
*buf = mandoc_realloc(*buf, bsz);
pos = 0;
while ('\0' != *val) {
/*
* Halt on the first escape sequence.
* This also halts on the end of string, in which case
* we just copy, fallthrough, and exit the loop.
*/
if ((sz = strcspn(val, res)) > 0) {
memcpy(&(*buf)[pos], val, sz);
pos += (int)sz;
val += (int)sz;
}
if (ASCII_HYPH == *val) {
(*buf)[pos++] = '-';
val++;
continue;
} else if ('\t' == *val || ASCII_NBRSP == *val) {
(*buf)[pos++] = ' ';
val++;
continue;
} else if ('\\' != *val)
break;
/* Read past the slash. */
val++;
u = 0;
/*
* Parse the escape sequence and see if it's a
* predefined character or special character.
*/
esc = mandoc_escape(&val, &seq, &len);
if (ESCAPE_ERROR == esc)
break;
/*
* XXX - this just does UTF-8, but we need to know
* beforehand whether we should do text substitution.
*/
switch (esc) {
case (ESCAPE_SPECIAL):
if (0 != (u = mchars_spec2cp(mc, seq, len)))
break;
/* FALLTHROUGH */
default:
continue;
}
/*
* If we have a Unicode codepoint, try to convert that
* to a UTF-8 byte string.
*/
cpp = utfbuf;
if (0 == (sz = norm_utf8(u, utfbuf)))
continue;
/* Copy the rendered glyph into the stream. */
sz = strlen(cpp);
bsz += sz;
*buf = mandoc_realloc(*buf, bsz);
memcpy(&(*buf)[pos], cpp, sz);
pos += (int)sz;
}
(*buf)[pos] = '\0';
}
/*
* Open the filename-index mandoc-db database.
* Returns NULL if opening failed.
*/
static DB *
index_open(void)
{
DB *db;
db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL);
if (NULL != db)
return(db);
return(NULL);
}
/*
* Safely unpack from an index file record into the structure.
* Returns 1 if an entry was unpacked, 0 if the database is insane.
*/
static int
index_read(const DBT *key, const DBT *val, int index,
const struct mchars *mc, struct res *rec)
{
size_t left;
char *np, *cp;
char type;
#define INDEX_BREAD(_dst) \
do { \
if (NULL == (np = memchr(cp, '\0', left))) \
return(0); \
norm_string(cp, mc, &(_dst)); \
left -= (np - cp) + 1; \
cp = np + 1; \
} while (/* CONSTCOND */ 0)
if (0 == (left = val->size))
return(0);
cp = val->data;
assert(sizeof(recno_t) == key->size);
memcpy(&rec->rec, key->data, key->size);
rec->volume = index;
if ('d' == (type = *cp++))
rec->type = RESTYPE_MDOC;
else if ('a' == type)
rec->type = RESTYPE_MAN;
else if ('c' == type)
rec->type = RESTYPE_CAT;
else
return(0);
left--;
INDEX_BREAD(rec->file);
INDEX_BREAD(rec->cat);
INDEX_BREAD(rec->title);
INDEX_BREAD(rec->arch);
INDEX_BREAD(rec->desc);
return(1);
}
/*
* Search mandocdb databases in paths for expression "expr".
* Filter out by "opts".
* Call "res" with the results, which may be zero.
* Return 0 if there was a database error, else return 1.
*/
int
apropos_search(int pathsz, char **paths, const struct opts *opts,
const struct expr *expr, size_t terms, void *arg,
size_t *sz, struct res **resp,
void (*res)(struct res *, size_t, void *))
{
struct rectree tree;
struct mchars *mc;
int i, rc;
memset(&tree, 0, sizeof(struct rectree));
rc = 0;
mc = mchars_alloc();
*sz = 0;
*resp = NULL;
/*
* Main loop. Change into the directory containing manpage
* databases. Run our expession over each database in the set.
*/
for (i = 0; i < pathsz; i++) {
if (chdir(paths[i]))
continue;
if (single_search(&tree, opts, expr, terms, mc, i))
continue;
resfree(tree.node, tree.len);
mchars_free(mc);
return(0);
}
(*res)(tree.node, tree.len, arg);
*sz = tree.len;
*resp = tree.node;
mchars_free(mc);
return(1);
}
static int
single_search(struct rectree *tree, const struct opts *opts,
const struct expr *expr, size_t terms,
struct mchars *mc, int vol)
{
int root, leaf, ch;
DBT key, val;
DB *btree, *idx;
char *buf;
struct res *rs;
struct res r;
uint64_t mask;
recno_t rec;
root = -1;
leaf = -1;
btree = NULL;
idx = NULL;
buf = NULL;
rs = tree->node;
memset(&r, 0, sizeof(struct res));
if (NULL == (btree = btree_open()))
return(1);
if (NULL == (idx = index_open())) {
(*btree->close)(btree);
return(1);
}
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf))
break;
/*
* See if this keyword record matches any of the
* expressions we have stored.
*/
if ( ! exprmark(expr, buf, mask, NULL))
continue;
/*
* O(log n) scan for prior records. Since a record
* number is unbounded, this has decent performance over
* a complex hash function.
*/
for (leaf = root; leaf >= 0; )
if (rec > rs[leaf].rec &&
rs[leaf].rhs >= 0)
leaf = rs[leaf].rhs;
else if (rec < rs[leaf].rec &&
rs[leaf].lhs >= 0)
leaf = rs[leaf].lhs;
else
break;
/*
* If we find a record, see if it has already evaluated
* to true. If it has, great, just keep going. If not,
* try to evaluate it now and continue anyway.
*/
if (leaf >= 0 && rs[leaf].rec == rec) {
if (0 == rs[leaf].matched)
exprexec(expr, buf, mask, &rs[leaf]);
continue;
}
/*
* We have a new file to examine.
* Extract the manpage's metadata from the index
* database, then begin partial evaluation.
*/
key.data = &rec;
key.size = sizeof(recno_t);
if (0 != (*idx->get)(idx, &key, &val, 0))
break;
r.lhs = r.rhs = -1;
if ( ! index_read(&key, &val, vol, mc, &r))
break;
/* XXX: this should be elsewhere, I guess? */
if (opts->cat && strcasecmp(opts->cat, r.cat))
continue;
if (opts->arch && *r.arch)
if (strcasecmp(opts->arch, r.arch))
continue;
tree->node = rs = mandoc_realloc
(rs, (tree->len + 1) * sizeof(struct res));
memcpy(&rs[tree->len], &r, sizeof(struct res));
memset(&r, 0, sizeof(struct res));
rs[tree->len].matches =
mandoc_calloc(terms, sizeof(int));
exprexec(expr, buf, mask, &rs[tree->len]);
/* Append to our tree. */
if (leaf >= 0) {
if (rec > rs[leaf].rec)
rs[leaf].rhs = tree->len;
else
rs[leaf].lhs = tree->len;
} else
root = tree->len;
tree->len++;
}
(*btree->close)(btree);
(*idx->close)(idx);
free(buf);
RESFREE(&r);
return(1 == ch);
}
void
resfree(struct res *rec, size_t sz)
{
size_t i;
for (i = 0; i < sz; i++)
RESFREE(&rec[i]);
free(rec);
}
/*
* Compile a list of straight-up terms.
* The arguments are re-written into ~[[:<:]]term[[:>:]], or "term"
* surrounded by word boundaries, then pumped through exprterm().
* Terms are case-insensitive.
* This emulates whatis(1) behaviour.
*/
struct expr *
termcomp(int argc, char *argv[], size_t *tt)
{
char *buf;
int pos;
struct expr *e, *next;
size_t sz;
buf = NULL;
e = NULL;
*tt = 0;
for (pos = argc - 1; pos >= 0; pos--) {
sz = strlen(argv[pos]) + 18;
buf = mandoc_realloc(buf, sz);
strlcpy(buf, "Nm~[[:<:]]", sz);
strlcat(buf, argv[pos], sz);
strlcat(buf, "[[:>:]]", sz);
if (NULL == (next = exprterm(buf, 0))) {
free(buf);
exprfree(e);
return(NULL);
}
next->next = e;
e = next;
(*tt)++;
}
free(buf);
return(e);
}
/*
* Compile a sequence of logical expressions.
* See apropos.1 for a grammar of this sequence.
*/
struct expr *
exprcomp(int argc, char *argv[], size_t *tt)
{
int pos, lvl;
struct expr *e;
pos = lvl = 0;
*tt = 0;
e = exprexpr(argc, argv, &pos, &lvl, tt);
if (0 == lvl && pos >= argc)
return(e);
exprfree(e);
return(NULL);
}
/*
* Compile an array of tokens into an expression.
* An informal expression grammar is defined in apropos(1).
* Return NULL if we fail doing so. All memory will be cleaned up.
* Return the root of the expression sequence if alright.
*/
static struct expr *
exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt)
{
struct expr *e, *first, *next;
int log;
first = next = NULL;
for ( ; *pos < argc; (*pos)++) {
e = next;
/*
* Close out a subexpression.
*/
if (NULL != e && 0 == strcmp(")", argv[*pos])) {
if (--(*lvl) < 0)
goto err;
break;
}
/*
* Small note: if we're just starting, don't let "-a"
* and "-o" be considered logical operators: they're
* just tokens unless pairwise joining, in which case we
* record their existence (or assume "OR").
*/
log = 0;
if (NULL != e && 0 == strcmp("-a", argv[*pos]))
log = 1;
else if (NULL != e && 0 == strcmp("-o", argv[*pos]))
log = 2;
if (log > 0 && ++(*pos) >= argc)
goto err;
/*
* Now we parse the term part. This can begin with
* "-i", in which case the expression is case
* insensitive.
*/
if (0 == strcmp("(", argv[*pos])) {
++(*pos);
++(*lvl);
next = mandoc_calloc(1, sizeof(struct expr));
next->subexpr = exprexpr(argc, argv, pos, lvl, tt);
if (NULL == next->subexpr) {
free(next);
next = NULL;
}
} else if (0 == strcmp("-i", argv[*pos])) {
if (++(*pos) >= argc)
goto err;
next = exprterm(argv[*pos], 0);
} else
next = exprterm(argv[*pos], 1);
if (NULL == next)
goto err;
next->and = log == 1;
next->index = (int)(*tt)++;
/* Append to our chain of expressions. */
if (NULL == first) {
assert(NULL == e);
first = next;
} else {
assert(NULL != e);
e->next = next;
}
}
return(first);
err:
exprfree(first);
return(NULL);
}
/*
* Parse a terminal expression with the grammar as defined in
* apropos(1).
* Return NULL if we fail the parse.
*/
static struct expr *
exprterm(char *buf, int cs)
{
struct expr e;
struct expr *p;
char *key;
int i;
memset(&e, 0, sizeof(struct expr));
/* Choose regex or substring match. */
if (NULL == (e.v = strpbrk(buf, "=~"))) {
e.regex = 0;
e.v = buf;
} else {
e.regex = '~' == *e.v;
*e.v++ = '\0';
}
/* Determine the record types to search for. */
e.mask = 0;
if (buf < e.v) {
while (NULL != (key = strsep(&buf, ","))) {
i = 0;
while (types[i].mask &&
strcmp(types[i].name, key))
i++;
e.mask |= types[i].mask;
}
}
if (0 == e.mask)
e.mask = TYPE_Nm | TYPE_Nd;
if (e.regex) {
i = REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE);
if (regcomp(&e.re, e.v, i))
return(NULL);
}
e.v = mandoc_strdup(e.v);
p = mandoc_calloc(1, sizeof(struct expr));
memcpy(p, &e, sizeof(struct expr));
return(p);
}
void
exprfree(struct expr *p)
{
struct expr *pp;
while (NULL != p) {
if (p->subexpr)
exprfree(p->subexpr);
if (p->regex)
regfree(&p->re);
free(p->v);
pp = p->next;
free(p);
p = pp;
}
}
static int
exprmark(const struct expr *p, const char *cp,
uint64_t mask, int *ms)
{
for ( ; p; p = p->next) {
if (p->subexpr) {
if (exprmark(p->subexpr, cp, mask, ms))
return(1);
continue;
} else if ( ! (mask & p->mask))
continue;
if (p->regex) {
if (regexec(&p->re, cp, 0, NULL, 0))
continue;
} else if (NULL == strcasestr(cp, p->v))
continue;
if (NULL == ms)
return(1);
else
ms[p->index] = 1;
}
return(0);
}
static int
expreval(const struct expr *p, int *ms)
{
int match;
/*
* AND has precedence over OR. Analysis is left-right, though
* it doesn't matter because there are no side-effects.
* Thus, step through pairwise ANDs and accumulate their Boolean
* evaluation. If we encounter a single true AND collection or
* standalone term, the whole expression is true (by definition
* of OR).
*/
for (match = 0; p && ! match; p = p->next) {
/* Evaluate a subexpression, if applicable. */
if (p->subexpr && ! ms[p->index])
ms[p->index] = expreval(p->subexpr, ms);
match = ms[p->index];
for ( ; p->next && p->next->and; p = p->next) {
/* Evaluate a subexpression, if applicable. */
if (p->next->subexpr && ! ms[p->next->index])
ms[p->next->index] =
expreval(p->next->subexpr, ms);
match = match && ms[p->next->index];
}
}
return(match);
}
/*
* First, update the array of terms for which this expression evaluates
* to true.
* Second, logically evaluate all terms over the updated array of truth
* values.
* If this evaluates to true, mark the expression as satisfied.
*/
static void
exprexec(const struct expr *e, const char *cp,
uint64_t mask, struct res *r)
{
assert(0 == r->matched);
exprmark(e, cp, mask, r->matches);
r->matched = expreval(e, r->matches);
}

View File

@ -1,73 +0,0 @@
/* $Vendor-Id: apropos_db.h,v 1.13 2012/03/24 01:46:25 kristaps Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef APROPOS_H
#define APROPOS_H
enum restype {
RESTYPE_MAN, /* man(7) file */
RESTYPE_MDOC, /* mdoc(7) file */
RESTYPE_CAT /* pre-formatted file */
};
struct res {
enum restype type; /* input file type */
char *file; /* file in file-system */
char *cat; /* category (3p, 3, etc.) */
char *title; /* title (FOO, etc.) */
char *arch; /* arch (or empty string) */
char *desc; /* description (from Nd) */
unsigned int rec; /* record in index */
/*
* The index volume. This indexes into the array of directories
* searched for manual page databases.
*/
unsigned int volume;
/*
* The following fields are used internally.
*
* Maintain a binary tree for checking the uniqueness of `rec'
* when adding elements to the results array.
* Since the results array is dynamic, use offset in the array
* instead of a pointer to the structure.
*/
int lhs;
int rhs;
int matched; /* expression is true */
int *matches; /* partial truth evaluations */
};
struct opts {
const char *arch; /* restrict to architecture */
const char *cat; /* restrict to manual section */
};
__BEGIN_DECLS
struct expr;
int apropos_search(int, char **, const struct opts *,
const struct expr *, size_t,
void *, size_t *, struct res **,
void (*)(struct res *, size_t, void *));
struct expr *exprcomp(int, char *[], size_t *);
void exprfree(struct expr *);
void resfree(struct res *, size_t);
struct expr *termcomp(int, char *[], size_t *);
__END_DECLS
#endif /*!APROPOS_H*/

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: arch.in,v 1.12 2012/01/28 14:02:17 joerg Exp $ */
/* Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -38,9 +38,9 @@ LINE("arm", "ARM")
LINE("arm26", "ARM26")
LINE("arm32", "ARM32")
LINE("armish", "ARMISH")
LINE("armv7", "ARMv7")
LINE("aviion", "AViiON")
LINE("atari", "ATARI")
LINE("beagle", "Beagle")
LINE("bebox", "BeBox")
LINE("cats", "cats")
LINE("cesfic", "CESFIC")
@ -81,6 +81,7 @@ LINE("netwinder", "NetWinder")
LINE("news68k", "NeWS68k")
LINE("newsmips", "NeWSMIPS")
LINE("next68k", "NeXT68k")
LINE("octeon", "OCTEON")
LINE("ofppc", "OFPPC")
LINE("palm", "Palm")
LINE("pc532", "PC532")

View File

@ -1,111 +0,0 @@
.\" $Vendor-Id: catman.8,v 1.5 2011/12/25 19:35:44 kristaps Exp $
.\"
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd December 25, 2011
.Dt CATMAN 8
.Os
.Sh NAME
.Nm catman
.Nd update a man.cgi manpage cache
.Sh SYNOPSIS
.Nm catman
.Op Fl fv
.Op Fl C Ar file
.Op Fl M Ar manpath
.Op Fl m Ar manpath
.Op Fl o Ar path
.Sh DESCRIPTION
The
.Nm
utility updates cached manpages for a jailed
.Xr man.cgi 7 .
.Pp
By default,
.Nm
searches for
.Xr mandocdb 8
databases in the default paths stipulated by
.Xr man 1
and updates the cache in
.Pa /var/www/cache/man.cgi .
.Pp
Its arguments are as follows:
.Bl -tag -width Ds
.It Fl f
Force an update to all files.
.It Fl v
Print each file being updated.
.It Fl C Ar file
Specify an alternative configuration
.Ar file
in
.Xr man.conf 5
format.
.It Fl M Ar manpath
Use the colon-separated path instead of the default list of paths
searched for
.Xr mandocdb 8
databases.
Invalid paths, or paths without manual databases, are ignored.
.It Fl m Ar manpath
Prepend the colon-separated paths to the list of paths searched
for
.Xr mandocdb 8
databases.
Invalid paths, or paths without manual databases, are ignored.
.It Fl o Ar path
Update into the directory tree under
.Ar path .
.El
.Pp
Cache updates occur when a
.Xr mandocdb 8
database is older than the cached copy unless
.Fl f
is specified, in which case files are always considered out of date.
Cached manual pages are only updated if older than the master copy.
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev MANPATH
Colon-separated paths modifying the default list of paths searched for
manual databases.
Invalid paths, or paths without manual databases, are ignored.
Overridden by
.Fl M .
If
.Ev MANPATH
begins with a
.Sq \&: ,
it is appended to the default list;
else if it ends with
.Sq \&: ,
it is prepended to the default list; else if it contains
.Sq \&:: ,
the default list is inserted between the colons.
If none of these conditions are met, it overrides the default list.
.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man.cgi 7 ,
.Xr mandocdb 8
.Sh AUTHORS
The
.Nm
utility was written by
.An Kristaps Dzonsons ,
.Mt kristaps@bsd.lv .

View File

@ -1,511 +0,0 @@
/* $Vendor-Id: catman.c,v 1.10 2012/01/03 15:17:20 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef __linux__
# include <db_185.h>
#else
# include <db.h>
#endif
#include "manpath.h"
#include "mandocdb.h"
#define xstrlcpy(_dst, _src, _sz) \
do if (strlcpy((_dst), (_src), (_sz)) >= (_sz)) { \
fprintf(stderr, "%s: Path too long", (_dst)); \
exit(EXIT_FAILURE); \
} while (/* CONSTCOND */0)
#define xstrlcat(_dst, _src, _sz) \
do if (strlcat((_dst), (_src), (_sz)) >= (_sz)) { \
fprintf(stderr, "%s: Path too long", (_dst)); \
exit(EXIT_FAILURE); \
} while (/* CONSTCOND */0)
static int indexhtml(char *, size_t, char *, size_t);
static int manup(const struct manpaths *, char *);
static int mkpath(char *, mode_t, mode_t);
static int treecpy(char *, char *);
static int update(char *, char *);
static void usage(void);
static const char *progname;
static int verbose;
static int force;
int
main(int argc, char *argv[])
{
int ch;
char *aux, *base, *conf_file;
struct manpaths dirs;
char buf[MAXPATHLEN];
extern char *optarg;
extern int optind;
progname = strrchr(argv[0], '/');
if (progname == NULL)
progname = argv[0];
else
++progname;
aux = base = conf_file = NULL;
xstrlcpy(buf, "/var/www/cache/man.cgi", MAXPATHLEN);
while (-1 != (ch = getopt(argc, argv, "C:fm:M:o:v")))
switch (ch) {
case ('C'):
conf_file = optarg;
break;
case ('f'):
force = 1;
break;
case ('m'):
aux = optarg;
break;
case ('M'):
base = optarg;
break;
case ('o'):
xstrlcpy(buf, optarg, MAXPATHLEN);
break;
case ('v'):
verbose++;
break;
default:
usage();
return(EXIT_FAILURE);
}
argc -= optind;
argv += optind;
if (argc > 0) {
usage();
return(EXIT_FAILURE);
}
memset(&dirs, 0, sizeof(struct manpaths));
manpath_parse(&dirs, conf_file, base, aux);
ch = manup(&dirs, buf);
manpath_free(&dirs);
return(ch ? EXIT_SUCCESS : EXIT_FAILURE);
}
static void
usage(void)
{
fprintf(stderr, "usage: %s "
"[-fv] "
"[-C file] "
"[-o path] "
"[-m manpath] "
"[-M manpath]\n",
progname);
}
/*
* If "src" file doesn't exist (errors out), return -1. Otherwise,
* return 1 if "src" is newer (which also happens "dst" doesn't exist)
* and 0 otherwise.
*/
static int
isnewer(const char *dst, const char *src)
{
struct stat s1, s2;
if (-1 == stat(src, &s1))
return(-1);
if (force)
return(1);
return(-1 == stat(dst, &s2) ? 1 : s1.st_mtime > s2.st_mtime);
}
/*
* Copy the contents of one file into another.
* Returns 0 on failure, 1 on success.
*/
static int
filecpy(const char *dst, const char *src)
{
char buf[BUFSIZ];
int sfd, dfd, rc;
ssize_t rsz, wsz;
sfd = dfd = -1;
rc = 0;
if (-1 == (dfd = open(dst, O_CREAT|O_TRUNC|O_WRONLY, 0644))) {
perror(dst);
goto out;
} else if (-1 == (sfd = open(src, O_RDONLY, 0))) {
perror(src);
goto out;
}
while ((rsz = read(sfd, buf, BUFSIZ)) > 0)
if (-1 == (wsz = write(dfd, buf, (size_t)rsz))) {
perror(dst);
goto out;
} else if (wsz < rsz) {
fprintf(stderr, "%s: Short write\n", dst);
goto out;
}
if (rsz < 0)
perror(src);
else
rc = 1;
out:
if (-1 != sfd)
close(sfd);
if (-1 != dfd)
close(dfd);
return(rc);
}
/*
* Pass over the recno database and re-create HTML pages if they're
* found to be out of date.
* Returns -1 on fatal error, 1 on success.
*/
static int
indexhtml(char *src, size_t ssz, char *dst, size_t dsz)
{
DB *idx;
DBT key, val;
int c, rc;
unsigned int fl;
const char *f;
char *d;
char fname[MAXPATHLEN];
pid_t pid;
pid = -1;
xstrlcpy(fname, dst, MAXPATHLEN);
xstrlcat(fname, "/", MAXPATHLEN);
xstrlcat(fname, MANDOC_IDX, MAXPATHLEN);
idx = dbopen(fname, O_RDONLY, 0, DB_RECNO, NULL);
if (NULL == idx) {
perror(fname);
return(-1);
}
fl = R_FIRST;
while (0 == (c = (*idx->seq)(idx, &key, &val, fl))) {
fl = R_NEXT;
/*
* If the record is zero-length, then it's unassigned.
* Skip past these.
*/
if (0 == val.size)
continue;
f = (const char *)val.data + 1;
if (NULL == memchr(f, '\0', val.size - 1))
break;
src[(int)ssz] = dst[(int)dsz] = '\0';
xstrlcat(dst, "/", MAXPATHLEN);
xstrlcat(dst, f, MAXPATHLEN);
xstrlcat(src, "/", MAXPATHLEN);
xstrlcat(src, f, MAXPATHLEN);
if (-1 == (rc = isnewer(dst, src))) {
fprintf(stderr, "%s: File missing\n", f);
break;
} else if (0 == rc)
continue;
d = strrchr(dst, '/');
assert(NULL != d);
*d = '\0';
if (-1 == mkpath(dst, 0755, 0755)) {
perror(dst);
break;
}
*d = '/';
if ( ! filecpy(dst, src))
break;
if (verbose)
printf("%s\n", dst);
}
(*idx->close)(idx);
if (c < 0)
perror(fname);
else if (0 == c)
fprintf(stderr, "%s: Corrupt index\n", fname);
return(1 == c ? 1 : -1);
}
/*
* Copy both recno and btree databases into the destination.
* Call in to begin recreating HTML files.
* Return -1 on fatal error and 1 if the update went well.
*/
static int
update(char *dst, char *src)
{
size_t dsz, ssz;
dsz = strlen(dst);
ssz = strlen(src);
xstrlcat(src, "/", MAXPATHLEN);
xstrlcat(dst, "/", MAXPATHLEN);
xstrlcat(src, MANDOC_DB, MAXPATHLEN);
xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
if ( ! filecpy(dst, src))
return(-1);
if (verbose)
printf("%s\n", dst);
dst[(int)dsz] = src[(int)ssz] = '\0';
xstrlcat(src, "/", MAXPATHLEN);
xstrlcat(dst, "/", MAXPATHLEN);
xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
if ( ! filecpy(dst, src))
return(-1);
if (verbose)
printf("%s\n", dst);
dst[(int)dsz] = src[(int)ssz] = '\0';
return(indexhtml(src, ssz, dst, dsz));
}
/*
* See if btree or recno databases in the destination are out of date
* with respect to a single manpath component.
* Return -1 on fatal error, 0 if the source is no longer valid (and
* shouldn't be listed), and 1 if the update went well.
*/
static int
treecpy(char *dst, char *src)
{
size_t dsz, ssz;
int rc;
dsz = strlen(dst);
ssz = strlen(src);
xstrlcat(src, "/", MAXPATHLEN);
xstrlcat(dst, "/", MAXPATHLEN);
xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
if (-1 == (rc = isnewer(dst, src)))
return(0);
dst[(int)dsz] = src[(int)ssz] = '\0';
if (1 == rc)
return(update(dst, src));
xstrlcat(src, "/", MAXPATHLEN);
xstrlcat(dst, "/", MAXPATHLEN);
xstrlcat(src, MANDOC_DB, MAXPATHLEN);
xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
if (-1 == (rc = isnewer(dst, src)))
return(0);
else if (rc == 0)
return(1);
dst[(int)dsz] = src[(int)ssz] = '\0';
return(update(dst, src));
}
/*
* Update the destination's file-tree with respect to changes in the
* source manpath components.
* "Change" is defined by an updated index or btree database.
* Returns 1 on success, 0 on failure.
*/
static int
manup(const struct manpaths *dirs, char *base)
{
char dst[MAXPATHLEN],
src[MAXPATHLEN];
const char *path;
int i, c;
size_t sz;
FILE *f;
/* Create the path and file for the catman.conf file. */
sz = strlen(base);
xstrlcpy(dst, base, MAXPATHLEN);
xstrlcat(dst, "/etc", MAXPATHLEN);
if (-1 == mkpath(dst, 0755, 0755)) {
perror(dst);
return(0);
}
xstrlcat(dst, "/catman.conf", MAXPATHLEN);
if (NULL == (f = fopen(dst, "w"))) {
perror(dst);
return(0);
} else if (verbose)
printf("%s\n", dst);
for (i = 0; i < dirs->sz; i++) {
path = dirs->paths[i];
dst[(int)sz] = '\0';
xstrlcat(dst, path, MAXPATHLEN);
if (-1 == mkpath(dst, 0755, 0755)) {
perror(dst);
break;
}
xstrlcpy(src, path, MAXPATHLEN);
if (-1 == (c = treecpy(dst, src)))
break;
else if (0 == c)
continue;
/*
* We want to use a relative path here because manpath.h
* will realpath() when invoked with man.cgi, and we'll
* make sure to chdir() into the cache directory before.
*
* This allows the cache directory to be in an arbitrary
* place, working in both chroot() and non-chroot()
* "safe" modes.
*/
assert('/' == path[0]);
fprintf(f, "_whatdb %s/whatis.db\n", path + 1);
}
fclose(f);
return(i == dirs->sz);
}
/*
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static int
mkpath(char *path, mode_t mode, mode_t dir_mode)
{
struct stat sb;
char *slash;
int done, exists;
slash = path;
for (;;) {
/* LINTED */
slash += strspn(slash, "/");
/* LINTED */
slash += strcspn(slash, "/");
done = (*slash == '\0');
*slash = '\0';
/* skip existing path components */
exists = !stat(path, &sb);
if (!done && exists && S_ISDIR(sb.st_mode)) {
*slash = '/';
continue;
}
if (mkdir(path, done ? mode : dir_mode) == 0) {
if (mode > 0777 && chmod(path, mode) < 0)
return (-1);
} else {
if (!exists) {
/* Not there */
return (-1);
}
if (!S_ISDIR(sb.st_mode)) {
/* Is there, but isn't a directory */
errno = ENOTDIR;
return (-1);
}
}
if (done)
break;
*slash = '/';
}
return (0);
}

View File

@ -8,7 +8,7 @@ int dummy;
#else
/* $NetBSD: compat_fgetln.c,v 1.2 2012/01/30 17:03:01 joerg Exp $ */
/* NetBSD: fgetln.c,v 1.3 2006/09/25 07:18:17 lukem Exp */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: lib.in,v 1.13 2012/01/28 23:46:28 joerg Exp $ */
/* Id: lib.in,v 1.17 2013/10/13 15:24:03 schwarze Exp */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -23,10 +23,12 @@
* Be sure to escape strings.
*/
LINE("libarchive", "Reading and Writing Streaming Archives Library (libarchive, \\-larchive)")
LINE("libalias", "Packet Aliasing Library (libalias, \\-lalias)")
LINE("libarchive", "Streaming Archive Library (libarchive, \\-larchive)")
LINE("libarm", "ARM Architecture Library (libarm, \\-larm)")
LINE("libarm32", "ARM32 Architecture Library (libarm32, \\-larm32)")
LINE("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)")
LINE("libbsdxml", "eXpat XML parser library (libbsdxml, \\-lbsdxml)")
LINE("libbsm", "Basic Security Module User Library (libbsm, \\-lbsm)")
LINE("libc", "Standard C Library (libc, \\-lc)")
LINE("libc_r", "Reentrant C\\~Library (libc_r, \\-lc_r)")
@ -37,18 +39,24 @@ LINE("libcipher", "FreeSec Crypt Library (libcipher, \\-lcipher)")
LINE("libcompat", "Compatibility Library (libcompat, \\-lcompat)")
LINE("libcrypt", "Crypt Library (libcrypt, \\-lcrypt)")
LINE("libcurses", "Curses Library (libcurses, \\-lcurses)")
LINE("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)")
LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
LINE("libdevstat", "Device Statistics Library (libdevstat, \\-ldevstat)")
LINE("libdisk", "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
LINE("libdm", "Device Mapper Library (libdm, \\-ldm)")
LINE("libdwarf", "DWARF Access Library (libdwarf, \\-ldwarf)")
LINE("libedit", "Command Line Editor Library (libedit, \\-ledit)")
LINE("libefi", "EFI Runtime Services Library (libefi, \\-lefi)")
LINE("libelf", "ELF Access Library (libelf, \\-lelf)")
LINE("libevent", "Event Notification Library (libevent, \\-levent)")
LINE("libexecinfo", "Backtrace Information Library (libexecinfo, \\-lexecinfo)")
LINE("libfetch", "File Transfer Library for URLs (libfetch, \\-lfetch)")
LINE("libfetch", "File Transfer Library (libfetch, \\-lfetch)")
LINE("libfsid", "Filesystem Identification Library (libfsid, \\-lfsid)")
LINE("libftpio", "FTP Connection Management Library (libftpio, \\-lftpio)")
LINE("libform", "Curses Form Library (libform, \\-lform)")
LINE("libgeom", "Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)")
LINE("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)")
LINE("libhammer", "HAMMER Filesystem Userland Library (libhammer, \\-lhammer)")
LINE("libi386", "i386 Architecture Library (libi386, \\-li386)")
LINE("libintl", "Internationalized Message Handling Library (libintl, \\-lintl)")
LINE("libipsec", "IPsec Policy Control Library (libipsec, \\-lipsec)")
@ -56,6 +64,7 @@ LINE("libipx", "IPX Address Conversion Support Library (libipx, \\-lipx)")
LINE("libiscsi", "iSCSI protocol library (libiscsi, \\-liscsi)")
LINE("libisns", "Internet Storage Name Service Library (libisns, \\-lisns)")
LINE("libjail", "Jail Library (libjail, \\-ljail)")
LINE("libkcore", "Kernel Memory Core Access Library (libkcore, \\-lkcore)")
LINE("libkiconv", "Kernel-side iconv Library (libkiconv, \\-lkiconv)")
LINE("libkse", "N:M Threading Library (libkse, \\-lkse)")
LINE("libkvm", "Kernel Data Access Library (libkvm, \\-lkvm)")
@ -76,12 +85,15 @@ LINE("libpam", "Pluggable Authentication Module Library (libpam, \\-lpam)")
LINE("libpcap", "Capture Library (libpcap, \\-lpcap)")
LINE("libpci", "PCI Bus Access Library (libpci, \\-lpci)")
LINE("libpmc", "Performance Counters Library (libpmc, \\-lpmc)")
LINE("libppath", "Property-List Paths Library (libppath, \\-lppath)")
LINE("libposix", "POSIX Compatibility Library (libposix, \\-lposix)")
LINE("libposix1e", "POSIX.1e Security API Library (libposix1e, \\-lposix1e)")
LINE("libppath", "Property-List Paths Library (libppath, \\-lppath)")
LINE("libprop", "Property Container Object Library (libprop, \\-lprop)")
LINE("libpthread", "POSIX Threads Library (libpthread, \\-lpthread)")
LINE("libpuffs", "puffs Convenience Library (libpuffs, \\-lpuffs)")
LINE("libquota", "Disk Quota Access and Control Library (libquota, \\-lquota)")
LINE("libradius", "RADIUS Client Library (libradius, \\-lradius)")
LINE("librefuse", "File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
LINE("libresolv", "DNS Resolver Library (libresolv, \\-lresolv)")
LINE("librpcsec_gss", "RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
@ -91,7 +103,10 @@ LINE("librumpclient", "Clientside Stubs for rump Kernel Remote Protocols (librum
LINE("libsaslc", "Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
LINE("libsdp", "Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
LINE("libssp", "Buffer Overflow Protection Library (libssp, \\-lssp)")
LINE("libstand", "Standalone Applications Library (libstand, \\-lstand)")
LINE("libSystem", "System Library (libSystem, \\-lSystem)")
LINE("libtacplus", "TACACS+ Client Library (libtacplus, \\-ltacplus)")
LINE("libtcplay", "TrueCrypt-compatible API library (libtcplay, \\-ltcplay)")
LINE("libtermcap", "Termcap Access Library (libtermcap, \\-ltermcap)")
LINE("libterminfo", "Terminal Information Library (libterminfo, \\-lterminfo)")
LINE("libthr", "1:1 Threading Library (libthr, \\-lthr)")

View File

@ -1,6 +1,7 @@
/* $Vendor-Id: libmandoc.h,v 1.29 2011/12/02 01:37:14 schwarze Exp $ */
/* Id: libmandoc.h,v 1.37 2014/01/05 19:10:56 joerg Exp */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 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
@ -29,11 +30,6 @@ enum rofferr {
ROFF_ERR /* badness: puke and stop */
};
enum regs {
REG_nS = 0, /* nS register */
REG__MAX
};
__BEGIN_DECLS
struct roff;
@ -42,17 +38,19 @@ struct man;
void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
#if __GNUC__ - 0 >= 4
__attribute__((__format__ (__printf__, 5, 6)))
#endif
void mandoc_vmsg(enum mandocerr, struct mparse *,
int, int, const char *, ...);
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct mparse *, char *, int, int);
int mandoc_eos(const char *, size_t, int);
int mandoc_getcontrol(const char *, int *);
int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
void mdoc_free(struct mdoc *);
struct mdoc *mdoc_alloc(struct roff *, struct mparse *);
struct mdoc *mdoc_alloc(struct roff *, struct mparse *, char *);
void mdoc_reset(struct mdoc *);
int mdoc_parseln(struct mdoc *, int, char *, int);
int mdoc_endparse(struct mdoc *);
@ -68,17 +66,16 @@ int man_addspan(struct man *, const struct tbl_span *);
int man_addeqn(struct man *, const struct eqn *);
void roff_free(struct roff *);
struct roff *roff_alloc(struct mparse *);
struct roff *roff_alloc(enum mparset, struct mparse *);
void roff_reset(struct roff *);
enum rofferr roff_parseln(struct roff *, int,
char **, size_t *, int, int *);
void roff_endparse(struct roff *);
void roff_expand_nr(struct roff *, const char *, int *, size_t,
char **, int *, size_t *);
int roff_regisset(const struct roff *, enum regs);
unsigned int roff_regget(const struct roff *, enum regs);
void roff_regunset(struct roff *, enum regs);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(const struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
int roff_getcontrol(const struct roff *,
const char *, int *);
#if 0
char roff_eqndelim(const struct roff *);
void roff_openeqn(struct roff *, const char *,

View File

@ -1,7 +1,7 @@
/* $Vendor-Id: man_term.c,v 1.127 2012/01/03 15:16:24 kristaps Exp $ */
/* Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011, 2012, 2013 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
@ -35,8 +35,6 @@
#define MAXMARGINS 64 /* maximum number of indented scopes */
/* FIXME: have PD set the default vspace width. */
struct mtermp {
int fl;
#define MANT_LITERAL (1 << 0)
@ -44,12 +42,13 @@ struct mtermp {
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
size_t offset; /* default offset to visible page */
int pardist; /* vert. space before par., unit: [v] */
};
#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
const struct man_node *n, \
const struct man_meta *m
const struct man_meta *meta
struct termact {
int (*pre)(DECL_ARGS);
@ -66,18 +65,20 @@ static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *, const void *);
static void print_man_foot(struct termp *, const void *);
static void print_bvspace(struct termp *,
const struct man_node *);
const struct man_node *, int);
static int pre_B(DECL_ARGS);
static int pre_HP(DECL_ARGS);
static int pre_I(DECL_ARGS);
static int pre_IP(DECL_ARGS);
static int pre_OP(DECL_ARGS);
static int pre_PD(DECL_ARGS);
static int pre_PP(DECL_ARGS);
static int pre_RS(DECL_ARGS);
static int pre_SH(DECL_ARGS);
static int pre_SS(DECL_ARGS);
static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ft(DECL_ARGS);
static int pre_ign(DECL_ARGS);
@ -91,6 +92,7 @@ static void post_RS(DECL_ARGS);
static void post_SH(DECL_ARGS);
static void post_SS(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
static const struct termact termacts[MAN_MAX] = {
{ pre_sp, NULL, MAN_NOTEXT }, /* br */
@ -122,11 +124,15 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_RS, post_RS, 0 }, /* RS */
{ pre_ign, NULL, 0 }, /* DT */
{ pre_ign, NULL, 0 }, /* UC */
{ pre_ign, NULL, 0 }, /* PD */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
{ pre_ft, NULL, MAN_NOTEXT }, /* ft */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
};
@ -136,7 +142,7 @@ terminal_man(void *arg, const struct man *man)
{
struct termp *p;
const struct man_node *n;
const struct man_meta *m;
const struct man_meta *meta;
struct mtermp mt;
p = (struct termp *)arg;
@ -152,18 +158,19 @@ terminal_man(void *arg, const struct man *man)
p->symtab = mchars_alloc();
n = man_node(man);
m = man_meta(man);
meta = man_meta(man);
term_begin(p, print_man_head, print_man_foot, m);
term_begin(p, print_man_head, print_man_foot, meta);
p->flags |= TERMP_NOSPACE;
memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
if (n->child)
print_man_nodelist(p, &mt, n->child, m);
print_man_nodelist(p, &mt, n->child, meta);
term_end(p);
}
@ -201,8 +208,9 @@ a2width(const struct termp *p, const char *cp)
* first, print it.
*/
static void
print_bvspace(struct termp *p, const struct man_node *n)
print_bvspace(struct termp *p, const struct man_node *n, int pardist)
{
int i;
term_newln(p);
@ -214,7 +222,8 @@ print_bvspace(struct termp *p, const struct man_node *n)
if (NULL == n->prev)
return;
term_vspace(p);
for (i = 0; i < pardist; i++)
term_vspace(p);
}
/* ARGSUSED */
@ -243,7 +252,7 @@ pre_literal(DECL_ARGS)
term_newln(p);
if (MAN_nf == n->tok)
if (MAN_nf == n->tok || MAN_EX == n->tok)
mt->fl |= MANT_LITERAL;
else
mt->fl &= ~MANT_LITERAL;
@ -256,13 +265,29 @@ pre_literal(DECL_ARGS)
if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE);
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
}
return(0);
}
/* ARGSUSED */
static int
pre_PD(DECL_ARGS)
{
n = n->child;
if (0 == n) {
mt->pardist = 1;
return(0);
}
assert(MAN_TEXT == n->type);
mt->pardist = atoi(n->string);
return(0);
}
/* ARGSUSED */
static int
pre_alternate(DECL_ARGS)
@ -307,7 +332,7 @@ pre_alternate(DECL_ARGS)
term_fontrepl(p, font[i]);
if (savelit && NULL == nn->next)
mt->fl |= MANT_LITERAL;
print_man_node(p, mt, nn, m);
print_man_node(p, mt, nn, meta);
if (nn->next)
p->flags |= TERMP_NOSPACE;
}
@ -438,28 +463,54 @@ pre_in(DECL_ARGS)
static int
pre_sp(DECL_ARGS)
{
char *s;
size_t i, len;
int neg;
if ((NULL == n->prev && n->parent)) {
if (MAN_SS == n->parent->tok)
return(0);
if (MAN_SH == n->parent->tok)
switch (n->parent->tok) {
case (MAN_SH):
/* FALLTHROUGH */
case (MAN_SS):
/* FALLTHROUGH */
case (MAN_PP):
/* FALLTHROUGH */
case (MAN_LP):
/* FALLTHROUGH */
case (MAN_P):
/* FALLTHROUGH */
return(0);
default:
break;
}
}
neg = 0;
switch (n->tok) {
case (MAN_br):
len = 0;
break;
default:
len = n->child ? a2height(p, n->child->string) : 1;
if (NULL == n->child) {
len = 1;
break;
}
s = n->child->string;
if ('-' == *s) {
neg = 1;
s++;
}
len = a2height(p, s);
break;
}
if (0 == len)
term_newln(p);
for (i = 0; i < len; i++)
term_vspace(p);
else if (neg)
p->skipvsp += len;
else
for (i = 0; i < len; i++)
term_vspace(p);
return(0);
}
@ -475,16 +526,19 @@ pre_HP(DECL_ARGS)
switch (n->type) {
case (MAN_BLOCK):
print_bvspace(p, n);
print_bvspace(p, n, mt->pardist);
return(1);
case (MAN_BODY):
p->flags |= TERMP_NOBREAK;
p->flags |= TERMP_TWOSPACE;
break;
default:
return(0);
}
if ( ! (MANT_LITERAL & mt->fl)) {
p->flags |= TERMP_NOBREAK;
p->trailspace = 2;
}
len = mt->lmargin[mt->lmargincur];
ival = -1;
@ -514,13 +568,10 @@ post_HP(DECL_ARGS)
{
switch (n->type) {
case (MAN_BLOCK):
term_flushln(p);
break;
case (MAN_BODY):
term_flushln(p);
term_newln(p);
p->flags &= ~TERMP_NOBREAK;
p->flags &= ~TERMP_TWOSPACE;
p->trailspace = 0;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
break;
@ -538,7 +589,7 @@ pre_PP(DECL_ARGS)
switch (n->type) {
case (MAN_BLOCK):
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n);
print_bvspace(p, n, mt->pardist);
break;
default:
p->offset = mt->offset;
@ -563,9 +614,10 @@ pre_IP(DECL_ARGS)
break;
case (MAN_HEAD):
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case (MAN_BLOCK):
print_bvspace(p, n);
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
@ -598,7 +650,7 @@ pre_IP(DECL_ARGS)
mt->fl &= ~MANT_LITERAL;
if (n->child)
print_man_node(p, mt, n->child, m);
print_man_node(p, mt, n->child, meta);
if (savelit)
mt->fl |= MANT_LITERAL;
@ -625,10 +677,12 @@ post_IP(DECL_ARGS)
case (MAN_HEAD):
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->rmargin = p->maxrmargin;
break;
case (MAN_BODY):
term_newln(p);
p->offset = mt->offset;
break;
default:
break;
@ -647,12 +701,13 @@ pre_TP(DECL_ARGS)
switch (n->type) {
case (MAN_HEAD):
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case (MAN_BODY):
p->flags |= TERMP_NOSPACE;
break;
case (MAN_BLOCK):
print_bvspace(p, n);
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
@ -683,7 +738,7 @@ pre_TP(DECL_ARGS)
/* Don't print same-line elements. */
for (nn = n->child; nn; nn = nn->next)
if (nn->line > n->line)
print_man_node(p, mt, nn, m);
print_man_node(p, mt, nn, meta);
if (savelit)
mt->fl |= MANT_LITERAL;
@ -694,6 +749,8 @@ pre_TP(DECL_ARGS)
case (MAN_BODY):
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
break;
default:
break;
@ -711,12 +768,10 @@ post_TP(DECL_ARGS)
switch (n->type) {
case (MAN_HEAD):
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->flags &= ~TERMP_TWOSPACE;
p->rmargin = p->maxrmargin;
break;
case (MAN_BODY):
term_newln(p);
p->offset = mt->offset;
break;
default:
break;
@ -728,6 +783,7 @@ post_TP(DECL_ARGS)
static int
pre_SS(DECL_ARGS)
{
int i;
switch (n->type) {
case (MAN_BLOCK):
@ -740,11 +796,12 @@ pre_SS(DECL_ARGS)
break;
if (NULL == n->prev)
break;
term_vspace(p);
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case (MAN_HEAD):
term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, p->defindent/2);
p->offset = term_len(p, 3);
break;
case (MAN_BODY):
p->offset = mt->offset;
@ -779,6 +836,7 @@ post_SS(DECL_ARGS)
static int
pre_SH(DECL_ARGS)
{
int i;
switch (n->type) {
case (MAN_BLOCK):
@ -792,7 +850,8 @@ pre_SH(DECL_ARGS)
/* If the first macro, no vspae. */
if (NULL == n->prev)
break;
term_vspace(p);
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case (MAN_HEAD):
term_fontrepl(p, TERMFONT_BOLD);
@ -890,6 +949,32 @@ post_RS(DECL_ARGS)
mt->lmargincur = mt->lmarginsz;
}
/* ARGSUSED */
static int
pre_UR(DECL_ARGS)
{
return (MAN_HEAD != n->type);
}
/* ARGSUSED */
static void
post_UR(DECL_ARGS)
{
if (MAN_BLOCK != n->type)
return;
term_word(p, "<");
p->flags |= TERMP_NOSPACE;
if (NULL != n->child->child)
print_man_node(p, mt, n->child->child, meta);
p->flags |= TERMP_NOSPACE;
term_word(p, ">");
}
static void
print_man_node(DECL_ARGS)
{
@ -910,29 +995,8 @@ print_man_node(DECL_ARGS)
term_newln(p);
term_word(p, n->string);
goto out;
/*
* If we're in a literal context, make sure that words
* togehter on the same line stay together. This is a
* POST-printing call, so we check the NEXT word. Since
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
(NULL == n->next ||
n->next->line > n->line)) {
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
term_flushln(p);
p->rmargin = rm;
p->maxrmargin = rmax;
}
if (MAN_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
return;
case (MAN_EQN):
term_eqn(p, n->eqn);
return;
@ -954,16 +1018,41 @@ print_man_node(DECL_ARGS)
c = 1;
if (termacts[n->tok].pre)
c = (*termacts[n->tok].pre)(p, mt, n, m);
c = (*termacts[n->tok].pre)(p, mt, n, meta);
if (c && n->child)
print_man_nodelist(p, mt, n->child, m);
print_man_nodelist(p, mt, n->child, meta);
if (termacts[n->tok].post)
(*termacts[n->tok].post)(p, mt, n, m);
(*termacts[n->tok].post)(p, mt, n, meta);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
term_fontrepl(p, TERMFONT_NONE);
out:
/*
* If we're in a literal context, make sure that words
* together on the same line stay together. This is a
* POST-printing call, so we check the NEXT word. Since
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
(NULL == n->next || n->next->line > n->line)) {
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
if (NULL != n->string && '\0' != *n->string)
term_flushln(p);
else
term_newln(p);
if (rm < rmax && n->parent->tok == MAN_HP) {
p->offset = rm;
p->rmargin = rmax;
} else
p->rmargin = rm;
p->maxrmargin = rmax;
}
if (MAN_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
}
@ -973,10 +1062,10 @@ static void
print_man_nodelist(DECL_ARGS)
{
print_man_node(p, mt, n, m);
print_man_node(p, mt, n, meta);
if ( ! n->next)
return;
print_man_nodelist(p, mt, n->next, m);
print_man_nodelist(p, mt, n->next, meta);
}
@ -1016,6 +1105,7 @@ print_man_foot(struct termp *p, const void *arg)
/* Bottom left corner: manual source. */
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->offset = 0;
p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
@ -1038,6 +1128,7 @@ print_man_foot(struct termp *p, const void *arg)
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
p->trailspace = 0;
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
@ -1051,24 +1142,25 @@ print_man_head(struct termp *p, const void *arg)
{
char buf[BUFSIZ], title[BUFSIZ];
size_t buflen, titlen;
const struct man_meta *m;
const struct man_meta *meta;
m = (const struct man_meta *)arg;
assert(m->title);
assert(m->msec);
meta = (const struct man_meta *)arg;
assert(meta->title);
assert(meta->msec);
if (m->vol)
strlcpy(buf, m->vol, BUFSIZ);
if (meta->vol)
strlcpy(buf, meta->vol, BUFSIZ);
else
buf[0] = '\0';
buflen = term_strlen(p, buf);
/* Top left corner: manual title and section. */
snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
(p->maxrmargin -
@ -1091,6 +1183,7 @@ print_man_head(struct termp *p, const void *arg)
/* Top right corner: title and section, again. */
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;

View File

@ -1,6 +1,7 @@
/* $Vendor-Id: mandoc.h,v 1.99 2012/02/16 20:51:31 joerg Exp $ */
/* Id: mandoc.h,v 1.113 2014/01/02 16:29:55 schwarze Exp */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2013, 2014 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
@ -50,6 +51,7 @@ enum mandocerr {
MANDOCERR_NOTITLE, /* no title in document */
MANDOCERR_UPPERCASE, /* document title should be all caps */
MANDOCERR_BADMSEC, /* unknown manual section */
MANDOCERR_BADVOLARCH, /* unknown manual volume or arch */
MANDOCERR_NODATE, /* date missing, using today's date */
MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */
MANDOCERR_PROLOGOOO, /* prologue macros out of order */
@ -61,14 +63,14 @@ enum mandocerr {
MANDOCERR_SO, /* .so is fragile, better use ln(1) */
MANDOCERR_NAMESECFIRST, /* NAME section must come first */
MANDOCERR_BADNAMESEC, /* bad NAME section contents */
MANDOCERR_NONAME, /* manual name not yet set */
MANDOCERR_SECOOO, /* sections out of conventional order */
MANDOCERR_SECREP, /* duplicate section name */
MANDOCERR_SECMSEC, /* section not in conventional manual section */
MANDOCERR_SECMSEC, /* section header suited to sections ... */
/* related to macros and nesting */
MANDOCERR_MACROOBS, /* skipping obsolete macro */
MANDOCERR_IGNPAR, /* skipping paragraph macro */
MANDOCERR_MOVEPAR, /* moving paragraph macro out of list */
MANDOCERR_IGNNS, /* skipping no-space macro */
MANDOCERR_SCOPENEST, /* blocks badly nested */
MANDOCERR_CHILD, /* child violates parent syntax */
@ -129,10 +131,12 @@ enum mandocerr {
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_BADCHAR, /* skipping bad character */
MANDOCERR_NAMESC, /* escaped character not allowed in a name */
MANDOCERR_NONAME, /* manual name not yet set */
MANDOCERR_NOTEXT, /* skipping text before the first section header */
MANDOCERR_MACRO, /* skipping unknown macro */
MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */
MANDOCERR_ARGCOUNT, /* argument count wrong */
MANDOCERR_STRAYTA, /* skipping column outside column list */
MANDOCERR_NOSCOPE, /* skipping end of block that is not open */
MANDOCERR_SCOPEBROKEN, /* missing end of block */
MANDOCERR_SCOPEEXIT, /* scope open on exit */
@ -141,12 +145,14 @@ enum mandocerr {
MANDOCERR_NOARGS, /* macro requires line argument(s) */
MANDOCERR_NOBODY, /* macro requires body argument(s) */
MANDOCERR_NOARGV, /* macro requires argument(s) */
MANDOCERR_NUMERIC, /* request requires a numeric argument */
MANDOCERR_LISTTYPE, /* missing list type */
MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
MANDOCERR_BODYLOST, /* body argument(s) will be lost */
MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
MANDOCERR_TOOLARGE, /* input too large */
MANDOCERR_NOTMANUAL, /* manual isn't really a manual */
MANDOCERR_COLUMNS, /* column syntax is inconsistent */
MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */
@ -157,10 +163,17 @@ enum mandocerr {
MANDOCERR_NODOCBODY, /* no document body */
MANDOCERR_NODOCPROLOG, /* no document prologue */
MANDOCERR_MEM, /* static buffer exhausted */
/* ===== system errors ===== */
MANDOCERR_SYSOPEN, /* cannot open file */
MANDOCERR_SYSSTAT, /* cannot stat file */
MANDOCERR_SYSREAD, /* cannot read file */
MANDOCERR_MAX
};
struct tbl {
struct tbl_opts {
char tab; /* cell-separator */
char decimal; /* decimal point */
int linesize;
@ -175,20 +188,14 @@ struct tbl {
int cols; /* number of columns */
};
enum tbl_headt {
TBL_HEAD_DATA, /* plug in data from tbl_dat */
TBL_HEAD_VERT, /* vertical spacer */
TBL_HEAD_DVERT /* double-vertical spacer */
};
/*
* The head of a table specifies all of its columns. When formatting a
* tbl_span, iterate over these and plug in data from the tbl_span when
* appropriate, using tbl_cell as a guide to placement.
*/
struct tbl_head {
enum tbl_headt pos;
int ident; /* 0 <= unique id < cols */
int vert; /* width of preceding vertical line */
struct tbl_head *next;
struct tbl_head *prev;
};
@ -203,8 +210,6 @@ enum tbl_cellt {
TBL_CELL_DOWN, /* ^ */
TBL_CELL_HORIZ, /* _, - */
TBL_CELL_DHORIZ, /* = */
TBL_CELL_VERT, /* | */
TBL_CELL_DVERT, /* || */
TBL_CELL_MAX
};
@ -213,6 +218,7 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next;
int vert; /* width of preceding vertical line */
enum tbl_cellt pos;
size_t spacing;
int flags;
@ -266,7 +272,7 @@ enum tbl_spant {
* A row of data in a table.
*/
struct tbl_span {
struct tbl *tbl;
struct tbl_opts *opts;
struct tbl_head *head;
struct tbl_row *layout; /* layout row */
struct tbl_dat *first;
@ -382,11 +388,13 @@ enum mandoc_esc {
ESCAPE_FONT, /* a generic font mode */
ESCAPE_FONTBOLD, /* bold font mode */
ESCAPE_FONTITALIC, /* italic font mode */
ESCAPE_FONTBI, /* bold italic font mode */
ESCAPE_FONTROMAN, /* roman font mode */
ESCAPE_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_NOSPACE /* suppress space if the last on a line */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_SKIPCHAR /* skip the next character */
};
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
@ -413,8 +421,8 @@ int mchars_spec2cp(const struct mchars *,
const char *, size_t);
const char *mchars_spec2str(const struct mchars *,
const char *, size_t, size_t *);
struct mparse *mparse_alloc(enum mparset,
enum mandoclevel, mandocmsg, void *);
struct mparse *mparse_alloc(enum mparset, enum mandoclevel,
mandocmsg, void *, char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);

View File

@ -1,62 +0,0 @@
/* $Vendor-Id: mandocdb.h,v 1.6 2012/03/23 02:52:33 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef MANDOCDB_H
#define MANDOCDB_H
#define MANDOC_DB "mandocdb.db"
#define MANDOC_IDX "mandocdb.index"
#define TYPE_An 0x0000000000000001ULL
#define TYPE_Ar 0x0000000000000002ULL
#define TYPE_At 0x0000000000000004ULL
#define TYPE_Bsx 0x0000000000000008ULL
#define TYPE_Bx 0x0000000000000010ULL
#define TYPE_Cd 0x0000000000000020ULL
#define TYPE_Cm 0x0000000000000040ULL
#define TYPE_Dv 0x0000000000000080ULL
#define TYPE_Dx 0x0000000000000100ULL
#define TYPE_Em 0x0000000000000200ULL
#define TYPE_Er 0x0000000000000400ULL
#define TYPE_Ev 0x0000000000000800ULL
#define TYPE_Fa 0x0000000000001000ULL
#define TYPE_Fl 0x0000000000002000ULL
#define TYPE_Fn 0x0000000000004000ULL
#define TYPE_Ft 0x0000000000008000ULL
#define TYPE_Fx 0x0000000000010000ULL
#define TYPE_Ic 0x0000000000020000ULL
#define TYPE_In 0x0000000000040000ULL
#define TYPE_Lb 0x0000000000080000ULL
#define TYPE_Li 0x0000000000100000ULL
#define TYPE_Lk 0x0000000000200000ULL
#define TYPE_Ms 0x0000000000400000ULL
#define TYPE_Mt 0x0000000000800000ULL
#define TYPE_Nd 0x0000000001000000ULL
#define TYPE_Nm 0x0000000002000000ULL
#define TYPE_Nx 0x0000000004000000ULL
#define TYPE_Ox 0x0000000008000000ULL
#define TYPE_Pa 0x0000000010000000ULL
#define TYPE_Rs 0x0000000020000000ULL
#define TYPE_Sh 0x0000000040000000ULL
#define TYPE_Ss 0x0000000080000000ULL
#define TYPE_St 0x0000000100000000ULL
#define TYPE_Sy 0x0000000200000000ULL
#define TYPE_Tn 0x0000000400000000ULL
#define TYPE_Va 0x0000000800000000ULL
#define TYPE_Vt 0x0000001000000000ULL
#define TYPE_Xr 0x0000002000000000ULL
#endif /*!MANDOCDB_H */

View File

@ -1,6 +1,7 @@
/* $Vendor-Id: mdoc_argv.c,v 1.82 2012/03/23 05:50:24 kristaps Exp $ */
/* Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012 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
@ -42,8 +43,7 @@ enum argsflag {
enum argvflag {
ARGV_NONE, /* no args to flag (e.g., -split) */
ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */
ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */
};
struct mdocarg {
@ -57,8 +57,6 @@ static enum margserr args(struct mdoc *, int, int *,
static int args_checkpunct(const char *, int);
static int argv_multi(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
static int argv_opt_single(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
static int argv_single(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
@ -69,7 +67,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = {
ARGV_NONE, /* MDOC_Unfilled */
ARGV_NONE, /* MDOC_Literal */
ARGV_SINGLE, /* MDOC_File */
ARGV_OPT_SINGLE, /* MDOC_Offset */
ARGV_SINGLE, /* MDOC_Offset */
ARGV_NONE, /* MDOC_Bullet */
ARGV_NONE, /* MDOC_Dash */
ARGV_NONE, /* MDOC_Hyphen */
@ -81,7 +79,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = {
ARGV_NONE, /* MDOC_Ohang */
ARGV_NONE, /* MDOC_Inset */
ARGV_MULTI, /* MDOC_Column */
ARGV_OPT_SINGLE, /* MDOC_Width */
ARGV_SINGLE, /* MDOC_Width */
ARGV_NONE, /* MDOC_Compact */
ARGV_NONE, /* MDOC_Std */
ARGV_NONE, /* MDOC_Filled */
@ -146,7 +144,7 @@ static const enum mdocargt args_Bl[] = {
};
static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* Ap */
{ ARGSFL_DELIM, NULL }, /* Ap */
{ ARGSFL_NONE, NULL }, /* Dd */
{ ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */
@ -163,7 +161,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Ad */
{ ARGSFL_DELIM, args_An }, /* An */
{ ARGSFL_DELIM, NULL }, /* Ar */
{ ARGSFL_NONE, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cm */
{ ARGSFL_DELIM, NULL }, /* Dv */
{ ARGSFL_DELIM, NULL }, /* Er */
@ -175,7 +173,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Fn */
{ ARGSFL_DELIM, NULL }, /* Ft */
{ ARGSFL_DELIM, NULL }, /* Ic */
{ ARGSFL_NONE, NULL }, /* In */
{ ARGSFL_DELIM, NULL }, /* In */
{ ARGSFL_DELIM, NULL }, /* Li */
{ ARGSFL_NONE, NULL }, /* Nd */
{ ARGSFL_DELIM, NULL }, /* Nm */
@ -243,7 +241,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Xc */
{ ARGSFL_NONE, NULL }, /* Xo */
{ ARGSFL_NONE, NULL }, /* Fo */
{ ARGSFL_NONE, NULL }, /* Fc */
{ ARGSFL_DELIM, NULL }, /* Fc */
{ ARGSFL_NONE, NULL }, /* Oo */
{ ARGSFL_DELIM, NULL }, /* Oc */
{ ARGSFL_NONE, args_Bk }, /* Bk */
@ -252,7 +250,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* Hf */
{ ARGSFL_NONE, NULL }, /* Fr */
{ ARGSFL_NONE, NULL }, /* Ud */
{ ARGSFL_NONE, NULL }, /* Lb */
{ ARGSFL_DELIM, NULL }, /* Lb */
{ ARGSFL_NONE, NULL }, /* Lp */
{ ARGSFL_DELIM, NULL }, /* Lk */
{ ARGSFL_DELIM, NULL }, /* Mt */
@ -262,7 +260,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* %C */
{ ARGSFL_NONE, NULL }, /* Es */
{ ARGSFL_NONE, NULL }, /* En */
{ ARGSFL_NONE, NULL }, /* Dx */
{ ARGSFL_DELIM, NULL }, /* Dx */
{ ARGSFL_NONE, NULL }, /* %Q */
{ ARGSFL_NONE, NULL }, /* br */
{ ARGSFL_NONE, NULL }, /* sp */
@ -277,7 +275,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
* one mandatory value, an optional single value, or no value.
*/
enum margverr
mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
struct mdoc_arg **v, int *pos, char *buf)
{
char *p, sv;
@ -344,15 +342,11 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
switch (argvflags[tmp.arg]) {
case (ARGV_SINGLE):
if ( ! argv_single(m, line, &tmp, pos, buf))
if ( ! argv_single(mdoc, line, &tmp, pos, buf))
return(ARGV_ERROR);
break;
case (ARGV_MULTI):
if ( ! argv_multi(m, line, &tmp, pos, buf))
return(ARGV_ERROR);
break;
case (ARGV_OPT_SINGLE):
if ( ! argv_opt_single(m, line, &tmp, pos, buf))
if ( ! argv_multi(mdoc, line, &tmp, pos, buf))
return(ARGV_ERROR);
break;
case (ARGV_NONE):
@ -413,14 +407,14 @@ argn_free(struct mdoc_arg *p, int iarg)
}
enum margserr
mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v)
{
return(args(m, line, pos, buf, ARGSFL_NONE, v));
return(args(mdoc, line, pos, buf, ARGSFL_NONE, v));
}
enum margserr
mdoc_args(struct mdoc *m, int line, int *pos,
mdoc_args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum mdoct tok, char **v)
{
enum argsflag fl;
@ -429,7 +423,7 @@ mdoc_args(struct mdoc *m, int line, int *pos,
fl = mdocargs[tok].flags;
if (MDOC_It != tok)
return(args(m, line, pos, buf, fl, v));
return(args(mdoc, line, pos, buf, fl, v));
/*
* We know that we're in an `It', so it's reasonable to expect
@ -438,18 +432,18 @@ mdoc_args(struct mdoc *m, int line, int *pos,
* safe fall-back into the default behaviour.
*/
for (n = m->last; n; n = n->parent)
for (n = mdoc->last; n; n = n->parent)
if (MDOC_Bl == n->tok)
if (LIST_column == n->norm->Bl.type) {
fl = ARGSFL_TABSEP;
break;
}
return(args(m, line, pos, buf, fl, v));
return(args(mdoc, line, pos, buf, fl, v));
}
static enum margserr
args(struct mdoc *m, int line, int *pos,
args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum argsflag fl, char **v)
{
char *p, *pp;
@ -457,17 +451,17 @@ args(struct mdoc *m, int line, int *pos,
enum margserr rc;
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & m->flags)
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_EOLN);
/*
* If we're not in a partial phrase and the flag for
* being a phrase literal is still set, the punctuation
* is unterminated.
*/
if (MDOC_PHRASELIT & m->flags)
mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
if (MDOC_PHRASELIT & mdoc->flags)
mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
m->flags &= ~MDOC_PHRASELIT;
mdoc->flags &= ~MDOC_PHRASELIT;
return(ARGS_EOLN);
}
@ -490,7 +484,7 @@ args(struct mdoc *m, int line, int *pos,
pp = NULL;
/* Scan ahead to unescaped `Ta'. */
if ( ! (MDOC_PHRASELIT & m->flags))
if ( ! (MDOC_PHRASELIT & mdoc->flags))
for (pp = *v; ; pp++) {
if (NULL == (pp = strstr(pp, "Ta")))
break;
@ -524,7 +518,7 @@ args(struct mdoc *m, int line, int *pos,
/* Whitespace check for eoln case... */
if ('\0' == *p && ' ' == *(p - 1))
mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
*pos += (int)(p - *v);
@ -542,22 +536,22 @@ args(struct mdoc *m, int line, int *pos,
/* Skip ahead. */ ;
return(rc);
}
}
/*
/*
* Process a quoted literal. A quote begins with a double-quote
* and ends with a double-quote NOT preceded by a double-quote.
* Null-terminate the literal in place.
* NUL-terminate the literal in place.
* Collapse pairs of quotes inside quoted literals.
* Whitespace is NOT involved in literal termination.
*/
if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
if ( ! (MDOC_PHRASELIT & m->flags))
if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) {
if ( ! (MDOC_PHRASELIT & mdoc->flags))
*v = &buf[++(*pos)];
if (MDOC_PPHRASE & m->flags)
m->flags |= MDOC_PHRASELIT;
if (MDOC_PPHRASE & mdoc->flags)
mdoc->flags |= MDOC_PHRASELIT;
pairs = 0;
for ( ; buf[*pos]; (*pos)++) {
@ -577,13 +571,13 @@ args(struct mdoc *m, int line, int *pos,
buf[*pos - pairs] = '\0';
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & m->flags)
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_QWORD);
mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
return(ARGS_QWORD);
}
m->flags &= ~MDOC_PHRASELIT;
mdoc->flags &= ~MDOC_PHRASELIT;
buf[(*pos)++] = '\0';
if ('\0' == buf[*pos])
@ -593,13 +587,13 @@ args(struct mdoc *m, int line, int *pos,
(*pos)++;
if ('\0' == buf[*pos])
mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
return(ARGS_QWORD);
}
p = &buf[*pos];
*v = mandoc_getarg(m->parse, &p, line, pos);
*v = mandoc_getarg(mdoc->parse, &p, line, pos);
return(ARGS_WORD);
}
@ -655,7 +649,7 @@ args_checkpunct(const char *buf, int i)
}
static int
argv_multi(struct mdoc *m, int line,
argv_multi(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
@ -664,7 +658,7 @@ argv_multi(struct mdoc *m, int line,
for (v->sz = 0; ; v->sz++) {
if ('-' == buf[*pos])
break;
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
if (ARGS_ERROR == ac)
return(0);
else if (ARGS_EOLN == ac)
@ -681,16 +675,13 @@ argv_multi(struct mdoc *m, int line,
}
static int
argv_opt_single(struct mdoc *m, int line,
argv_single(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
char *p;
if ('-' == buf[*pos])
return(1);
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
if (ARGS_ERROR == ac)
return(0);
if (ARGS_EOLN == ac)
@ -702,27 +693,3 @@ argv_opt_single(struct mdoc *m, int line,
return(1);
}
static int
argv_single(struct mdoc *m, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
int ppos;
enum margserr ac;
char *p;
ppos = *pos;
ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
if (ARGS_EOLN == ac) {
mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
return(0);
} else if (ARGS_ERROR == ac)
return(0);
v->sz = 1;
v->value = mandoc_malloc(sizeof(char *));
v->value[0] = mandoc_strdup(p);
return(1);
}

View File

@ -1,7 +1,8 @@
/* $Vendor-Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */
/* Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -41,8 +42,8 @@ struct termpair {
#define DECL_ARGS struct termp *p, \
struct termpair *pair, \
const struct mdoc_meta *m, \
const struct mdoc_node *n
const struct mdoc_meta *meta, \
struct mdoc_node *n
struct termact {
int (*pre)(DECL_ARGS);
@ -69,7 +70,7 @@ static void termp_an_post(DECL_ARGS);
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
static void termp_d1_post(DECL_ARGS);
static void termp_fd_post(DECL_ARGS);
static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
static void termp_it_post(DECL_ARGS);
@ -100,7 +101,6 @@ static int termp_fl_pre(DECL_ARGS);
static int termp_fn_pre(DECL_ARGS);
static int termp_fo_pre(DECL_ARGS);
static int termp_ft_pre(DECL_ARGS);
static int termp_igndelim_pre(DECL_ARGS);
static int termp_in_pre(DECL_ARGS);
static int termp_it_pre(DECL_ARGS);
static int termp_li_pre(DECL_ARGS);
@ -129,8 +129,8 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_sh_pre, termp_sh_post }, /* Sh */
{ termp_ss_pre, termp_ss_post }, /* Ss */
{ termp_sp_pre, NULL }, /* Pp */
{ termp_d1_pre, termp_d1_post }, /* D1 */
{ termp_d1_pre, termp_d1_post }, /* Dl */
{ termp_d1_pre, termp_bl_post }, /* D1 */
{ termp_d1_pre, termp_bl_post }, /* Dl */
{ termp_bd_pre, termp_bd_post }, /* Bd */
{ NULL, NULL }, /* Ed */
{ termp_bl_pre, termp_bl_post }, /* Bl */
@ -146,7 +146,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* Ev */
{ termp_ex_pre, NULL }, /* Ex */
{ termp_fa_pre, NULL }, /* Fa */
{ termp_fd_pre, NULL }, /* Fd */
{ termp_fd_pre, termp_fd_post }, /* Fd */
{ termp_fl_pre, NULL }, /* Fl */
{ termp_fn_pre, NULL }, /* Fn */
{ termp_ft_pre, NULL }, /* Ft */
@ -194,12 +194,12 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
{ termp_igndelim_pre, NULL }, /* No */
{ NULL, NULL }, /* No */
{ termp_ns_pre, NULL }, /* Ns */
{ termp_xx_pre, NULL }, /* Nx */
{ termp_xx_pre, NULL }, /* Ox */
{ NULL, NULL }, /* Pc */
{ termp_igndelim_pre, termp_pf_post }, /* Pf */
{ NULL, termp_pf_post }, /* Pf */
{ termp_quote_pre, termp_quote_post }, /* Po */
{ termp_quote_pre, termp_quote_post }, /* Pq */
{ NULL, NULL }, /* Qc */
@ -242,7 +242,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ NULL, termp____post }, /* %Q */
{ termp_sp_pre, NULL }, /* br */
{ termp_sp_pre, NULL }, /* sp */
{ termp_under_pre, termp____post }, /* %U */
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
};
@ -251,7 +251,7 @@ void
terminal_mdoc(void *arg, const struct mdoc *mdoc)
{
const struct mdoc_node *n;
const struct mdoc_meta *m;
const struct mdoc_meta *meta;
struct termp *p;
p = (struct termp *)arg;
@ -267,12 +267,12 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc)
p->symtab = mchars_alloc();
n = mdoc_node(mdoc);
m = mdoc_meta(mdoc);
meta = mdoc_meta(mdoc);
term_begin(p, print_mdoc_head, print_mdoc_foot, m);
term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
if (n->child)
print_mdoc_nodelist(p, NULL, m, n->child);
print_mdoc_nodelist(p, NULL, meta, n->child);
term_end(p);
}
@ -282,9 +282,9 @@ static void
print_mdoc_nodelist(DECL_ARGS)
{
print_mdoc_node(p, pair, m, n);
print_mdoc_node(p, pair, meta, n);
if (n->next)
print_mdoc_nodelist(p, pair, m, n->next);
print_mdoc_nodelist(p, pair, meta, n->next);
}
@ -293,14 +293,13 @@ static void
print_mdoc_node(DECL_ARGS)
{
int chld;
const void *font;
struct termpair npair;
size_t offset, rmargin;
chld = 1;
offset = p->offset;
rmargin = p->rmargin;
font = term_fontq(p);
n->prev_font = term_fontq(p);
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
@ -308,33 +307,16 @@ print_mdoc_node(DECL_ARGS)
/*
* Keeps only work until the end of a line. If a keep was
* invoked in a prior line, revert it to PREKEEP.
*
* Also let SYNPRETTY sections behave as if they were wrapped
* in a `Bk' block.
*/
if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) {
if (n->prev && n->prev->line != n->line) {
if (TERMP_KEEP & p->flags) {
if (n->prev ? (n->prev->lastline != n->line) :
(n->parent && n->parent->line != n->line)) {
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_PREKEEP;
} else if (NULL == n->prev) {
if (n->parent && n->parent->line != n->line) {
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_PREKEEP;
}
}
}
/*
* Since SYNPRETTY sections aren't "turned off" with `Ek',
* we have to intuit whether we should disable formatting.
*/
if ( ! (MDOC_SYNPRETTY & n->flags) &&
((n->prev && MDOC_SYNPRETTY & n->prev->flags) ||
(n->parent && MDOC_SYNPRETTY & n->parent->flags)))
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
/*
* After the keep flags have been set up, we may now
* produce output. Note that some pre-handlers do so.
@ -359,14 +341,15 @@ print_mdoc_node(DECL_ARGS)
default:
if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
chld = (*termacts[n->tok].pre)
(p, &npair, m, n);
(p, &npair, meta, n);
break;
}
if (chld && n->child)
print_mdoc_nodelist(p, &npair, m, n->child);
print_mdoc_nodelist(p, &npair, meta, n->child);
term_fontpopq(p, font);
term_fontpopq(p,
(ENDBODY_NOT == n->end ? n : n->pending)->prev_font);
switch (n->type) {
case (MDOC_TEXT):
@ -378,7 +361,7 @@ print_mdoc_node(DECL_ARGS)
default:
if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
break;
(void)(*termacts[n->tok].post)(p, &npair, m, n);
(void)(*termacts[n->tok].post)(p, &npair, meta, n);
/*
* Explicit end tokens not only call the post
@ -409,9 +392,9 @@ print_mdoc_node(DECL_ARGS)
static void
print_mdoc_foot(struct termp *p, const void *arg)
{
const struct mdoc_meta *m;
const struct mdoc_meta *meta;
m = (const struct mdoc_meta *)arg;
meta = (const struct mdoc_meta *)arg;
term_fontrepl(p, TERMFONT_NONE);
@ -427,25 +410,27 @@ print_mdoc_foot(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = (p->maxrmargin -
term_strlen(p, m->date) + term_len(p, 1)) / 2;
term_strlen(p, meta->date) + term_len(p, 1)) / 2;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
term_word(p, m->os);
term_word(p, meta->os);
term_flushln(p);
p->offset = p->rmargin;
p->rmargin = p->maxrmargin - term_strlen(p, m->os);
p->rmargin = p->maxrmargin - term_strlen(p, meta->os);
p->flags |= TERMP_NOSPACE;
term_word(p, m->date);
term_word(p, meta->date);
term_flushln(p);
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
term_word(p, m->os);
term_word(p, meta->os);
term_flushln(p);
p->offset = 0;
@ -459,9 +444,9 @@ print_mdoc_head(struct termp *p, const void *arg)
{
char buf[BUFSIZ], title[BUFSIZ];
size_t buflen, titlen;
const struct mdoc_meta *m;
const struct mdoc_meta *meta;
m = (const struct mdoc_meta *)arg;
meta = (const struct mdoc_meta *)arg;
/*
* The header is strange. It has three components, which are
@ -479,20 +464,21 @@ print_mdoc_head(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = p->maxrmargin;
assert(m->vol);
strlcpy(buf, m->vol, BUFSIZ);
assert(meta->vol);
strlcpy(buf, meta->vol, BUFSIZ);
buflen = term_strlen(p, buf);
if (m->arch) {
if (meta->arch) {
strlcat(buf, " (", BUFSIZ);
strlcat(buf, m->arch, BUFSIZ);
strlcat(buf, meta->arch, BUFSIZ);
strlcat(buf, ")", BUFSIZ);
}
snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
(p->maxrmargin -
@ -511,6 +497,7 @@ print_mdoc_head(struct termp *p, const void *arg)
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
@ -727,12 +714,10 @@ termp_it_pre(DECL_ARGS)
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_hyphen):
if (width < term_len(p, 4))
width = term_len(p, 4);
break;
/* FALLTHROUGH */
case (LIST_enum):
if (width < term_len(p, 5))
width = term_len(p, 5);
if (width < term_len(p, 2))
width = term_len(p, 2);
break;
case (LIST_hang):
if (0 == width)
@ -787,20 +772,26 @@ termp_it_pre(DECL_ARGS)
*/
switch (type) {
case (LIST_enum):
/*
* Weird special case.
* Very narrow enum lists actually hang.
*/
if (width == term_len(p, 2))
p->flags |= TERMP_HANG;
/* FALLTHROUGH */
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_enum):
/* FALLTHROUGH */
case (LIST_hyphen):
if (MDOC_HEAD == n->type)
p->flags |= TERMP_NOBREAK;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case (LIST_hang):
if (MDOC_HEAD == n->type)
p->flags |= TERMP_NOBREAK;
else
if (MDOC_HEAD != n->type)
break;
/*
@ -812,16 +803,18 @@ termp_it_pre(DECL_ARGS)
if (n->next->child &&
(MDOC_Bl == n->next->child->tok ||
MDOC_Bd == n->next->child->tok))
p->flags &= ~TERMP_NOBREAK;
else
p->flags |= TERMP_HANG;
break;
p->flags |= TERMP_NOBREAK | TERMP_HANG;
p->trailspace = 1;
break;
case (LIST_tag):
if (MDOC_HEAD == n->type)
p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 2;
if (NULL == n->next || NULL == n->next->child)
p->flags |= TERMP_DANGLE;
break;
@ -829,15 +822,20 @@ termp_it_pre(DECL_ARGS)
if (MDOC_HEAD == n->type)
break;
if (NULL == n->next)
if (NULL == n->next) {
p->flags &= ~TERMP_NOBREAK;
else
p->trailspace = 0;
} else {
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
}
break;
case (LIST_diag):
if (MDOC_HEAD == n->type)
p->flags |= TERMP_NOBREAK;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
default:
break;
@ -989,8 +987,8 @@ termp_it_post(DECL_ARGS)
p->flags &= ~TERMP_DANGLE;
p->flags &= ~TERMP_NOBREAK;
p->flags &= ~TERMP_TWOSPACE;
p->flags &= ~TERMP_HANG;
p->trailspace = 0;
}
@ -999,22 +997,25 @@ static int
termp_nm_pre(DECL_ARGS)
{
if (MDOC_BLOCK == n->type)
if (MDOC_BLOCK == n->type) {
p->flags |= TERMP_PREKEEP;
return(1);
}
if (MDOC_BODY == n->type) {
if (NULL == n->child)
return(0);
p->flags |= TERMP_NOSPACE;
p->offset += term_len(p, 1) +
(NULL == n->prev->child ? term_strlen(p, m->name) :
(NULL == n->prev->child ?
term_strlen(p, meta->name) :
MDOC_TEXT == n->prev->child->type ?
term_strlen(p, n->prev->child->string) :
term_strlen(p, n->prev->child->string) :
term_len(p, 5));
return(1);
}
if (NULL == n->child && NULL == m->name)
if (NULL == n->child && NULL == meta->name)
return(0);
if (MDOC_HEAD == n->type)
@ -1022,9 +1023,10 @@ termp_nm_pre(DECL_ARGS)
if (MDOC_HEAD == n->type && n->next->child) {
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1);
if (NULL == n->child) {
p->rmargin += term_strlen(p, m->name);
p->rmargin += term_strlen(p, meta->name);
} else if (MDOC_TEXT == n->child->type) {
p->rmargin += term_strlen(p, n->child->string);
if (n->child->next)
@ -1037,7 +1039,7 @@ termp_nm_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD);
if (NULL == n->child)
term_word(p, m->name);
term_word(p, meta->name);
return(1);
}
@ -1047,9 +1049,12 @@ static void
termp_nm_post(DECL_ARGS)
{
if (MDOC_HEAD == n->type && n->next->child) {
if (MDOC_BLOCK == n->type) {
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
} else if (MDOC_HEAD == n->type && n->next->child) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
p->trailspace = 0;
} else if (MDOC_BODY == n->type && n->child)
term_flushln(p);
}
@ -1375,14 +1380,14 @@ termp_vt_pre(DECL_ARGS)
if (MDOC_ELEM == n->type) {
synopsis_pre(p, n);
return(termp_under_pre(p, pair, m, n));
return(termp_under_pre(p, pair, meta, n));
} else if (MDOC_BLOCK == n->type) {
synopsis_pre(p, n);
return(1);
} else if (MDOC_HEAD == n->type)
return(0);
return(termp_under_pre(p, pair, m, n));
return(termp_under_pre(p, pair, meta, n));
}
@ -1402,7 +1407,16 @@ termp_fd_pre(DECL_ARGS)
{
synopsis_pre(p, n);
return(termp_bold_pre(p, pair, m, n));
return(termp_bold_pre(p, pair, meta, n));
}
/* ARGSUSED */
static void
termp_fd_post(DECL_ARGS)
{
term_newln(p);
}
@ -1425,6 +1439,8 @@ termp_sh_pre(DECL_ARGS)
break;
case (MDOC_BODY):
p->offset = term_len(p, p->defindent);
if (SEC_AUTHORS == n->sec)
p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
break;
default:
break;
@ -1497,17 +1513,6 @@ termp_d1_pre(DECL_ARGS)
}
/* ARGSUSED */
static void
termp_d1_post(DECL_ARGS)
{
if (MDOC_BLOCK != n->type)
return;
term_newln(p);
}
/* ARGSUSED */
static int
termp_ft_pre(DECL_ARGS)
@ -1524,6 +1529,7 @@ termp_ft_pre(DECL_ARGS)
static int
termp_fn_pre(DECL_ARGS)
{
size_t rmargin = 0;
int pretty;
pretty = MDOC_SYNPRETTY & n->flags;
@ -1533,11 +1539,24 @@ termp_fn_pre(DECL_ARGS)
if (NULL == (n = n->child))
return(0);
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_HANG;
}
assert(MDOC_TEXT == n->type);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, n->string);
term_fontpop(p);
if (pretty) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
@ -1545,6 +1564,8 @@ termp_fn_pre(DECL_ARGS)
for (n = n->next; n; n = n->next) {
assert(MDOC_TEXT == n->type);
term_fontpush(p, TERMFONT_UNDER);
if (pretty)
p->flags |= TERMP_NBRWORD;
term_word(p, n->string);
term_fontpop(p);
@ -1560,6 +1581,7 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
p->flags |= TERMP_NOSPACE;
term_word(p, ";");
term_flushln(p);
}
return(0);
@ -1579,20 +1601,16 @@ termp_fa_pre(DECL_ARGS)
for (nn = n->child; nn; nn = nn->next) {
term_fontpush(p, TERMFONT_UNDER);
p->flags |= TERMP_NBRWORD;
term_word(p, nn->string);
term_fontpop(p);
if (nn->next) {
if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
}
if (n->child && n->next && n->next->tok == MDOC_Fa) {
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
return(0);
}
@ -1602,7 +1620,7 @@ static int
termp_bd_pre(DECL_ARGS)
{
size_t tabwidth, rm, rmax;
const struct mdoc_node *nn;
struct mdoc_node *nn;
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
@ -1634,7 +1652,7 @@ termp_bd_pre(DECL_ARGS)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
for (nn = n->child; nn; nn = nn->next) {
print_mdoc_node(p, pair, m, nn);
print_mdoc_node(p, pair, meta, nn);
/*
* If the printed node flushes its own line, then we
* needn't do it here as well. This is hacky, but the
@ -1751,7 +1769,8 @@ termp_xx_pre(DECL_ARGS)
pp = "UNIX";
break;
default:
break;
abort();
/* NOTREACHED */
}
term_word(p, pp);
@ -1765,16 +1784,6 @@ termp_xx_pre(DECL_ARGS)
}
/* ARGSUSED */
static int
termp_igndelim_pre(DECL_ARGS)
{
p->flags |= TERMP_IGNDELIM;
return(1);
}
/* ARGSUSED */
static void
termp_pf_post(DECL_ARGS)
@ -1923,7 +1932,7 @@ termp_quote_pre(DECL_ARGS)
case (MDOC_Do):
/* FALLTHROUGH */
case (MDOC_Dq):
term_word(p, "``");
term_word(p, "\\(lq");
break;
case (MDOC_Eo):
break;
@ -1944,7 +1953,7 @@ termp_quote_pre(DECL_ARGS)
case (MDOC_So):
/* FALLTHROUGH */
case (MDOC_Sq):
term_word(p, "`");
term_word(p, "\\(oq");
break;
default:
abort();
@ -1989,7 +1998,7 @@ termp_quote_post(DECL_ARGS)
case (MDOC_Do):
/* FALLTHROUGH */
case (MDOC_Dq):
term_word(p, "''");
term_word(p, "\\(rq");
break;
case (MDOC_Eo):
break;
@ -2010,7 +2019,7 @@ termp_quote_post(DECL_ARGS)
case (MDOC_So):
/* FALLTHROUGH */
case (MDOC_Sq):
term_word(p, "'");
term_word(p, "\\(cq");
break;
default:
abort();
@ -2023,16 +2032,31 @@ termp_quote_post(DECL_ARGS)
static int
termp_fo_pre(DECL_ARGS)
{
size_t rmargin = 0;
int pretty;
pretty = MDOC_SYNPRETTY & n->flags;
if (MDOC_BLOCK == n->type) {
synopsis_pre(p, n);
return(1);
} else if (MDOC_BODY == n->type) {
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_HANG;
}
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
if (pretty) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
return(1);
}
}
if (NULL == n->child)
return(0);
@ -2060,6 +2084,7 @@ termp_fo_post(DECL_ARGS)
if (MDOC_SYNPRETTY & n->flags) {
p->flags |= TERMP_NOSPACE;
term_word(p, ";");
term_flushln(p);
}
}
@ -2071,7 +2096,7 @@ termp_bf_pre(DECL_ARGS)
if (MDOC_HEAD == n->type)
return(0);
else if (MDOC_BLOCK != n->type)
else if (MDOC_BODY != n->type)
return(1);
if (FONT_Em == n->norm->Bf.font)
@ -2157,25 +2182,24 @@ termp_li_pre(DECL_ARGS)
static int
termp_lk_pre(DECL_ARGS)
{
const struct mdoc_node *nn, *sv;
const struct mdoc_node *link, *descr;
term_fontpush(p, TERMFONT_UNDER);
if (NULL == (link = n->child))
return(0);
nn = sv = n->child;
if (NULL == nn || NULL == nn->next)
return(1);
for (nn = nn->next; nn; nn = nn->next)
term_word(p, nn->string);
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, ":");
if (NULL != (descr = link->next)) {
term_fontpush(p, TERMFONT_UNDER);
while (NULL != descr) {
term_word(p, descr->string);
descr = descr->next;
}
p->flags |= TERMP_NOSPACE;
term_word(p, ":");
term_fontpop(p);
}
term_fontpush(p, TERMFONT_BOLD);
term_word(p, sv->string);
term_word(p, link->string);
term_fontpop(p);
return(0);
@ -2225,9 +2249,9 @@ termp__t_post(DECL_ARGS)
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
n->parent->norm->Rs.quote_T)
termp_quote_post(p, pair, m, n);
termp_quote_post(p, pair, meta, n);
termp____post(p, pair, m, n);
termp____post(p, pair, meta, n);
}
/* ARGSUSED */
@ -2241,7 +2265,7 @@ termp__t_pre(DECL_ARGS)
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
n->parent->norm->Rs.quote_T)
return(termp_quote_pre(p, pair, m, n));
return(termp_quote_pre(p, pair, meta, n));
term_fontpush(p, TERMFONT_UNDER);
return(1);

View File

@ -1,7 +1,7 @@
/* $Vendor-Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */
/* Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011, 2012, 2013 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
@ -19,7 +19,7 @@
#include "config.h"
#endif
#ifndef OSNAME
#ifndef OSNAME
#include <sys/utsname.h>
#endif
@ -97,17 +97,19 @@ static int post_bl_block_width(POST_ARGS);
static int post_bl_block_tag(POST_ARGS);
static int post_bl_head(POST_ARGS);
static int post_bx(POST_ARGS);
static int post_defaults(POST_ARGS);
static int post_dd(POST_ARGS);
static int post_dt(POST_ARGS);
static int post_defaults(POST_ARGS);
static int post_literal(POST_ARGS);
static int post_eoln(POST_ARGS);
static int post_hyph(POST_ARGS);
static int post_ignpar(POST_ARGS);
static int post_it(POST_ARGS);
static int post_lb(POST_ARGS);
static int post_literal(POST_ARGS);
static int post_nm(POST_ARGS);
static int post_ns(POST_ARGS);
static int post_os(POST_ARGS);
static int post_ignpar(POST_ARGS);
static int post_par(POST_ARGS);
static int post_prol(POST_ARGS);
static int post_root(POST_ARGS);
static int post_rs(POST_ARGS);
@ -141,27 +143,30 @@ static v_post posts_bx[] = { post_bx, NULL };
static v_post posts_bool[] = { ebool, NULL };
static v_post posts_eoln[] = { post_eoln, NULL };
static v_post posts_defaults[] = { post_defaults, NULL };
static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
static v_post posts_dd[] = { post_dd, post_prol, NULL };
static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
static v_post posts_dt[] = { post_dt, post_prol, NULL };
static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
static v_post posts_hyph[] = { post_hyph, NULL };
static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
static v_post posts_it[] = { post_it, NULL };
static v_post posts_lb[] = { post_lb, NULL };
static v_post posts_nd[] = { berr_ge1, NULL };
static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
static v_post posts_nm[] = { post_nm, NULL };
static v_post posts_notext[] = { ewarn_eq0, NULL };
static v_post posts_ns[] = { post_ns, NULL };
static v_post posts_os[] = { post_os, post_prol, NULL };
static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
static v_post posts_rs[] = { post_rs, NULL };
static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
static v_post posts_sp[] = { ewarn_le1, NULL };
static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
static v_post posts_st[] = { post_st, NULL };
static v_post posts_std[] = { post_std, NULL };
static v_post posts_text[] = { ewarn_ge1, NULL };
static v_post posts_text1[] = { ewarn_eq1, NULL };
static v_post posts_vt[] = { post_vt, NULL };
static v_post posts_wline[] = { bwarn_ge1, NULL };
static v_pre pres_an[] = { pre_an, NULL };
static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
@ -169,8 +174,6 @@ static v_pre pres_d1[] = { pre_display, NULL };
static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
static v_pre pres_dd[] = { pre_dd, NULL };
static v_pre pres_dt[] = { pre_dt, NULL };
static v_pre pres_er[] = { NULL, NULL };
static v_pre pres_fd[] = { NULL, NULL };
static v_pre pres_it[] = { pre_it, pre_par, NULL };
static v_pre pres_os[] = { pre_os, NULL };
static v_pre pres_pp[] = { pre_par, NULL };
@ -185,8 +188,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ pres_os, posts_os }, /* Os */
{ pres_sh, posts_sh }, /* Sh */
{ pres_ss, posts_ss }, /* Ss */
{ pres_pp, posts_notext }, /* Pp */
{ pres_d1, posts_wline }, /* D1 */
{ pres_pp, posts_pp }, /* Pp */
{ pres_d1, posts_d1 }, /* D1 */
{ pres_dl, posts_dl }, /* Dl */
{ pres_bd, posts_bd }, /* Bd */
{ NULL, NULL }, /* Ed */
@ -199,11 +202,11 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Cd */
{ NULL, NULL }, /* Cm */
{ NULL, NULL }, /* Dv */
{ pres_er, NULL }, /* Er */
{ NULL, NULL }, /* Er */
{ NULL, NULL }, /* Ev */
{ pres_std, posts_std }, /* Ex */
{ NULL, NULL }, /* Fa */
{ pres_fd, posts_text }, /* Fd */
{ NULL, posts_text }, /* Fd */
{ NULL, NULL }, /* Fl */
{ NULL, NULL }, /* Fn */
{ NULL, NULL }, /* Ft */
@ -221,15 +224,15 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, posts_vt }, /* Vt */
{ NULL, posts_text }, /* Xr */
{ NULL, posts_text }, /* %A */
{ NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */
{ NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
{ NULL, posts_text }, /* %D */
{ NULL, posts_text }, /* %I */
{ NULL, posts_text }, /* %J */
{ NULL, posts_text }, /* %N */
{ NULL, posts_text }, /* %O */
{ NULL, posts_hyphtext }, /* %N */
{ NULL, posts_hyphtext }, /* %O */
{ NULL, posts_text }, /* %P */
{ NULL, posts_text }, /* %R */
{ NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */
{ NULL, posts_hyphtext }, /* %R */
{ NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
{ NULL, posts_text }, /* %V */
{ NULL, NULL }, /* Ac */
{ NULL, NULL }, /* Ao */
@ -269,7 +272,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
{ NULL, posts_bool }, /* Sm */
{ NULL, NULL }, /* Sx */
{ NULL, posts_hyph }, /* Sx */
{ NULL, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
{ NULL, NULL }, /* Ux */
@ -286,7 +289,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Fr */
{ NULL, posts_eoln }, /* Ud */
{ NULL, posts_lb }, /* Lb */
{ NULL, posts_notext }, /* Lp */
{ pres_pp, posts_pp }, /* Lp */
{ NULL, NULL }, /* Lk */
{ NULL, posts_defaults }, /* Mt */
{ NULL, NULL }, /* Brq */
@ -297,8 +300,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* En */
{ NULL, NULL }, /* Dx */
{ NULL, posts_text }, /* %Q */
{ NULL, posts_notext }, /* br */
{ pres_pp, posts_sp }, /* sp */
{ NULL, posts_pp }, /* br */
{ NULL, posts_sp }, /* sp */
{ NULL, posts_text1 }, /* %U */
{ NULL, NULL }, /* Ta */
};
@ -314,12 +317,12 @@ static const enum mdoct rsord[RSORD_MAX] = {
MDOC__R,
MDOC__N,
MDOC__V,
MDOC__U,
MDOC__P,
MDOC__Q,
MDOC__D,
MDOC__O,
MDOC__C,
MDOC__U
MDOC__D,
MDOC__O
};
static const char * const secnames[SEC__MAX] = {
@ -414,29 +417,29 @@ mdoc_valid_post(struct mdoc *mdoc)
}
static int
check_count(struct mdoc *m, enum mdoc_type type,
check_count(struct mdoc *mdoc, enum mdoc_type type,
enum check_lvl lvl, enum check_ineq ineq, int val)
{
const char *p;
enum mandocerr t;
if (m->last->type != type)
if (mdoc->last->type != type)
return(1);
switch (ineq) {
case (CHECK_LT):
p = "less than ";
if (m->last->nchild < val)
if (mdoc->last->nchild < val)
return(1);
break;
case (CHECK_GT):
p = "more than ";
if (m->last->nchild > val)
if (mdoc->last->nchild > val)
return(1);
break;
case (CHECK_EQ):
p = "";
if (val == m->last->nchild)
if (val == mdoc->last->nchild)
return(1);
break;
default:
@ -445,9 +448,9 @@ check_count(struct mdoc *m, enum mdoc_type type,
}
t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
"want %s%d children (have %d)",
p, val, m->last->nchild);
p, val, mdoc->last->nchild);
return(1);
}
@ -513,7 +516,7 @@ hwarn_le1(POST_ARGS)
}
static void
check_args(struct mdoc *m, struct mdoc_node *n)
check_args(struct mdoc *mdoc, struct mdoc_node *n)
{
int i;
@ -522,34 +525,34 @@ check_args(struct mdoc *m, struct mdoc_node *n)
assert(n->args->argc);
for (i = 0; i < (int)n->args->argc; i++)
check_argv(m, n, &n->args->argv[i]);
check_argv(mdoc, n, &n->args->argv[i]);
}
static void
check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
{
int i;
for (i = 0; i < (int)v->sz; i++)
check_text(m, v->line, v->pos, v->value[i]);
check_text(mdoc, v->line, v->pos, v->value[i]);
/* FIXME: move to post_std(). */
if (MDOC_Std == v->arg)
if ( ! (v->sz || m->meta.name))
mdoc_nmsg(m, n, MANDOCERR_NONAME);
if ( ! (v->sz || mdoc->meta.name))
mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
}
static void
check_text(struct mdoc *m, int ln, int pos, char *p)
check_text(struct mdoc *mdoc, int ln, int pos, char *p)
{
char *cp;
if (MDOC_LITERAL & m->flags)
if (MDOC_LITERAL & mdoc->flags)
return;
for (cp = p; NULL != (p = strchr(p, '\t')); p++)
mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
}
static int
@ -733,14 +736,14 @@ pre_bl(PRE_ARGS)
/*
* Validate the width field. Some list types don't need width
* types and should be warned about them. Others should have it
* and must also be warned.
* and must also be warned. Yet others have a default and need
* no warning.
*/
switch (n->norm->Bl.type) {
case (LIST_tag):
if (n->norm->Bl.width)
break;
mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
if (NULL == n->norm->Bl.width)
mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
break;
case (LIST_column):
/* FALLTHROUGH */
@ -754,6 +757,18 @@ pre_bl(PRE_ARGS)
if (n->norm->Bl.width)
mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
break;
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_hyphen):
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "2n";
break;
case (LIST_enum):
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "3n";
break;
default:
break;
}
@ -874,8 +889,6 @@ pre_sh(PRE_ARGS)
if (MDOC_BLOCK != n->type)
return(1);
roff_regunset(mdoc->roff, REG_nS);
return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
}
@ -1111,24 +1124,29 @@ post_nm(POST_ARGS)
char buf[BUFSIZ];
int c;
/* If no child specified, make sure we have the meta name. */
if (NULL == mdoc->last->child && NULL == mdoc->meta.name) {
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
return(1);
} else if (mdoc->meta.name)
if (NULL != mdoc->meta.name)
return(1);
/* If no meta name, set it from the child. */
/* Try to use our children for setting the meta name. */
buf[0] = '\0';
if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
if (NULL != mdoc->last->child) {
buf[0] = '\0';
c = concat(buf, mdoc->last->child, BUFSIZ);
} else
c = 0;
switch (c) {
case (-1):
mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
return(0);
case (0):
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
mdoc->meta.name = mandoc_strdup("UNKNOWN");
break;
default:
mdoc->meta.name = mandoc_strdup(buf);
break;
}
assert(c);
mdoc->meta.name = mandoc_strdup(buf);
return(1);
}
@ -1334,7 +1352,7 @@ post_it(POST_ARGS)
static int
post_bl_block(POST_ARGS)
{
struct mdoc_node *n;
struct mdoc_node *n, *ni, *nc;
/*
* These are fairly complicated, so we've broken them into two
@ -1350,13 +1368,42 @@ post_bl_block(POST_ARGS)
NULL == n->norm->Bl.width) {
if ( ! post_bl_block_tag(mdoc))
return(0);
assert(n->norm->Bl.width);
} else if (NULL != n->norm->Bl.width) {
if ( ! post_bl_block_width(mdoc))
return(0);
} else
return(1);
assert(n->norm->Bl.width);
}
assert(n->norm->Bl.width);
for (ni = n->body->child; ni; ni = ni->next) {
if (NULL == ni->body)
continue;
nc = ni->body->last;
while (NULL != nc) {
switch (nc->tok) {
case (MDOC_Pp):
/* FALLTHROUGH */
case (MDOC_Lp):
/* FALLTHROUGH */
case (MDOC_br):
break;
default:
nc = NULL;
continue;
}
if (NULL == ni->next) {
mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
if ( ! mdoc_node_relink(mdoc, nc))
return(0);
} else if (0 == n->norm->Bl.comp &&
LIST_column != n->norm->Bl.type) {
mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
mdoc_node_delete(mdoc, nc);
} else
break;
nc = ni->body->last;
}
}
return(1);
}
@ -1544,32 +1591,71 @@ post_bl_head(POST_ARGS)
static int
post_bl(POST_ARGS)
{
struct mdoc_node *n;
struct mdoc_node *nparent, *nprev; /* of the Bl block */
struct mdoc_node *nblock, *nbody; /* of the Bl */
struct mdoc_node *nchild, *nnext; /* of the Bl body */
if (MDOC_HEAD == mdoc->last->type)
return(post_bl_head(mdoc));
if (MDOC_BLOCK == mdoc->last->type)
nbody = mdoc->last;
switch (nbody->type) {
case (MDOC_BLOCK):
return(post_bl_block(mdoc));
if (MDOC_BODY != mdoc->last->type)
case (MDOC_HEAD):
return(post_bl_head(mdoc));
case (MDOC_BODY):
break;
default:
return(1);
}
for (n = mdoc->last->child; n; n = n->next) {
switch (n->tok) {
case (MDOC_Lp):
/* FALLTHROUGH */
case (MDOC_Pp):
mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
/* FALLTHROUGH */
case (MDOC_It):
/* FALLTHROUGH */
case (MDOC_Sm):
nchild = nbody->child;
while (NULL != nchild) {
if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
nchild = nchild->next;
continue;
default:
break;
}
mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
return(0);
mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
/*
* Move the node out of the Bl block.
* First, collect all required node pointers.
*/
nblock = nbody->parent;
nprev = nblock->prev;
nparent = nblock->parent;
nnext = nchild->next;
/*
* Unlink this child.
*/
assert(NULL == nchild->prev);
if (0 == --nbody->nchild) {
nbody->child = NULL;
nbody->last = NULL;
assert(NULL == nnext);
} else {
nbody->child = nnext;
nnext->prev = NULL;
}
/*
* Relink this child.
*/
nchild->parent = nparent;
nchild->prev = nprev;
nchild->next = nblock;
nblock->prev = nchild;
nparent->nchild++;
if (NULL == nprev)
nparent->child = nchild;
else
nprev->next = nchild;
nchild = nnext;
}
return(1);
@ -1588,10 +1674,16 @@ ebool(struct mdoc *mdoc)
assert(MDOC_TEXT == mdoc->last->child->type);
if (0 == strcmp(mdoc->last->child->string, "on"))
if (0 == strcmp(mdoc->last->child->string, "on")) {
if (MDOC_Sm == mdoc->last->tok)
mdoc->flags &= ~MDOC_SMOFF;
return(1);
if (0 == strcmp(mdoc->last->child->string, "off"))
}
if (0 == strcmp(mdoc->last->child->string, "off")) {
if (MDOC_Sm == mdoc->last->tok)
mdoc->flags |= MDOC_SMOFF;
return(1);
}
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
return(1);
@ -1771,6 +1863,47 @@ post_rs(POST_ARGS)
return(1);
}
/*
* For some arguments of some macros,
* convert all breakable hyphens into ASCII_HYPH.
*/
static int
post_hyph(POST_ARGS)
{
struct mdoc_node *n, *nch;
char *cp;
n = mdoc->last;
switch (n->type) {
case (MDOC_HEAD):
if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
break;
return(1);
case (MDOC_BODY):
if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
break;
return(1);
case (MDOC_ELEM):
break;
default:
return(1);
}
for (nch = n->child; nch; nch = nch->next) {
if (MDOC_TEXT != nch->type)
continue;
cp = nch->string;
if (3 > strnlen(cp, 3))
continue;
while ('\0' != *(++cp))
if ('-' == *cp &&
isalpha((unsigned char)cp[-1]) &&
isalpha((unsigned char)cp[1]))
*cp = ASCII_HYPH;
}
return(1);
}
static int
post_ns(POST_ARGS)
{
@ -1857,10 +1990,13 @@ post_sh_head(POST_ARGS)
/* The SYNOPSIS gets special attention in other areas. */
if (SEC_SYNOPSIS == sec)
if (SEC_SYNOPSIS == sec) {
roff_setreg(mdoc->roff, "nS", 1, '=');
mdoc->flags |= MDOC_SYNOPSIS;
else
} else {
roff_setreg(mdoc->roff, "nS", 0, '=');
mdoc->flags &= ~MDOC_SYNOPSIS;
}
/* Mark our last section. */
@ -1916,7 +2052,8 @@ post_sh_head(POST_ARGS)
break;
if (*mdoc->meta.msec == '9')
break;
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC);
mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
mdoc->last->line, mdoc->last->pos, buf);
break;
default:
break;
@ -1962,7 +2099,9 @@ pre_par(PRE_ARGS)
* block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
*/
if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
if (MDOC_Pp != mdoc->last->tok &&
MDOC_Lp != mdoc->last->tok &&
MDOC_br != mdoc->last->tok)
return(1);
if (MDOC_Bl == n->tok && n->norm->Bl.comp)
return(1);
@ -1976,6 +2115,32 @@ pre_par(PRE_ARGS)
return(1);
}
static int
post_par(POST_ARGS)
{
if (MDOC_ELEM != mdoc->last->type &&
MDOC_BLOCK != mdoc->last->type)
return(1);
if (NULL == mdoc->last->prev) {
if (MDOC_Sh != mdoc->last->parent->tok &&
MDOC_Ss != mdoc->last->parent->tok)
return(1);
} else {
if (MDOC_Pp != mdoc->last->prev->tok &&
MDOC_Lp != mdoc->last->prev->tok &&
(MDOC_br != mdoc->last->tok ||
(MDOC_sp != mdoc->last->prev->tok &&
MDOC_br != mdoc->last->prev->tok)))
return(1);
}
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
mdoc_node_delete(mdoc, mdoc->last);
return(1);
}
static int
pre_literal(PRE_ARGS)
{
@ -2129,9 +2294,9 @@ post_dt(POST_ARGS)
free(mdoc->meta.vol);
mdoc->meta.vol = mandoc_strdup(cp);
} else {
/* FIXME: warn about bad arch. */
cp = mdoc_a2arch(nn->string);
if (NULL == cp) {
mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
free(mdoc->meta.vol);
mdoc->meta.vol = mandoc_strdup(nn->string);
} else
@ -2192,14 +2357,15 @@ post_os(POST_ARGS)
n = mdoc->last;
/*
* Set the operating system by way of the `Os' macro. Note that
* if an argument isn't provided and -DOSNAME="\"foo\"" is
* provided during compilation, this value will be used instead
* of filling in "sysname release" from uname().
* Set the operating system by way of the `Os' macro.
* The order of precedence is:
* 1. the argument of the `Os' macro, unless empty
* 2. the -Ios=foo command line argument, if provided
* 3. -DOSNAME="\"foo\"", if provided during compilation
* 4. "sysname release" from uname(3)
*/
if (mdoc->meta.os)
free(mdoc->meta.os);
free(mdoc->meta.os);
buf[0] = '\0';
if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
@ -2209,11 +2375,11 @@ post_os(POST_ARGS)
assert(c);
/* XXX: yes, these can all be dynamically-adjusted buffers, but
* it's really not worth the extra hackery.
*/
if ('\0' == buf[0]) {
if (mdoc->defos) {
mdoc->meta.os = mandoc_strdup(mdoc->defos);
return(1);
}
#ifdef OSNAME
if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
mdoc_nmsg(mdoc, n, MANDOCERR_MEM);

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
/* Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps Exp */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*

View File

@ -1,7 +1,7 @@
/* $Vendor-Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */
/* Id: read.c,v 1.40 2014/01/02 16:29:55 schwarze Exp */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2014 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
@ -26,6 +26,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
@ -40,10 +41,6 @@
#include "man.h"
#include "main.h"
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
#define REPARSE_LIMIT 1000
struct buf {
@ -66,14 +63,17 @@ struct mparse {
void *arg; /* argument to mmsg */
const char *file;
struct buf *secondary;
char *defos; /* default operating system */
};
static void resize_buf(struct buf *, size_t);
static void mparse_buf_r(struct mparse *, struct buf, int);
static void mparse_readfd_r(struct mparse *, int, const char *, int);
static void pset(const char *, int, struct mparse *);
static int read_whole_file(const char *, int, struct buf *, int *);
static int read_whole_file(struct mparse *, const char *, int,
struct buf *, int *);
static void mparse_end(struct mparse *);
static void mparse_parse_buffer(struct mparse *, struct buf,
const char *);
static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
MANDOCERR_OK,
@ -94,6 +94,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"no title in document",
"document title should be all caps",
"unknown manual section",
"unknown manual volume or arch",
"date missing, using today's date",
"cannot parse date, using it verbatim",
"prologue macros out of order",
@ -105,14 +106,14 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
".so is fragile, better use ln(1)",
"NAME section must come first",
"bad NAME section contents",
"manual name not yet set",
"sections out of conventional order",
"duplicate section name",
"section not in conventional manual section",
"section header suited to sections 2, 3, and 9 only",
/* related to macros and nesting */
"skipping obsolete macro",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"blocks badly nested",
"child violates parent syntax",
@ -173,10 +174,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"escaped character not allowed in a name",
"manual name not yet set",
"skipping text before the first section header",
"skipping unknown macro",
"NOT IMPLEMENTED, please use groff: skipping request",
"argument count wrong",
"skipping column outside column list",
"skipping end of block that is not open",
"missing end of block",
"scope open on exit",
@ -184,12 +187,14 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"macro requires line argument(s)",
"macro requires body argument(s)",
"macro requires argument(s)",
"request requires a numeric argument",
"missing list type",
"line argument(s) will be lost",
"body argument(s) will be lost",
"generic fatal error",
"input too large",
"not a manual",
"column syntax is inconsistent",
"NOT IMPLEMENTED: .Bd -file",
@ -200,6 +205,11 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"no document body",
"no document prologue",
"static buffer exhausted",
/* system errors */
"cannot open file",
"cannot stat file",
"cannot read file",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@ -247,7 +257,8 @@ pset(const char *buf, int pos, struct mparse *curp)
switch (curp->inttype) {
case (MPARSE_MDOC):
if (NULL == curp->pmdoc)
curp->pmdoc = mdoc_alloc(curp->roff, curp);
curp->pmdoc = mdoc_alloc(curp->roff, curp,
curp->defos);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
@ -263,7 +274,8 @@ pset(const char *buf, int pos, struct mparse *curp)
if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
if (NULL == curp->pmdoc)
curp->pmdoc = mdoc_alloc(curp->roff, curp);
curp->pmdoc = mdoc_alloc(curp->roff, curp,
curp->defos);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
@ -322,6 +334,15 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
break;
}
/*
* Make sure we have space for at least
* one backslash and one other character
* and the trailing NUL byte.
*/
if (pos + 2 >= (int)ln.sz)
resize_buf(&ln, 256);
/*
* Warn about bogus characters. If you're using
* non-ASCII encoding, you're screwing your
@ -338,26 +359,17 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
mandoc_msg(MANDOCERR_BADCHAR, curp,
curp->line, pos, NULL);
i++;
if (pos >= (int)ln.sz)
resize_buf(&ln, 256);
ln.buf[pos++] = '?';
continue;
}
/* Expand registers inline */
if ('\\' == blk.buf[i] && 'n' == blk.buf[i + 1]) {
roff_expand_nr(curp->roff,
blk.buf, &i, blk.sz, &ln.buf, &pos, &ln.sz);
continue;
}
/* Trailing backslash = a plain char. */
if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
if (pos >= (int)ln.sz)
resize_buf(&ln, 256);
ln.buf[pos++] = blk.buf[i++];
continue;
}
/*
* Found escape and at least one other character.
* When it's a newline character, skip it.
@ -395,10 +407,20 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
break;
}
/* Some other escape sequence, copy & cont. */
/* Catch escaped bogus characters. */
if (pos + 1 >= (int)ln.sz)
resize_buf(&ln, 256);
c = (unsigned char) blk.buf[i+1];
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
mandoc_msg(MANDOCERR_BADCHAR, curp,
curp->line, pos, NULL);
i += 2;
ln.buf[pos++] = '?';
continue;
}
/* Some other escape sequence, copy & cont. */
ln.buf[pos++] = blk.buf[i++];
ln.buf[pos++] = blk.buf[i++];
@ -474,7 +496,7 @@ rerun:
*/
if (curp->secondary)
curp->secondary->sz -= pos + 1;
mparse_readfd_r(curp, -1, ln.buf + of, 1);
mparse_readfd(curp, -1, ln.buf + of);
if (MANDOCLEVEL_FATAL <= curp->file_status)
break;
pos = 0;
@ -554,7 +576,8 @@ rerun:
}
static int
read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
read_whole_file(struct mparse *curp, const char *file, int fd,
struct buf *fb, int *with_mmap)
{
size_t off;
ssize_t ssz;
@ -562,7 +585,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
#ifdef HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
perror(file);
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
file, 0, 0, strerror(errno));
return(0);
}
@ -575,13 +601,15 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
fprintf(stderr, "%s: input too large\n", file);
curp->file_status = MANDOCLEVEL_FATAL;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_TOOLARGE,
curp->file_status, file, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
fb->sz = (size_t)st.st_size;
fb->buf = mmap(NULL, fb->sz, PROT_READ,
MAP_FILE|MAP_SHARED, fd, 0);
fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
if (fb->buf != MAP_FAILED)
return(1);
}
@ -599,7 +627,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
fprintf(stderr, "%s: input too large\n", file);
curp->file_status = MANDOCLEVEL_FATAL;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_TOOLARGE,
curp->file_status,
file, 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@ -610,7 +642,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
return(1);
}
if (ssz == -1) {
perror(file);
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_SYSREAD,
curp->file_status, file, 0, 0,
strerror(errno));
break;
}
off += (size_t)ssz;
@ -648,19 +684,25 @@ mparse_end(struct mparse *curp)
}
static void
mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file,
int re)
mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
{
const char *svfile;
static int recursion_depth;
if (64 < recursion_depth) {
mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
return;
}
/* Line number is per-file. */
svfile = curp->file;
curp->file = file;
curp->line = 1;
recursion_depth++;
mparse_buf_r(curp, blk, 1);
if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
mparse_end(curp);
curp->file = svfile;
@ -675,22 +717,25 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len,
blk.buf = UNCONST(buf);
blk.sz = len;
mparse_parse_buffer(curp, blk, file, 0);
mparse_parse_buffer(curp, blk, file);
return(curp->file_status);
}
static void
mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
if (-1 == fd)
if (-1 == (fd = open(file, O_RDONLY, 0))) {
perror(file);
curp->file_status = MANDOCLEVEL_SYSERR;
return;
}
if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_SYSOPEN,
curp->file_status,
file, 0, 0, strerror(errno));
goto out;
}
/*
* Run for each opened file; may be called more than once for
* each full parse sequence if the opened file is nested (i.e.,
@ -698,12 +743,10 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
* the parse phase for the file.
*/
if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
curp->file_status = MANDOCLEVEL_SYSERR;
return;
}
if ( ! read_whole_file(curp, file, fd, &blk, &with_mmap))
goto out;
mparse_parse_buffer(curp, blk, file, re);
mparse_parse_buffer(curp, blk, file);
#ifdef HAVE_MMAP
if (with_mmap)
@ -714,18 +757,13 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
if (STDIN_FILENO != fd && -1 == close(fd))
perror(file);
}
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
mparse_readfd_r(curp, fd, file, 0);
out:
return(curp->file_status);
}
struct mparse *
mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg)
mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
mandocmsg mmsg, void *arg, char *defos)
{
struct mparse *curp;
@ -737,8 +775,9 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void
curp->mmsg = mmsg;
curp->arg = arg;
curp->inttype = inttype;
curp->defos = defos;
curp->roff = roff_alloc(curp);
curp->roff = roff_alloc(inttype, curp);
return(curp);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: st.in,v 1.19 2012/02/26 21:47:09 schwarze Exp $ */
/* Id: st.in,v 1.23 2013/12/31 23:29:41 schwarze Exp */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -34,18 +34,21 @@ LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2013", "IEEE Std 1003.1-2008/Cor 1-2013 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
LINE("-p1003.1d-99", "IEEE Std 1003.1d-1999 (\\(lqPOSIX.1d\\(rq)")
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
LINE("-p1003.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1j\\(rq)")
LINE("-p1003.1q-2000", "IEEE Std 1003.1q-2000 (\\(lqPOSIX.1q\\(rq)")
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)")
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)")
LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)")
LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
@ -69,11 +72,12 @@ LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\
LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(rq)")
LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)")
LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
LINE("-susv2", "Version\\~2 of the Single UNIX Specification")
LINE("-susv3", "Version\\~3 of the Single UNIX Specification")
LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: tbl.c,v 1.26 2011/07/25 15:37:00 kristaps Exp $ */
/* Id: tbl.c,v 1.27 2013/05/31 22:08:09 schwarze Exp */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@ -72,21 +72,21 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
struct tbl_node *
tbl_alloc(int pos, int line, struct mparse *parse)
{
struct tbl_node *p;
struct tbl_node *tbl;
p = mandoc_calloc(1, sizeof(struct tbl_node));
p->line = line;
p->pos = pos;
p->parse = parse;
p->part = TBL_PART_OPTS;
p->opts.tab = '\t';
p->opts.linesize = 12;
p->opts.decimal = '.';
return(p);
tbl = mandoc_calloc(1, sizeof(struct tbl_node));
tbl->line = line;
tbl->pos = pos;
tbl->parse = parse;
tbl->part = TBL_PART_OPTS;
tbl->opts.tab = '\t';
tbl->opts.linesize = 12;
tbl->opts.decimal = '.';
return(tbl);
}
void
tbl_free(struct tbl_node *p)
tbl_free(struct tbl_node *tbl)
{
struct tbl_row *rp;
struct tbl_cell *cp;
@ -94,8 +94,8 @@ tbl_free(struct tbl_node *p)
struct tbl_dat *dp;
struct tbl_head *hp;
while (NULL != (rp = p->first_row)) {
p->first_row = rp->next;
while (NULL != (rp = tbl->first_row)) {
tbl->first_row = rp->next;
while (rp->first) {
cp = rp->first;
rp->first = cp->next;
@ -104,8 +104,8 @@ tbl_free(struct tbl_node *p)
free(rp);
}
while (NULL != (sp = p->first_span)) {
p->first_span = sp->next;
while (NULL != (sp = tbl->first_span)) {
tbl->first_span = sp->next;
while (sp->first) {
dp = sp->first;
sp->first = dp->next;
@ -116,12 +116,12 @@ tbl_free(struct tbl_node *p)
free(sp);
}
while (NULL != (hp = p->first_head)) {
p->first_head = hp->next;
while (NULL != (hp = tbl->first_head)) {
tbl->first_head = hp->next;
free(hp);
}
free(p);
free(tbl);
}
void

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */
/* Id: tbl_data.c,v 1.28 2014/01/05 18:37:53 joerg Exp */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@ -49,13 +49,11 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
cp = dp->layout->first;
/*
* Skip over spanners and vertical lines to data formats, since
* Skip over spanners, since
* we want to match data with data layout cells in the header.
*/
while (cp && (TBL_CELL_VERT == cp->pos ||
TBL_CELL_DVERT == cp->pos ||
TBL_CELL_SPAN == cp->pos))
while (cp && TBL_CELL_SPAN == cp->pos)
cp = cp->next;
/*
@ -104,7 +102,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
tbl->part = TBL_PART_CDATA;
return(0);
return(1);
}
assert(*pos - sv >= 0);
@ -187,7 +185,7 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
dp = mandoc_calloc(1, sizeof(struct tbl_span));
dp->line = line;
dp->tbl = &tbl->opts;
dp->opts = &tbl->opts;
dp->layout = rp;
dp->head = tbl->first_head;

View File

@ -1,6 +1,7 @@
/* $Vendor-Id: tbl_layout.c,v 1.22 2011/09/18 14:14:15 schwarze Exp $ */
/* Id: tbl_layout.c,v 1.23 2012/05/27 17:54:54 schwarze Exp */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012 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
@ -51,8 +52,7 @@ static const struct tbl_phrase keys[KEYS_MAX] = {
{ '^', TBL_CELL_DOWN },
{ '-', TBL_CELL_HORIZ },
{ '_', TBL_CELL_HORIZ },
{ '=', TBL_CELL_DHORIZ },
{ '|', TBL_CELL_VERT }
{ '=', TBL_CELL_DHORIZ }
};
static int mods(struct tbl_node *, struct tbl_cell *,
@ -60,10 +60,8 @@ static int mods(struct tbl_node *, struct tbl_cell *,
static int cell(struct tbl_node *, struct tbl_row *,
int, const char *, int *);
static void row(struct tbl_node *, int, const char *, int *);
static struct tbl_cell *cell_alloc(struct tbl_node *,
struct tbl_row *, enum tbl_cellt);
static void head_adjust(const struct tbl_cell *,
struct tbl_head *);
static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
enum tbl_cellt, int vert);
static int
mods(struct tbl_node *tbl, struct tbl_cell *cp,
@ -80,10 +78,6 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
case (TBL_CELL_HORIZ):
/* FALLTHROUGH */
case (TBL_CELL_DHORIZ):
/* FALLTHROUGH */
case (TBL_CELL_VERT):
/* FALLTHROUGH */
case (TBL_CELL_DVERT):
return(1);
default:
break;
@ -214,10 +208,17 @@ static int
cell(struct tbl_node *tbl, struct tbl_row *rp,
int ln, const char *p, int *pos)
{
int i;
int vert, i;
enum tbl_cellt c;
/* Parse the column position (`r', `R', `|', ...). */
/* Handle vertical lines. */
for (vert = 0; '|' == p[*pos]; ++*pos)
vert++;
while (' ' == p[*pos])
(*pos)++;
/* Parse the column position (`c', `l', `r', ...). */
for (i = 0; i < KEYS_MAX; i++)
if (tolower((unsigned char)p[*pos]) == keys[i].name)
@ -246,8 +247,6 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
return(0);
} else if (rp->last)
switch (rp->last->pos) {
case (TBL_CELL_VERT):
case (TBL_CELL_DVERT):
case (TBL_CELL_HORIZ):
case (TBL_CELL_DHORIZ):
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
@ -270,25 +269,16 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
(*pos)++;
/* Extra check for the double-vertical. */
if (TBL_CELL_VERT == c && '|' == p[*pos]) {
(*pos)++;
c = TBL_CELL_DVERT;
}
/* Disallow adjacent spacers. */
if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) &&
(TBL_CELL_VERT == rp->last->pos ||
TBL_CELL_DVERT == rp->last->pos)) {
if (vert > 2) {
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL);
return(0);
}
/* Allocate cell then parse its modifiers. */
return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos));
return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos));
}
@ -308,11 +298,11 @@ row: /*
*/
rp = mandoc_calloc(1, sizeof(struct tbl_row));
if (tbl->last_row) {
if (tbl->last_row)
tbl->last_row->next = rp;
tbl->last_row = rp;
} else
tbl->last_row = tbl->first_row = rp;
else
tbl->first_row = rp;
tbl->last_row = rp;
cell:
while (isspace((unsigned char)p[*pos]))
@ -357,7 +347,8 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p)
}
static struct tbl_cell *
cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos,
int vert)
{
struct tbl_cell *p, *pp;
struct tbl_head *h, *hp;
@ -365,108 +356,35 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
p = mandoc_calloc(1, sizeof(struct tbl_cell));
if (NULL != (pp = rp->last)) {
rp->last->next = p;
rp->last = p;
} else
rp->last = rp->first = p;
pp->next = p;
h = pp->head->next;
} else {
rp->first = p;
h = tbl->first_head;
}
rp->last = p;
p->pos = pos;
p->vert = vert;
/*
* This is a little bit complicated. Here we determine the
* header the corresponds to a cell. We add headers dynamically
* when need be or re-use them, otherwise. As an example, given
* the following:
*
* 1 c || l
* 2 | c | l
* 3 l l
* 3 || c | l |.
*
* We first add the new headers (as there are none) in (1); then
* in (2) we insert the first spanner (as it doesn't match up
* with the header); then we re-use the prior data headers,
* skipping over the spanners; then we re-use everything and add
* a last spanner. Note that VERT headers are made into DVERT
* ones.
*/
h = pp ? pp->head->next : tbl->first_head;
/* Re-use header. */
if (h) {
/* Re-use data header. */
if (TBL_HEAD_DATA == h->pos &&
(TBL_CELL_VERT != p->pos &&
TBL_CELL_DVERT != p->pos)) {
p->head = h;
return(p);
}
/* Re-use spanner header. */
if (TBL_HEAD_DATA != h->pos &&
(TBL_CELL_VERT == p->pos ||
TBL_CELL_DVERT == p->pos)) {
head_adjust(p, h);
p->head = h;
return(p);
}
/* Right-shift headers with a new spanner. */
if (TBL_HEAD_DATA == h->pos &&
(TBL_CELL_VERT == p->pos ||
TBL_CELL_DVERT == p->pos)) {
hp = mandoc_calloc(1, sizeof(struct tbl_head));
hp->ident = tbl->opts.cols++;
hp->prev = h->prev;
if (h->prev)
h->prev->next = hp;
if (h == tbl->first_head)
tbl->first_head = hp;
h->prev = hp;
hp->next = h;
head_adjust(p, hp);
p->head = hp;
return(p);
}
if (NULL != (h = h->next)) {
head_adjust(p, h);
p->head = h;
return(p);
}
/* Fall through to default case... */
p->head = h;
return(p);
}
hp = mandoc_calloc(1, sizeof(struct tbl_head));
hp->ident = tbl->opts.cols++;
hp->vert = vert;
if (tbl->last_head) {
hp->prev = tbl->last_head;
tbl->last_head->next = hp;
tbl->last_head = hp;
} else
tbl->last_head = tbl->first_head = hp;
tbl->first_head = hp;
tbl->last_head = hp;
head_adjust(p, hp);
p->head = hp;
return(p);
}
static void
head_adjust(const struct tbl_cell *cellp, struct tbl_head *head)
{
if (TBL_CELL_VERT != cellp->pos &&
TBL_CELL_DVERT != cellp->pos) {
head->pos = TBL_HEAD_DATA;
return;
}
if (TBL_CELL_VERT == cellp->pos)
if (TBL_HEAD_DVERT != head->pos)
head->pos = TBL_HEAD_VERT;
if (TBL_CELL_DVERT == cellp->pos)
head->pos = TBL_HEAD_DVERT;
}

View File

@ -1,4 +1,4 @@
/* $Vendor-Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp $ */
/* Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*

View File

@ -1,190 +0,0 @@
.\" $Vendor-Id: whatis.1,v 1.8 2012/03/24 01:54:43 kristaps Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd March 24, 2012
.Dt WHATIS 1
.Os
.Sh NAME
.Nm whatis
.Nd search for manual pages by page names
.Sh SYNOPSIS
.Nm
.Op Fl C Ar file
.Op Fl M Ar manpath
.Op Fl m Ar manpath
.Op Fl S Ar arch
.Op Fl s Ar section
.Ar name ...
.Sh DESCRIPTION
The
.Nm
utility searches databases generated by
.Xr mandocdb 8
for manuals containing the word
.Ar name
in their page name, ignoring case.
It returns the header lines from all matching pages.
You can then use the
.Xr man 1
command to get more information.
.Pp
By default,
.Nm
searches for
.Xr mandocdb 8
databases in the default paths stipulated by
.Xr man 1 .
If standard output is a TTY, a result may be selected from a list and
its manual displayed with the pager.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl C Ar file
Specify an alternative configuration
.Ar file
in
.Xr man.conf 5
format.
.It Fl M Ar manpath
Use the colon-separated
.Ar manpath
instead of the default list of paths searched for
.Xr mandocdb 8
databases.
Invalid paths, or paths without manual databases, are ignored.
.It Fl m Ar manpath
Prepend the colon-separated
.Ar manpath
to the list of paths searched for
.Xr mandocdb 8
databases.
Invalid paths, or paths without manual databases, are ignored.
.It Fl S Ar arch
Search only for a particular architecture.
.It Fl s Ar cat
Search only for a manual section.
See
.Xr man 1
for a listing of manual sections.
.El
.Pp
Results are sorted by manual title, with output formatted as
.Pp
.D1 title(sec) \- description
.Pp
Where
.Qq title
is the manual's title (note multiple manual names may exist for one
title),
.Qq sec
is the manual section, and
.Qq description
is the manual's short description.
If an architecture is specified for the manual, it is displayed as
.Pp
.D1 title(cat/arch) \- description
.Pp
If on a TTY, results are prefixed with a numeric identifier.
.Pp
.D1 [index] title(cat) \- description
.Pp
One may choose a manual be entering the index at the prompt.
Valid choices are displayed using
.Ev MANPAGER ,
or failing that ,
.Ev PAGER
or just
.Xr more 1 .
Source pages are formatted with
.Xr mandoc 1 ;
preformatted pages with
.Xr cat 1 .
.Pp
.Nm
is identical to running
.Xr apropos 1
as follows:
.Pp
.Dl $ apropos -- -i 'Nm~[[:<:]]term[[:>:]]'
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev MANPAGER
Default pager for manuals.
If this is unset, falls back to
.Ev Pager .
.It Ev PAGER
The second choice for a manual pager.
If this is unset, use
.Xr more 1 .
.It Ev MANPATH
Colon-separated paths modifying the default list of paths searched for
manual databases.
Invalid paths, or paths without manual databases, are ignored.
Overridden by
.Fl M .
If
.Ev MANPATH
begins with a
.Sq \&: ,
it is appended to the default list;
else if it ends with
.Sq \&: ,
it is prepended to the default list; else if it contains
.Sq \&:: ,
the default list is inserted between the colons.
If none of these conditions are met, it overrides the default list.
.El
.Sh FILES
.Bl -tag -width "/etc/man.conf" -compact
.It Pa whatis.db
name of the
.Xr mandocdb 8
keyword database
.It Pa whatis.index
name of the
.Xr mandocdb 8
filename database
.It Pa /etc/man.conf
default
.Xr man 1
configuration file
.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr man 1 ,
.Xr man.conf 5 ,
.Xr mandocdb 8
.Sh HISTORY
The
.Nm
utility first appeared in
.Bx 2 .
It was rewritten from scratch as part of the
.Xr mandocdb 8
project for
.Ox 5.1 .
.Sh AUTHORS
.An -nosplit
.An Bill Joy
wrote the original
.Bx
.Nm
in 1979.
The current version was written by
.An Kristaps Dzonsons ,
.Mt kristaps@bsd.lv .