-/* $Id: man.c,v 1.158 2015/04/19 13:50:25 schwarze Exp $ */
+/* $Id: man.c,v 1.166 2015/10/22 21:54:23 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
const char * const *man_macronames = __man_macronames;
-static void man_breakscope(struct roff_man *, int);
static void man_descope(struct roff_man *, int, int);
static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int);
-void
-man_endparse(struct roff_man *man)
-{
-
- man_macroend(man);
-}
-
int
man_parseln(struct roff_man *man, int ln, char *buf, int offs)
{
if (man->last->type != ROFFT_EQN || ln > man->last->line)
man->flags |= MAN_NEWLINE;
- return (roff_getcontrol(man->roff, buf, &offs) ?
+ return roff_getcontrol(man->roff, buf, &offs) ?
man_pmacro(man, ln, buf, offs) :
- man_ptext(man, ln, buf, offs));
-}
-
-void
-man_elem_alloc(struct roff_man *man, int line, int pos, int tok)
-{
- struct roff_node *p;
-
- p = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok);
- roff_node_append(man, p);
- man->next = ROFF_NEXT_CHILD;
-}
-
-void
-man_block_alloc(struct roff_man *man, int line, int pos, int tok)
-{
- struct roff_node *p;
-
- p = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
- roff_node_append(man, p);
- man->next = ROFF_NEXT_CHILD;
-}
-
-void
-man_word_alloc(struct roff_man *man, int line, int pos, const char *word)
-{
- struct roff_node *n;
-
- n = roff_node_alloc(man, line, pos, ROFFT_TEXT, MAN_MAX);
- n->string = roff_strdup(man->roff, word);
- roff_node_append(man, n);
- man_valid_post(man);
- man->next = ROFF_NEXT_SIBLING;
-}
-
-void
-man_word_append(struct roff_man *man, const char *word)
-{
- struct roff_node *n;
- char *addstr, *newstr;
-
- n = man->last;
- addstr = roff_strdup(man->roff, word);
- mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
- free(addstr);
- free(n->string);
- n->string = newstr;
- man->next = ROFF_NEXT_SIBLING;
-}
-
-void
-man_addeqn(struct roff_man *man, const struct eqn *ep)
-{
- struct roff_node *n;
-
- n = roff_node_alloc(man, ep->ln, ep->pos, ROFFT_EQN, MAN_MAX);
- n->eqn = ep;
- if (ep->ln > man->last->line)
- n->flags |= MAN_LINE;
- roff_node_append(man, n);
- man->next = ROFF_NEXT_SIBLING;
- man_descope(man, ep->ln, ep->pos);
-}
-
-void
-man_addspan(struct roff_man *man, const struct tbl_span *sp)
-{
- struct roff_node *n;
-
- man_breakscope(man, MAN_MAX);
- n = roff_node_alloc(man, sp->line, 0, ROFFT_TBL, MAN_MAX);
- n->span = sp;
- roff_node_append(man, n);
- man_valid_post(man);
- man->next = ROFF_NEXT_SIBLING;
- man_descope(man, sp->line, 0);
+ man_ptext(man, ln, buf, offs);
}
static void
/* Literal free-form text whitespace is preserved. */
if (man->flags & MAN_LITERAL) {
- man_word_alloc(man, line, offs, buf + offs);
+ roff_word_alloc(man, line, offs, buf + offs);
man_descope(man, line, offs);
- return(1);
+ return 1;
}
for (i = offs; buf[i] == ' '; i++)
/* Allocate a blank entry. */
if (man->last->tok != MAN_SH &&
man->last->tok != MAN_SS) {
- man_elem_alloc(man, line, offs, MAN_sp);
+ roff_elem_alloc(man, line, offs, MAN_sp);
man->next = ROFF_NEXT_SIBLING;
}
- return(1);
+ return 1;
}
/*
buf[i] = '\0';
}
- man_word_alloc(man, line, offs, buf + offs);
+ roff_word_alloc(man, line, offs, buf + offs);
/*
* End-of-sentence check. If the last character is an unescaped
man->last->flags |= MAN_EOS;
man_descope(man, line, offs);
- return(1);
+ return 1;
}
static int
mac[i] = '\0';
- tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
+ tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;
- if (tok == MAN_MAX) {
+ if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1);
- return(1);
+ return 1;
}
/* Skip a leading escape sequence or tab. */
n = man->last;
if (n->type == ROFFT_BODY &&
strcmp(n->prev->child->string, "NAME"))
- return(2);
+ return 2;
}
/*
if ( ! bline || man->flags & MAN_ELINE ||
man_macros[tok].flags & MAN_NSCOPED)
- return(1);
+ return 1;
assert(man->flags & MAN_BLINE);
man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
roff_body_alloc(man, ln, ppos, man->last->tok);
- return(1);
+ return 1;
}
void
* Delete the element that is being broken.
*/
- if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
+ if (man->flags & MAN_ELINE && (tok == TOKEN_NONE ||
! (man_macros[tok].flags & MAN_NSCOPED))) {
n = man->last;
assert(n->type != ROFFT_TEXT);
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
- tok == MAN_MAX ? "TS" : man_macronames[tok],
+ tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
}
+ /*
+ * Weird special case:
+ * Switching fill mode closes section headers.
+ */
+
+ if (man->flags & MAN_BLINE &&
+ (tok == MAN_nf || tok == MAN_fi) &&
+ (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
+ n = man->last;
+ man_unscope(man, n);
+ roff_body_alloc(man, n->line, n->pos, n->tok);
+ man->flags &= ~MAN_BLINE;
+ }
+
/*
* A block header next line scope is open,
* and the new macro is not allowed inside block headers.
* Delete the block that is being broken.
*/
- if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
+ if (man->flags & MAN_BLINE && (tok == TOKEN_NONE ||
man_macros[tok].flags & MAN_BSCOPE)) {
n = man->last;
if (n->type == ROFFT_TEXT)
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
- tok == MAN_MAX ? "TS" : man_macronames[tok],
+ tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
roff_node_delete(man, n);
{
assert(man && man->parse);
- return(man->parse);
+ return man->parse;
}
void
-man_deroff(char **dest, const struct roff_node *n)
+man_state(struct roff_man *man, struct roff_node *n)
{
- char *cp;
- size_t sz;
- if (n->type != ROFFT_TEXT) {
- for (n = n->child; n; n = n->next)
- man_deroff(dest, n);
- return;
- }
-
- /* Skip leading whitespace and escape sequences. */
-
- cp = n->string;
- while ('\0' != *cp) {
- if ('\\' == *cp) {
- cp++;
- mandoc_escape((const char **)&cp, NULL, NULL);
- } else if (isspace((unsigned char)*cp))
- cp++;
- else
- break;
+ switch(n->tok) {
+ case MAN_nf:
+ case MAN_EX:
+ if (man->flags & MAN_LITERAL && ! (n->flags & MAN_VALID))
+ mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
+ n->line, n->pos, "nf");
+ man->flags |= MAN_LITERAL;
+ break;
+ case MAN_fi:
+ case MAN_EE:
+ if ( ! (man->flags & MAN_LITERAL) &&
+ ! (n->flags & MAN_VALID))
+ mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
+ n->line, n->pos, "fi");
+ man->flags &= ~MAN_LITERAL;
+ break;
+ default:
+ break;
}
+ man->last->flags |= MAN_VALID;
+}
- /* Skip trailing whitespace. */
-
- for (sz = strlen(cp); sz; sz--)
- if (0 == isspace((unsigned char)cp[sz-1]))
- break;
-
- /* Skip empty strings. */
-
- if (0 == sz)
- return;
-
- if (NULL == *dest) {
- *dest = mandoc_strndup(cp, sz);
- return;
- }
+void
+man_validate(struct roff_man *man)
+{
- mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
- free(*dest);
- *dest = cp;
+ man->last = man->first;
+ man_node_validate(man);
+ man->flags &= ~MAN_LITERAL;
}