-/* $Id: mdoc_macro.c,v 1.150 2014/11/28 03:14:18 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.161 2014/12/22 23:27:32 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
REWIND_ERROR
};
-static int blk_full(MACRO_PROT_ARGS);
-static int blk_exp_close(MACRO_PROT_ARGS);
-static int blk_part_exp(MACRO_PROT_ARGS);
-static int blk_part_imp(MACRO_PROT_ARGS);
-static int ctx_synopsis(MACRO_PROT_ARGS);
-static int in_line_eoln(MACRO_PROT_ARGS);
-static int in_line_argn(MACRO_PROT_ARGS);
-static int in_line(MACRO_PROT_ARGS);
-static int phrase_ta(MACRO_PROT_ARGS);
+static void blk_full(MACRO_PROT_ARGS);
+static void blk_exp_close(MACRO_PROT_ARGS);
+static void blk_part_exp(MACRO_PROT_ARGS);
+static void blk_part_imp(MACRO_PROT_ARGS);
+static void ctx_synopsis(MACRO_PROT_ARGS);
+static void in_line_eoln(MACRO_PROT_ARGS);
+static void in_line_argn(MACRO_PROT_ARGS);
+static void in_line(MACRO_PROT_ARGS);
+static void phrase_ta(MACRO_PROT_ARGS);
static void dword(struct mdoc *, int, int, const char *,
enum mdelim, int);
static void append_delims(struct mdoc *, int, int *, char *);
-static enum mdoct lookup(enum mdoct, const char *);
-static enum mdoct lookup_raw(const char *);
+static enum mdoct lookup(struct mdoc *, enum mdoct,
+ int, int, const char *);
+static int macro_or_word(MACRO_PROT_ARGS, int);
static int make_pending(struct mdoc_node *, enum mdoct,
struct mdoc *, int, int);
-static int phrase(struct mdoc *, int, int, char *);
+static int parse_rest(struct mdoc *, enum mdoct,
+ int, int *, char *);
static enum mdoct rew_alt(enum mdoct);
static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
const struct mdoc_node *);
* closing out open [implicit] scopes. Obviously, open explicit scopes
* are errors.
*/
-int
+void
mdoc_macroend(struct mdoc *mdoc)
{
struct mdoc_node *n;
/* Scan for open explicit scopes. */
- n = MDOC_VALID & mdoc->last->flags ?
+ n = mdoc->last->flags & MDOC_VALID ?
mdoc->last->parent : mdoc->last;
for ( ; n; n = n->parent)
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags)
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
/* Rewind to the first. */
rew_last(mdoc, mdoc->first);
- return(1);
-}
-
-/*
- * Look up a macro from within a subsequent context.
- */
-static enum mdoct
-lookup(enum mdoct from, const char *p)
-{
-
- if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
- return(MDOC_MAX);
- return(lookup_raw(p));
}
/*
- * Lookup a macro following the initial line macro.
+ * Look up the macro at *p called by "from",
+ * or as a line macro if from == MDOC_MAX.
*/
static enum mdoct
-lookup_raw(const char *p)
+lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p)
{
enum mdoct res;
- if (MDOC_MAX == (res = mdoc_hash_find(p)))
- return(MDOC_MAX);
- if (MDOC_CALLABLE & mdoc_macros[res].flags)
- return(res);
+ if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) {
+ res = mdoc_hash_find(p);
+ if (res != MDOC_MAX) {
+ if (mdoc_macros[res].flags & MDOC_CALLABLE)
+ return(res);
+ if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll)
+ mandoc_msg(MANDOCERR_MACRO_CALL,
+ mdoc->parse, line, ppos, p);
+ }
+ }
return(MDOC_MAX);
}
* When starting to rewind, skip plain text
* and nodes that have already been rewound.
*/
- if (MDOC_TEXT == p->type || MDOC_VALID & p->flags)
+ if (p->type == MDOC_TEXT || p->flags & (MDOC_VALID | MDOC_BREAK))
return(REWIND_MORE);
/*
for (breaker = broken->parent; breaker; breaker = breaker->parent) {
/*
- * If the *broken block had already been broken before
- * and we encounter its breaker, make the tok block
- * pending on the inner breaker.
- * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]"
- * becomes "[A broken=[B [C->B B] tok=A] C]"
- * and finally "[A [B->A [C->B B] A] C]".
+ * If the *broken block (Z) is already broken and we
+ * encounter its breaker (B), make the tok block (A)
+ * pending on that inner breaker (B).
+ * Graphically, [A breaker=[B! broken=[Z->B B] tok=A] Z]
+ * becomes breaker=[A broken=[B! [Z->B B] tok=A] Z]
+ * and finally [A! [B!->A [Z->B B] A] Z].
+ * In these graphics, "->" indicates the "pending"
+ * pointer and "!" indicates the MDOC_BREAK flag.
+ * Each of the cases gets one additional pointer (B->A)
+ * and one additional flag (A!).
*/
if (breaker == broken->pending) {
broken = breaker;
/*
* Found the breaker.
- * If another, outer breaker is already pending on
- * the *broken block, we must not clobber the link
+ * If another, outer breaker (X) is already pending on
+ * the *broken block (B), we must not clobber the link
* to the outer breaker, but make it pending on the
- * new, now inner breaker.
- * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]"
- * becomes "[A breaker=[B->A broken=[C A] tok=B] C]"
- * and finally "[A [B->A [C->B A] B] C]".
+ * new, now inner breaker (A).
+ * Graphically, [X! breaker=[A broken=[B->X X] tok=A] B]
+ * becomes [X! breaker=[A->X broken=[B X] tok=A] B]
+ * and finally [X! [A!->X [B->A X] A] B].
*/
if (broken->pending) {
struct mdoc_node *taker;
/*
- * If the breaker had also been broken before,
- * it cannot take on the outer breaker itself,
- * but must hand it on to its own breakers.
- * Graphically, this is the following situation:
- * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]"
- * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]"
+ * If the inner breaker (A) is already broken,
+ * too, it cannot take on the outer breaker (X)
+ * but must hand it on to its own breakers (Y):
+ * [X! [Y! breaker=[A->Y Y] broken=[B->X X] tok=A] B]
+ * [X! take=[Y!->X brea=[A->Y Y] brok=[B X] tok=A] B]
+ * and finally [X! [Y!->X [A!->Y Y] [B->A X] A] B].
*/
taker = breaker;
while (taker->pending)
taker = taker->pending;
taker->pending = broken->pending;
}
+
+ /*
+ * Now we have reduced the situation to the simplest
+ * case, which is just breaker=[A broken=[B tok=A] B]
+ * and becomes [A! [B->A A] B].
+ */
broken->pending = breaker;
+ breaker->flags |= MDOC_BREAK;
mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos,
"%s breaks %s", mdoc_macronames[tok],
mdoc_macronames[broken->tok]);
rew_sub(enum mdoc_type t, struct mdoc *mdoc,
enum mdoct tok, int line, int ppos)
{
- struct mdoc_node *n;
+ struct mdoc_node *n, *to;
+ to = NULL;
n = mdoc->last;
while (n) {
switch (rew_dohalt(tok, t, n)) {
case REWIND_NONE:
- return;
+ if (to == NULL)
+ return;
+ n = to;
+ break;
case REWIND_THIS:
n->lastline = line -
(mdoc->flags & MDOC_NEWLINE &&
case REWIND_MORE:
n->lastline = line -
(mdoc->flags & MDOC_NEWLINE ? 1 : 0);
+ to = n;
n = n->parent;
continue;
case REWIND_LATER:
static void
append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
{
- int la;
- enum margserr ac;
char *p;
+ int la;
if (buf[*pos] == '\0')
return;
for (;;) {
la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
- if (ac == ARGS_EOLN)
+ if (mdoc_args(mdoc, line, pos, buf, MDOC_MAX, &p) == ARGS_EOLN)
break;
dword(mdoc, line, la, p, DELIM_MAX, 1);
}
/*
- * Close out block partial/full explicit.
+ * Parse one word.
+ * If it is a macro, call it and return 1.
+ * Otherwise, allocate it and return 0.
*/
static int
+macro_or_word(MACRO_PROT_ARGS, int parsed)
+{
+ char *p;
+ enum mdoct ntok;
+
+ p = buf + ppos;
+ ntok = MDOC_MAX;
+ if (*p == '"')
+ p++;
+ else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
+ ntok = lookup(mdoc, tok, line, ppos, p);
+
+ if (ntok == MDOC_MAX) {
+ dword(mdoc, line, ppos, p, DELIM_MAX, tok == MDOC_MAX ||
+ mdoc_macros[tok].flags & MDOC_JOIN);
+ return(0);
+ } else {
+ if (mdoc_macros[tok].fp == in_line_eoln)
+ rew_elem(mdoc, tok);
+ mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
+ if (tok == MDOC_MAX)
+ append_delims(mdoc, line, pos, buf);
+ return(1);
+ }
+}
+
+/*
+ * Close out block partial/full explicit.
+ */
+static void
blk_exp_close(MACRO_PROT_ARGS)
{
struct mdoc_node *body; /* Our own body. */
struct mdoc_node *later; /* A sub-block starting later. */
struct mdoc_node *n; /* For searching backwards. */
- int j, lastarg, maxargs, flushed, nl;
+ int flushed, have_it, j, lastarg, maxargs, nl;
enum margserr ac;
enum mdoct atok, ntok;
char *p;
break;
case MDOC_Ek:
mdoc->flags &= ~MDOC_KEEP;
+ /* FALLTHROUGH */
default:
maxargs = 0;
break;
* Search backwards for beginnings of blocks,
* both of our own and of pending sub-blocks.
*/
+
+ have_it = 0;
atok = rew_alt(tok);
body = endbody = later = NULL;
for (n = mdoc->last; n; n = n->parent) {
- if (n->flags & MDOC_VALID)
+ if (n->flags & (MDOC_VALID | MDOC_BREAK))
continue;
/* Remember the start of our own body. */
+
if (n->type == MDOC_BODY && atok == n->tok) {
if (n->end == ENDBODY_NOT)
body = n;
if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm)
continue;
+
+ if (n->tok == MDOC_It) {
+ have_it = 1;
+ continue;
+ }
+
if (atok == n->tok) {
assert(body);
* When there is no pending sub block,
* just proceed to closing out.
*/
- if (later == NULL)
+
+ if (later == NULL ||
+ (tok == MDOC_El && !have_it))
break;
/*
* postpone closing out the current block
* until the rew_sub() closing out the sub-block.
*/
+
make_pending(later, tok, mdoc, line, ppos);
/*
* Mark the place where the formatting - but not
* the scope - of the current block ends.
*/
+
mdoc_endbody_alloc(mdoc, line, ppos,
atok, body, ENDBODY_SPACE);
+
+ /*
+ * If a block closing macro taking arguments
+ * breaks another block, put the arguments
+ * into the end marker and remeber the
+ * end marker in order to close it out.
+ */
+
if (maxargs) {
endbody = mdoc->last;
mdoc->next = MDOC_NEXT_CHILD;
* open explicit block, or, in case there are only
* implicit ones, the first open implicit block.
*/
- if (later &&
- mdoc_macros[later->tok].flags & MDOC_EXPLICIT)
- continue;
- if (n->tok != MDOC_It)
+
+ if (later == NULL ||
+ ! (mdoc_macros[later->tok].flags & MDOC_EXPLICIT))
later = n;
}
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
if (buf[*pos] != '\0')
mdoc->parse, line, ppos,
"%s %s", mdoc_macronames[tok],
buf + *pos);
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
- return(1);
+ return;
}
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
if (maxargs && endbody == NULL) {
if (n == NULL) {
if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
+ ntok = ac == ARGS_QWORD ? MDOC_MAX :
+ lookup(mdoc, tok, line, lastarg, p);
if (ntok == MDOC_MAX) {
dword(mdoc, line, lastarg, p, DELIM_MAX,
rew_last(mdoc, endbody);
flushed = 1;
}
-
mdoc->flags &= ~MDOC_NEWLINE;
-
- if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
break;
}
}
if (nl)
append_delims(mdoc, line, pos, buf);
- return(1);
}
-static int
+static void
in_line(MACRO_PROT_ARGS)
{
int la, scope, cnt, firstarg, mayopen, nc, nl;
- enum margverr av;
enum mdoct ntok;
enum margserr ac;
enum mdelim d;
break;
}
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
d = DELIM_NONE;
firstarg = 1;
}
ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
- MDOC_MAX : lookup(tok, p);
+ MDOC_MAX : lookup(mdoc, tok, line, la, p);
/*
* In this case, we've located a submacro and must
mdoc->parse, line, ppos,
mdoc_macronames[tok]);
}
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
if (nl)
append_delims(mdoc, line, pos, buf);
- return(1);
+ return;
}
/*
}
if (nl)
append_delims(mdoc, line, pos, buf);
- return(1);
}
-static int
+static void
blk_full(MACRO_PROT_ARGS)
{
- int la, nl, nparsed;
+ int la, nl, parsed;
struct mdoc_arg *arg;
struct mdoc_node *head; /* save of head macro */
struct mdoc_node *body; /* save of body macro */
struct mdoc_node *n;
- enum mdoct ntok;
enum margserr ac, lac;
- enum margverr av;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
if (tok == MDOC_It) {
for (n = mdoc->last; n; n = n->parent)
- if (n->tok == MDOC_Bl &&
- ! (n->flags & MDOC_VALID))
+ if (n->tok == MDOC_Bl && n->type == MDOC_BLOCK &&
+ ! (n->flags & (MDOC_VALID | MDOC_BREAK)))
break;
if (n == NULL) {
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
line, ppos, "It %s", buf + *pos);
mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
rew_elem(mdoc, MDOC_br);
- return(1);
+ return;
}
}
* regular child nodes.
*/
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
-
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
-
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
mdoc_block_alloc(mdoc, line, ppos, tok, arg);
head = body = NULL;
* Exception: Heads of `It' macros in `-diag' lists are not
* parsed, even though `It' macros in general are parsed.
*/
- nparsed = tok == MDOC_It &&
- mdoc->last->parent->tok == MDOC_Bl &&
- mdoc->last->parent->norm->Bl.type == LIST_diag;
+
+ parsed = tok != MDOC_It ||
+ mdoc->last->parent->tok != MDOC_Bl ||
+ mdoc->last->parent->norm->Bl.type != LIST_diag;
/*
* The `Nd' macro has all arguments in its body: it's a hybrid
if (ac == ARGS_PHRASE ||
ac == ARGS_PEND ||
ac == ARGS_PPHRASE) {
+
/*
* If we haven't opened a body yet, rewind the
* head; if we have, rewind that instead.
rew_sub(body ? MDOC_BODY : MDOC_HEAD,
mdoc, tok, line, ppos);
-
- /* Then allocate our body context. */
-
body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
mdoc->flags |= MDOC_PPHRASE;
if (ac == ARGS_PEND && lac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
-
- if ( ! phrase(mdoc, line, la, buf))
- return(0);
-
+ parse_rest(mdoc, MDOC_MAX, line, &la, buf);
mdoc->flags &= ~MDOC_PPHRASE;
continue;
}
- ntok = nparsed || ac == ARGS_QWORD ?
- MDOC_MAX : lookup(tok, p);
-
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
+ break;
}
if (head == NULL)
head = mdoc_head_alloc(mdoc, line, ppos, tok);
if (nl)
append_delims(mdoc, line, pos, buf);
-
- /* If we've already opened our body, exit now. */
-
- if (NULL != body)
+ if (body != NULL)
goto out;
/*
* sub-block.
*/
for (n = mdoc->last; n && n != head; n = n->parent) {
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
- ! (MDOC_VALID & n->flags)) {
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT &&
+ ! (n->flags & MDOC_VALID)) {
n->pending = head;
- return(1);
+ return;
}
}
rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
mdoc_body_alloc(mdoc, line, ppos, tok);
-
out:
if (mdoc->flags & MDOC_FREECOL) {
rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
mdoc->flags &= ~MDOC_FREECOL;
}
- return(1);
}
-static int
+static void
blk_part_imp(MACRO_PROT_ARGS)
{
int la, nl;
- enum mdoct ntok;
enum margserr ac;
char *p;
struct mdoc_node *blk; /* saved block context */
if (body == NULL)
body = mdoc_body_alloc(mdoc, line, ppos, tok);
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
-
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
-
- /* Clean-ups to leave in a consistent state. */
-
if (body == NULL)
body = mdoc_body_alloc(mdoc, line, ppos, tok);
* postpone closing out the current block
* until the rew_sub() call closing out the sub-block.
*/
+
for (n = mdoc->last; n && n != body && n != blk->parent;
n = n->parent) {
if (n->type == MDOC_BLOCK &&
make_pending(n, tok, mdoc, line, ppos);
mdoc_endbody_alloc(mdoc, line, ppos,
tok, body, ENDBODY_NOSPACE);
- return(1);
+ return;
}
}
assert(n == body);
rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
-
- /* Standard appending of delimiters. */
-
if (nl)
append_delims(mdoc, line, pos, buf);
-
- /* Rewind scope, if applicable. */
-
rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
/* Move trailing .Ns out of scope. */
/* Do nothing. */ ;
if (n && n->tok == MDOC_Ns)
mdoc_node_relink(mdoc, n);
-
- return(1);
}
-static int
+static void
blk_part_exp(MACRO_PROT_ARGS)
{
int la, nl;
struct mdoc_node *head; /* keep track of head */
struct mdoc_node *body; /* keep track of body */
char *p;
- enum mdoct ntok;
nl = MDOC_NEWLINE & mdoc->flags;
}
assert(head != NULL && body != NULL);
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
- continue;
- }
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
/* Clean-up to leave in a consistent state. */
rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
mdoc_body_alloc(mdoc, line, ppos, tok);
}
-
- /* Standard appending of delimiters. */
-
if (nl)
append_delims(mdoc, line, pos, buf);
- return(1);
}
-static int
+static void
in_line_argn(MACRO_PROT_ARGS)
{
int la, flushed, j, maxargs, nl;
enum margserr ac;
- enum margverr av;
struct mdoc_arg *arg;
char *p;
enum mdoct ntok;
- nl = MDOC_NEWLINE & mdoc->flags;
+ nl = mdoc->flags & MDOC_NEWLINE;
/*
* A line macro that has a fixed number of arguments (maxargs).
break;
}
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
-
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
- for (flushed = j = 0; ; ) {
+ p = NULL;
+ flushed = j = 0;
+ for (;;) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
+ if (j < 2 && tok == MDOC_Pf)
+ mandoc_vmsg(MANDOCERR_PF_SKIP,
+ mdoc->parse, line, ppos, "Pf %s",
+ p == NULL ? "at eol" : p);
break;
+ }
if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
ac != ARGS_QWORD && j == 0 &&
flushed = 1;
}
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
+ ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && j == 0)) ?
+ MDOC_MAX : lookup(mdoc, tok, line, la, p);
if (ntok != MDOC_MAX) {
if ( ! flushed)
rew_elem(mdoc, tok);
flushed = 1;
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
j++;
break;
}
j++;
}
- if (j == 0)
+ if (j == 0) {
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-
- /* Close out in a consistent state. */
-
+ if (ac == ARGS_PUNCT && tok == MDOC_Pf)
+ append_delims(mdoc, line, pos, buf);
+ }
if ( ! flushed)
rew_elem(mdoc, tok);
if (nl)
append_delims(mdoc, line, pos, buf);
- return(1);
}
-static int
+static void
in_line_eoln(MACRO_PROT_ARGS)
{
- int la;
- enum margserr ac;
- enum margverr av;
struct mdoc_arg *arg;
- char *p;
- enum mdoct ntok;
-
- assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
if (tok == MDOC_Pp)
rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos);
- /* Parse macro arguments. */
-
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
-
- /* Open element scope. */
-
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ if (parse_rest(mdoc, tok, line, pos, buf))
+ return;
+ rew_elem(mdoc, tok);
+}
- /* Parse argument terms. */
+/*
+ * The simplest argument parser available: Parse the remaining
+ * words until the end of the phrase or line and return 0
+ * or until the next macro, call that macro, and return 1.
+ */
+static int
+parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf)
+{
+ int la;
for (;;) {
la = *pos;
- ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ac == ARGS_EOLN)
- break;
-
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
-
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
- continue;
- }
- rew_elem(mdoc, tok);
- return(mdoc_macro(mdoc, ntok, line, la, pos, buf));
+ if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
+ return(0);
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ return(1);
}
-
- /* Close out (no delimiters). */
-
- rew_elem(mdoc, tok);
- return(1);
}
-static int
+static void
ctx_synopsis(MACRO_PROT_ARGS)
{
- int nl;
-
- nl = MDOC_NEWLINE & mdoc->flags;
- /* If we're not in the SYNOPSIS, go straight to in-line. */
- if ( ! (MDOC_SYNOPSIS & mdoc->flags))
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /* If we're a nested call, same place. */
- if ( ! nl)
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /*
- * XXX: this will open a block scope; however, if later we end
- * up formatting the block scope, then child nodes will inherit
- * the formatting. Be careful.
- */
- if (MDOC_Nm == tok)
- return(blk_full(mdoc, tok, line, ppos, pos, buf));
- assert(MDOC_Vt == tok);
- return(blk_part_imp(mdoc, tok, line, ppos, pos, buf));
+ if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
+ in_line(mdoc, tok, line, ppos, pos, buf);
+ else if (tok == MDOC_Nm)
+ blk_full(mdoc, tok, line, ppos, pos, buf);
+ else {
+ assert(tok == MDOC_Vt);
+ blk_part_imp(mdoc, tok, line, ppos, pos, buf);
+ }
}
/*
* They're unusual because they're basically free-form text until a
* macro is encountered.
*/
-static int
-phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
-{
- int la, pos;
- enum margserr ac;
- enum mdoct ntok;
- char *p;
-
- for (pos = ppos; ; ) {
- la = pos;
-
- ac = mdoc_zargs(mdoc, line, &pos, buf, &p);
- if (ac == ARGS_EOLN)
- break;
-
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup_raw(p);
-
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX, 1);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf))
- return(0);
- append_delims(mdoc, line, &pos, buf);
- return(1);
- }
-
- return(1);
-}
-
-static int
+static void
phrase_ta(MACRO_PROT_ARGS)
{
struct mdoc_node *n;
- int la;
- enum mdoct ntok;
- enum margserr ac;
- char *p;
/* Make sure we are in a column list or ignore this macro. */
+
n = mdoc->last;
- while (NULL != n && MDOC_Bl != n->tok)
+ while (n != NULL &&
+ (n->tok != MDOC_Bl || n->flags & (MDOC_VALID | MDOC_BREAK)))
n = n->parent;
- if (NULL == n || LIST_column != n->norm->Bl.type) {
+ if (n == NULL || n->norm->Bl.type != LIST_column) {
mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
line, ppos, "Ta");
- return(1);
+ return;
}
/* Advance to the next column. */
rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos);
mdoc_body_alloc(mdoc, line, ppos, MDOC_It);
-
- for (;;) {
- la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
- if (ac == ARGS_EOLN)
- break;
-
- ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup_raw(p);
-
- if (ntok == MDOC_MAX) {
- dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- append_delims(mdoc, line, pos, buf);
- return(1);
- }
-
- return(1);
+ parse_rest(mdoc, MDOC_MAX, line, pos, buf);
}