Print this page
Update to 1.12.3.

*** 1,8 **** ! /* $Id: man_macro.c,v 1.71 2012/01/03 15:16:24 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 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. * --- 1,10 ---- ! /* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 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 * copyright notice and this permission notice appear in all copies. *
*** 75,102 **** { in_line_eoln, MAN_NSCOPED }, /* na */ { in_line_eoln, MAN_NSCOPED }, /* sp */ { in_line_eoln, MAN_BSCOPE }, /* nf */ { in_line_eoln, MAN_BSCOPE }, /* fi */ { blk_close, 0 }, /* RE */ ! { blk_exp, MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ { in_line_eoln, 0 }, /* AT */ { in_line_eoln, 0 }, /* in */ { in_line_eoln, 0 }, /* ft */ { in_line_eoln, 0 }, /* OP */ }; const struct man_macro * const man_macros = __man_macros; /* * Warn when "n" is an explicit non-roff macro. */ static void ! rew_warn(struct man *m, struct man_node *n, enum mandocerr er) { if (er == MANDOCERR_MAX || MAN_BLOCK != n->type) return; if (MAN_VALID & n->flags) --- 77,108 ---- { in_line_eoln, MAN_NSCOPED }, /* na */ { in_line_eoln, MAN_NSCOPED }, /* sp */ { in_line_eoln, MAN_BSCOPE }, /* nf */ { in_line_eoln, MAN_BSCOPE }, /* fi */ { blk_close, 0 }, /* RE */ ! { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ { in_line_eoln, 0 }, /* AT */ { in_line_eoln, 0 }, /* in */ { in_line_eoln, 0 }, /* ft */ { in_line_eoln, 0 }, /* OP */ + { in_line_eoln, MAN_BSCOPE }, /* EX */ + { in_line_eoln, MAN_BSCOPE }, /* EE */ + { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */ + { blk_close, 0 }, /* UE */ }; const struct man_macro * const man_macros = __man_macros; /* * Warn when "n" is an explicit non-roff macro. */ static void ! rew_warn(struct man *man, struct man_node *n, enum mandocerr er) { if (er == MANDOCERR_MAX || MAN_BLOCK != n->type) return; if (MAN_VALID & n->flags)
*** 103,148 **** return; if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) return; assert(er < MANDOCERR_FATAL); ! man_nmsg(m, n, er); } /* * Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it * will be used if an explicit block scope is being closed out. */ int ! man_unscope(struct man *m, const struct man_node *to, enum mandocerr er) { struct man_node *n; assert(to); ! m->next = MAN_NEXT_SIBLING; /* LINTED */ ! while (m->last != to) { /* * Save the parent here, because we may delete the ! * m->last node in the post-validation phase and reset ! * it to m->last->parent, causing a step in the closing * out to be lost. */ ! n = m->last->parent; ! rew_warn(m, m->last, er); ! if ( ! man_valid_post(m)) return(0); ! m->last = n; ! assert(m->last); } ! rew_warn(m, m->last, er); ! if ( ! man_valid_post(m)) return(0); return(1); } --- 109,154 ---- return; if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) return; assert(er < MANDOCERR_FATAL); ! man_nmsg(man, n, er); } /* * Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it * will be used if an explicit block scope is being closed out. */ int ! man_unscope(struct man *man, const struct man_node *to, enum mandocerr er) { struct man_node *n; assert(to); ! man->next = MAN_NEXT_SIBLING; /* LINTED */ ! while (man->last != to) { /* * Save the parent here, because we may delete the ! * man->last node in the post-validation phase and reset ! * it to man->last->parent, causing a step in the closing * out to be lost. */ ! n = man->last->parent; ! rew_warn(man, man->last, er); ! if ( ! man_valid_post(man)) return(0); ! man->last = n; ! assert(man->last); } ! rew_warn(man, man->last, er); ! if ( ! man_valid_post(man)) return(0); return(1); }
*** 181,192 **** /* Already-validated nodes should be closed out. */ if (MAN_VALID & n->flags) return(REW_NOHALT); /* First: rewind to ourselves. */ ! if (type == n->type && tok == n->tok) return(REW_REWIND); /* * Next follow the implicit scope-smashings as defined by man.7: * section, sub-section, etc. */ --- 187,202 ---- /* Already-validated nodes should be closed out. */ if (MAN_VALID & n->flags) return(REW_NOHALT); /* First: rewind to ourselves. */ ! if (type == n->type && tok == n->tok) { ! if (MAN_EXPLICIT & man_macros[n->tok].flags) ! return(REW_HALT); ! else return(REW_REWIND); + } /* * Next follow the implicit scope-smashings as defined by man.7: * section, sub-section, etc. */
*** 198,207 **** --- 208,221 ---- /* Rewind to a section, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) return(c); break; case (MAN_RS): + /* Preserve empty paragraphs before RS. */ + if (0 == n->nchild && (MAN_P == n->tok || + MAN_PP == n->tok || MAN_LP == n->tok)) + return(REW_HALT); /* Rewind to a subsection, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) return(c); /* Rewind to a section, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
*** 228,244 **** * Rewinding entails ascending the parse tree until a coherent point, * for example, the `SH' macro will close out any intervening `SS' * scopes. When a scope is closed, it must be validated and actioned. */ static int ! rew_scope(enum man_type type, struct man *m, enum mant tok) { struct man_node *n; enum rew c; /* LINTED */ ! for (n = m->last; n; n = n->parent) { /* * Whether we should stop immediately (REW_HALT), stop * and rewind until this point (REW_REWIND), or keep * rewinding (REW_NOHALT). */ --- 242,258 ---- * Rewinding entails ascending the parse tree until a coherent point, * for example, the `SH' macro will close out any intervening `SS' * scopes. When a scope is closed, it must be validated and actioned. */ static int ! rew_scope(enum man_type type, struct man *man, enum mant tok) { struct man_node *n; enum rew c; /* LINTED */ ! for (n = man->last; n; n = n->parent) { /* * Whether we should stop immediately (REW_HALT), stop * and rewind until this point (REW_REWIND), or keep * rewinding (REW_NOHALT). */
*** 253,263 **** * Rewind until the current point. Warn if we're a roff * instruction that's mowing over explicit scopes. */ assert(n); ! return(man_unscope(m, n, MANDOCERR_MAX)); } /* * Close out a generic explicit macro. --- 267,277 ---- * Rewind until the current point. Warn if we're a roff * instruction that's mowing over explicit scopes. */ assert(n); ! return(man_unscope(man, n, MANDOCERR_MAX)); } /* * Close out a generic explicit macro.
*** 271,333 **** switch (tok) { case (MAN_RE): ntok = MAN_RS; break; default: abort(); /* NOTREACHED */ } ! for (nn = m->last->parent; nn; nn = nn->parent) ! if (ntok == nn->tok) break; ! if (NULL == nn) ! man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); ! ! if ( ! rew_scope(MAN_BODY, m, ntok)) return(0); ! if ( ! rew_scope(MAN_BLOCK, m, ntok)) ! return(0); return(1); } /* ARGSUSED */ int blk_exp(MACRO_PROT_ARGS) { int la; char *p; ! /* ! * Close out prior scopes. "Regular" explicit macros cannot be ! * nested, but we allow roff macros to be placed just about ! * anywhere. ! */ ! if ( ! man_block_alloc(m, line, ppos, tok)) return(0); ! if ( ! man_head_alloc(m, line, ppos, tok)) return(0); for (;;) { la = *pos; ! if ( ! man_args(m, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(m, line, la, p)) return(0); } ! assert(m); assert(tok != MAN_MAX); ! if ( ! rew_scope(MAN_HEAD, m, tok)) ! return(0); ! return(man_body_alloc(m, line, ppos, tok)); } /* --- 285,355 ---- switch (tok) { case (MAN_RE): ntok = MAN_RS; break; + case (MAN_UE): + ntok = MAN_UR; + break; default: abort(); /* NOTREACHED */ } ! for (nn = man->last->parent; nn; nn = nn->parent) ! if (ntok == nn->tok && MAN_BLOCK == nn->type) break; ! if (NULL == nn) { ! man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE); ! if ( ! rew_scope(MAN_BLOCK, man, MAN_PP)) return(0); ! } else ! man_unscope(man, nn, MANDOCERR_MAX); return(1); } /* ARGSUSED */ int blk_exp(MACRO_PROT_ARGS) { + struct man_node *n; int la; char *p; ! /* Close out prior implicit scopes. */ ! if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); ! ! if ( ! man_block_alloc(man, line, ppos, tok)) return(0); + if ( ! man_head_alloc(man, line, ppos, tok)) + return(0); for (;;) { la = *pos; ! if ( ! man_args(man, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(man, line, la, p)) return(0); } ! assert(man); assert(tok != MAN_MAX); ! for (n = man->last; n; n = n->parent) { ! if (n->tok != tok) ! continue; ! assert(MAN_HEAD == n->type); ! man_unscope(man, n, MANDOCERR_MAX); ! break; ! } ! ! return(man_body_alloc(man, line, ppos, tok)); } /*
*** 344,393 **** char *p; struct man_node *n; /* Close out prior scopes. */ ! if ( ! rew_scope(MAN_BODY, m, tok)) return(0); ! if ( ! rew_scope(MAN_BLOCK, m, tok)) return(0); /* Allocate new block & head scope. */ ! if ( ! man_block_alloc(m, line, ppos, tok)) return(0); ! if ( ! man_head_alloc(m, line, ppos, tok)) return(0); ! n = m->last; /* Add line arguments. */ for (;;) { la = *pos; ! if ( ! man_args(m, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(m, line, la, p)) return(0); } /* Close out head and open body (unless MAN_SCOPE). */ if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { ! m->flags |= MAN_BLINE; return(1); ! } else if (n == m->last) { ! m->flags |= MAN_BLINE; return(1); } } ! if ( ! rew_scope(MAN_HEAD, m, tok)) return(0); ! return(man_body_alloc(m, line, ppos, tok)); } /* ARGSUSED */ int --- 366,415 ---- char *p; struct man_node *n; /* Close out prior scopes. */ ! if ( ! rew_scope(MAN_BODY, man, tok)) return(0); ! if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); /* Allocate new block & head scope. */ ! if ( ! man_block_alloc(man, line, ppos, tok)) return(0); ! if ( ! man_head_alloc(man, line, ppos, tok)) return(0); ! n = man->last; /* Add line arguments. */ for (;;) { la = *pos; ! if ( ! man_args(man, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(man, line, la, p)) return(0); } /* Close out head and open body (unless MAN_SCOPE). */ if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { ! man->flags |= MAN_BLINE; return(1); ! } else if (n == man->last) { ! man->flags |= MAN_BLINE; return(1); } } ! if ( ! rew_scope(MAN_HEAD, man, tok)) return(0); ! return(man_body_alloc(man, line, ppos, tok)); } /* ARGSUSED */ int
*** 395,476 **** { int la; char *p; struct man_node *n; ! if ( ! man_elem_alloc(m, line, ppos, tok)) return(0); ! n = m->last; for (;;) { la = *pos; ! if ( ! man_args(m, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(m, line, la, p)) return(0); } /* * If no arguments are specified and this is MAN_SCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ ! if (n == m->last && MAN_SCOPED & man_macros[tok].flags) { assert( ! (MAN_NSCOPED & man_macros[tok].flags)); ! m->flags |= MAN_ELINE; return(1); } /* Set ignorable context, if applicable. */ if (MAN_NSCOPED & man_macros[tok].flags) { assert( ! (MAN_SCOPED & man_macros[tok].flags)); ! m->flags |= MAN_ILINE; } ! assert(MAN_ROOT != m->last->type); ! m->next = MAN_NEXT_SIBLING; /* * Rewind our element scope. Note that when TH is pruned, we'll * be back at the root, so make sure that we don't clobber as * its sibling. */ ! for ( ; m->last; m->last = m->last->parent) { ! if (m->last == n) break; ! if (m->last->type == MAN_ROOT) break; ! if ( ! man_valid_post(m)) return(0); } ! assert(m->last); /* * Same here regarding whether we're back at the root. */ ! if (m->last->type != MAN_ROOT && ! man_valid_post(m)) return(0); return(1); } int ! man_macroend(struct man *m) { ! return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT)); } static int ! man_args(struct man *m, int line, int *pos, char *buf, char **v) { char *start; assert(*pos); *v = start = buf + *pos; --- 417,507 ---- { int la; char *p; struct man_node *n; ! if ( ! man_elem_alloc(man, line, ppos, tok)) return(0); ! n = man->last; for (;;) { la = *pos; ! if ( ! man_args(man, line, pos, buf, &p)) break; ! if ( ! man_word_alloc(man, line, la, p)) return(0); } /* + * Append MAN_EOS in case the last snipped argument + * ends with a dot, e.g. `.IR syslog (3).' + */ + + if (n != man->last && + mandoc_eos(man->last->string, strlen(man->last->string), 0)) + man->last->flags |= MAN_EOS; + + /* * If no arguments are specified and this is MAN_SCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ ! if (n == man->last && MAN_SCOPED & man_macros[tok].flags) { assert( ! (MAN_NSCOPED & man_macros[tok].flags)); ! man->flags |= MAN_ELINE; return(1); } /* Set ignorable context, if applicable. */ if (MAN_NSCOPED & man_macros[tok].flags) { assert( ! (MAN_SCOPED & man_macros[tok].flags)); ! man->flags |= MAN_ILINE; } ! assert(MAN_ROOT != man->last->type); ! man->next = MAN_NEXT_SIBLING; /* * Rewind our element scope. Note that when TH is pruned, we'll * be back at the root, so make sure that we don't clobber as * its sibling. */ ! for ( ; man->last; man->last = man->last->parent) { ! if (man->last == n) break; ! if (man->last->type == MAN_ROOT) break; ! if ( ! man_valid_post(man)) return(0); } ! assert(man->last); /* * Same here regarding whether we're back at the root. */ ! if (man->last->type != MAN_ROOT && ! man_valid_post(man)) return(0); return(1); } int ! man_macroend(struct man *man) { ! return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT)); } static int ! man_args(struct man *man, int line, int *pos, char *buf, char **v) { char *start; assert(*pos); *v = start = buf + *pos;
*** 477,484 **** assert(' ' != *start); if ('\0' == *start) return(0); ! *v = mandoc_getarg(m->parse, v, line, pos); return(1); } --- 508,515 ---- assert(' ' != *start); if ('\0' == *start) return(0); ! *v = mandoc_getarg(man->parse, v, line, pos); return(1); }