=================================================================== RCS file: /cvs/mandoc/man.c,v retrieving revision 1.122 retrieving revision 1.135 diff -u -p -r1.122 -r1.135 --- mandoc/man.c 2013/12/31 23:23:10 1.122 +++ mandoc/man.c 2014/07/30 21:18:24 1.135 @@ -1,6 +1,8 @@ -/* $Id: man.c,v 1.122 2013/12/31 23:23:10 schwarze Exp $ */ +/* $Id: man.c,v 1.135 2014/07/30 21:18:24 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2013, 2014 Ingo Schwarze + * Copyright (c) 2011 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +23,7 @@ #include #include +#include #include #include #include @@ -28,12 +31,13 @@ #include "man.h" #include "mandoc.h" +#include "mandoc_aux.h" #include "libman.h" #include "libmandoc.h" -const char *const __man_macronames[MAN_MAX] = { +const char *const __man_macronames[MAN_MAX] = { "br", "TH", "SH", "SS", - "TP", "LP", "PP", "P", + "TP", "LP", "PP", "P", "IP", "HP", "SM", "SB", "BI", "IB", "BR", "RB", "R", "B", "I", "IR", @@ -41,17 +45,17 @@ const char *const __man_macronames[MAN_MAX] = { "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", "ft", "OP", "EX", "EE", - "UR", "UE" + "UR", "UE", "ll" }; const char * const *man_macronames = __man_macronames; -static struct man_node *man_node_alloc(struct man *, int, int, +static struct man_node *man_node_alloc(struct man *, int, int, enum man_type, enum mant); -static int man_node_append(struct man *, +static int man_node_append(struct man *, struct man_node *); static void man_node_free(struct man_node *); -static void man_node_unlink(struct man *, +static void man_node_unlink(struct man *, struct man_node *); static int man_ptext(struct man *, int, char *, int); static int man_pmacro(struct man *, int, char *, int); @@ -64,20 +68,16 @@ const struct man_node * man_node(const struct man *man) { - assert( ! (MAN_HALT & man->flags)); return(man->first); } - const struct man_meta * man_meta(const struct man *man) { - assert( ! (MAN_HALT & man->flags)); return(&man->meta); } - void man_reset(struct man *man) { @@ -86,7 +86,6 @@ man_reset(struct man *man) man_alloc1(man); } - void man_free(struct man *man) { @@ -95,9 +94,8 @@ man_free(struct man *man) free(man); } - struct man * -man_alloc(struct roff *roff, struct mparse *parse) +man_alloc(struct roff *roff, struct mparse *parse, int quick) { struct man *p; @@ -105,39 +103,31 @@ man_alloc(struct roff *roff, struct mparse *parse) man_hash_init(); p->parse = parse; + p->quick = quick; p->roff = roff; man_alloc1(p); return(p); } - int man_endparse(struct man *man) { - assert( ! (MAN_HALT & man->flags)); - if (man_macroend(man)) - return(1); - man->flags |= MAN_HALT; - return(0); + return(man_macroend(man)); } - int man_parseln(struct man *man, int ln, char *buf, int offs) { man->flags |= MAN_NEWLINE; - assert( ! (MAN_HALT & man->flags)); - return (roff_getcontrol(man->roff, buf, &offs) ? - man_pmacro(man, ln, buf, offs) : - man_ptext(man, ln, buf, offs)); + man_pmacro(man, ln, buf, offs) : + man_ptext(man, ln, buf, offs)); } - static void man_free1(struct man *man) { @@ -156,7 +146,6 @@ man_free1(struct man *man) free(man->meta.msec); } - static void man_alloc1(struct man *man) { @@ -180,12 +169,12 @@ man_node_append(struct man *man, struct man_node *p) assert(MAN_ROOT != p->type); switch (man->next) { - case (MAN_NEXT_SIBLING): + case MAN_NEXT_SIBLING: man->last->next = p; p->prev = man->last; p->parent = man->last->parent; break; - case (MAN_NEXT_CHILD): + case MAN_NEXT_CHILD: man->last->child = p; p->parent = man->last; break; @@ -193,7 +182,7 @@ man_node_append(struct man *man, struct man_node *p) abort(); /* NOTREACHED */ } - + assert(p->parent); p->parent->nchild++; @@ -201,15 +190,15 @@ man_node_append(struct man *man, struct man_node *p) return(0); switch (p->type) { - case (MAN_HEAD): + case MAN_HEAD: assert(MAN_BLOCK == p->parent->type); p->parent->head = p; break; - case (MAN_TAIL): + case MAN_TAIL: assert(MAN_BLOCK == p->parent->type); p->parent->tail = p; break; - case (MAN_BODY): + case MAN_BODY: assert(MAN_BLOCK == p->parent->type); p->parent->body = p; break; @@ -220,9 +209,9 @@ man_node_append(struct man *man, struct man_node *p) man->last = p; switch (p->type) { - case (MAN_TBL): + case MAN_TBL: /* FALLTHROUGH */ - case (MAN_TEXT): + case MAN_TEXT: if ( ! man_valid_post(man)) return(0); break; @@ -233,9 +222,8 @@ man_node_append(struct man *man, struct man_node *p) return(1); } - static struct man_node * -man_node_alloc(struct man *man, int line, int pos, +man_node_alloc(struct man *man, int line, int pos, enum man_type type, enum mant tok) { struct man_node *p; @@ -252,7 +240,6 @@ man_node_alloc(struct man *man, int line, int pos, return(p); } - int man_elem_alloc(struct man *man, int line, int pos, enum mant tok) { @@ -265,7 +252,6 @@ man_elem_alloc(struct man *man, int line, int pos, enu return(1); } - int man_tail_alloc(struct man *man, int line, int pos, enum mant tok) { @@ -278,7 +264,6 @@ man_tail_alloc(struct man *man, int line, int pos, enu return(1); } - int man_head_alloc(struct man *man, int line, int pos, enum mant tok) { @@ -291,7 +276,6 @@ man_head_alloc(struct man *man, int line, int pos, enu return(1); } - int man_body_alloc(struct man *man, int line, int pos, enum mant tok) { @@ -304,7 +288,6 @@ man_body_alloc(struct man *man, int line, int pos, enu return(1); } - int man_block_alloc(struct man *man, int line, int pos, enum mant tok) { @@ -332,7 +315,6 @@ man_word_alloc(struct man *man, int line, int pos, con return(1); } - /* * Free all of the resources held by a node. This does NOT unlink a * node from its context; for that, see man_node_unlink(). @@ -346,7 +328,6 @@ man_node_free(struct man_node *p) free(p); } - void man_node_delete(struct man *man, struct man_node *p) { @@ -363,8 +344,6 @@ man_addeqn(struct man *man, const struct eqn *ep) { struct man_node *n; - assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX); n->eqn = ep; @@ -380,8 +359,6 @@ man_addspan(struct man *man, const struct tbl_span *sp { struct man_node *n; - assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX); n->span = sp; @@ -403,7 +380,7 @@ man_descope(struct man *man, int line, int offs) if (MAN_ELINE & man->flags) { man->flags &= ~MAN_ELINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); } @@ -411,7 +388,7 @@ man_descope(struct man *man, int line, int offs) return(1); man->flags &= ~MAN_BLINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, line, offs, man->last->tok)); } @@ -448,9 +425,9 @@ man_ptext(struct man *man, int line, char *buf, int of return(1); } - /* + /* * Warn if the last un-escaped character is whitespace. Then - * strip away the remaining spaces (tabs stay!). + * strip away the remaining spaces (tabs stay!). */ i = (int)strlen(buf); @@ -458,7 +435,8 @@ man_ptext(struct man *man, int line, char *buf, int of if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) - man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE); + mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, + line, i - 1, NULL); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; @@ -488,13 +466,15 @@ man_ptext(struct man *man, int line, char *buf, int of static int man_pmacro(struct man *man, int ln, char *buf, int offs) { - int i, ppos; - enum mant tok; char mac[5]; struct man_node *n; + enum mant tok; + int i, ppos; + int bline; if ('"' == buf[offs]) { - man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); + mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse, + ln, offs, NULL); return(1); } else if ('\0' == buf[offs]) return(1); @@ -507,8 +487,8 @@ man_pmacro(struct man *man, int ln, char *buf, int off */ i = 0; - while (i < 4 && '\0' != buf[offs] && - ' ' != buf[offs] && '\t' != buf[offs]) + while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && + '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; @@ -516,8 +496,8 @@ man_pmacro(struct man *man, int ln, char *buf, int off tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, - ppos, "%s", buf + ppos - 1); + mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, ppos, + "%s", buf + ppos - 1); return(1); } @@ -526,15 +506,16 @@ man_pmacro(struct man *man, int ln, char *buf, int off while (buf[offs] && ' ' == buf[offs]) offs++; - /* + /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); + mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, + ln, offs - 1, NULL); - /* + /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. @@ -550,7 +531,7 @@ man_pmacro(struct man *man, int ln, char *buf, int off if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; - mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, + mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); @@ -581,7 +562,7 @@ man_pmacro(struct man *man, int ln, char *buf, int off assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); - mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, + mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); @@ -589,63 +570,41 @@ man_pmacro(struct man *man, int ln, char *buf, int off man->flags &= ~MAN_BLINE; } - /* - * Save the fact that we're in the next-line for a block. In - * this way, embedded roff instructions can "remember" state - * when they exit. - */ + /* Remember whether we are in next-line scope for a block head. */ - if (MAN_BLINE & man->flags) - man->flags |= MAN_BPLINE; + bline = man->flags & MAN_BLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) - goto err; + return(0); - /* - * We weren't in a block-line scope when entering the - * above-parsed macro, so return. - */ + /* In quick mode (for mandocdb), abort after the NAME section. */ - if ( ! (MAN_BPLINE & man->flags)) { - man->flags &= ~MAN_ILINE; - return(1); + if (man->quick && MAN_SH == tok) { + n = man->last; + if (MAN_BODY == n->type && + strcmp(n->prev->child->string, "NAME")) + return(2); } - man->flags &= ~MAN_BPLINE; /* - * If we're in a block scope, then allow this macro to slip by - * without closing scope around it. + * If we are in a next-line scope for a block head, + * close it out now and switch to the body, + * unless the next-line scope is allowed to continue. */ - if (MAN_ILINE & man->flags) { - man->flags &= ~MAN_ILINE; + if ( ! bline || man->flags & MAN_ELINE || + man_macros[tok].flags & MAN_NSCOPED) return(1); - } - /* - * If we've opened a new next-line element scope, then return - * now, as the next line will close out the block scope. - */ - - if (MAN_ELINE & man->flags) - return(1); - - /* Close out the block scope opened in the prior line. */ - assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); - -err: /* Error out. */ - - man->flags |= MAN_HALT; - return(0); } /* @@ -695,4 +654,50 @@ man_mparse(const struct man *man) assert(man && man->parse); return(man->parse); +} + +void +man_deroff(char **dest, const struct man_node *n) +{ + char *cp; + size_t sz; + + if (MAN_TEXT != n->type) { + 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; + } + + /* 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; + } + + mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); + free(*dest); + *dest = cp; }