=================================================================== RCS file: /cvs/mandoc/man_macro.c,v retrieving revision 1.2 retrieving revision 1.13 diff -u -p -r1.2 -r1.13 --- mandoc/man_macro.c 2009/03/23 14:31:58 1.2 +++ mandoc/man_macro.c 2009/04/05 16:34:22 1.13 @@ -1,4 +1,4 @@ -/* $Id: man_macro.c,v 1.2 2009/03/23 14:31:58 kristaps Exp $ */ +/* $Id: man_macro.c,v 1.13 2009/04/05 16:34:22 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -19,78 +19,210 @@ #include #include #include -#include #include #include "libman.h" -static int in_line_eoln(MACRO_PROT_ARGS); +#define FL_NLINE (1 << 0) +#define FL_TLINE (1 << 1) -const struct man_macro __man_macros[MAN_MAX] = { - { in_line_eoln, 0 }, /* MAN___ */ - { in_line_eoln, 0 }, /* MAN_TH */ - { in_line_eoln, 0 }, /* MAN_SH */ - { in_line_eoln, 0 }, /* MAN_SS */ - { in_line_eoln, 0 }, /* MAN_TP */ - { in_line_eoln, 0 }, /* MAN_LP */ - { in_line_eoln, 0 }, /* MAN_PP */ - { in_line_eoln, 0 }, /* MAN_P */ - { in_line_eoln, 0 }, /* MAN_IP */ - { in_line_eoln, 0 }, /* MAN_HP */ - { in_line_eoln, 0 }, /* MAN_SM */ - { in_line_eoln, 0 }, /* MAN_SB */ - { in_line_eoln, 0 }, /* MAN_BI */ - { in_line_eoln, 0 }, /* MAN_IB */ - { in_line_eoln, 0 }, /* MAN_BR */ - { in_line_eoln, 0 }, /* MAN_RB */ - { in_line_eoln, 0 }, /* MAN_R */ - { in_line_eoln, 0 }, /* MAN_B */ - { in_line_eoln, 0 }, /* MAN_I */ +static int man_args(struct man *, int, + int *, char *, char **); + +static int man_flags[MAN_MAX] = { + 0, /* __ */ + 0, /* TH */ + 0, /* SH */ + 0, /* SS */ + FL_TLINE, /* TP */ + 0, /* LP */ + 0, /* PP */ + 0, /* P */ + 0, /* IP */ + 0, /* HP */ + FL_NLINE, /* SM */ + FL_NLINE, /* SB */ + FL_NLINE, /* BI */ + FL_NLINE, /* IB */ + FL_NLINE, /* BR */ + FL_NLINE, /* RB */ + FL_NLINE, /* R */ + FL_NLINE, /* B */ + FL_NLINE, /* I */ + FL_NLINE, /* IR */ + FL_NLINE, /* RI */ + 0, /* br */ + 0, /* na */ + FL_NLINE, /* i */ }; -const struct man_macro * const man_macros = __man_macros; - - -/* - * In-line macro that spans an entire line. May be callable, but has no - * subsequent parsed arguments. - */ -static int -in_line_eoln(MACRO_PROT_ARGS) +int +man_macro(struct man *man, int tok, int line, + int ppos, int *pos, char *buf) { -#if 0 - int c, w, la; - char *p; + int w, la; + char *p; + struct man_node *n; - if ( ! man_elem_alloc(man, line, ppos, tok, arg)) + if ( ! man_elem_alloc(man, line, ppos, tok)) return(0); - man->next = MDOC_NEXT_SIBLING; + n = man->last; + man->next = MAN_NEXT_CHILD; for (;;) { la = *pos; - w = man_args(man, line, pos, buf, tok, &p); + w = man_args(man, line, pos, buf, &p); - if (ARGS_ERROR == w) + if (-1 == w) return(0); - if (ARGS_EOLN == w) + if (0 == w) break; - c = ARGS_QWORD == w ? MAN_MAX : - lookup(man, line, la, tok, p); + if ( ! man_word_alloc(man, line, la, p)) + return(0); + man->next = MAN_NEXT_SIBLING; + } - if (MDOC_MAX != c && -1 != c) { - if ( ! rew_elem(mdoc, tok)) - return(0); - return(mdoc_macro(mdoc, c, line, la, pos, buf)); - } else if (-1 == c) + if (n == man->last && (FL_NLINE & man_flags[tok])) { + if (MAN_NLINE & man->flags) + return(man_verr(man, line, ppos, + "next-line scope already open")); + man->flags |= MAN_NLINE; + return(1); + } + + if (FL_TLINE & man_flags[tok]) { + if (MAN_NLINE & man->flags) + return(man_verr(man, line, ppos, + "next-line scope already open")); + man->flags |= MAN_NLINE; + return(1); + } + + /* + * 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); + if ( ! man_action_post(man)) + return(0); + } - if ( ! mdoc_word_alloc(mdoc, line, la, p)) + 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); + if (man->last->type != MAN_ROOT && ! man_action_post(man)) + return(0); + if (man->last->type != MAN_ROOT) + man->next = MAN_NEXT_SIBLING; + + return(1); +} + + +int +man_macroend(struct man *m) +{ + + for ( ; m->last && m->last != m->first; + m->last = m->last->parent) { + if ( ! man_valid_post(m)) return(0); + if ( ! man_action_post(m)) + return(0); } + assert(m->last == m->first); - return(rew_elem(mdoc, tok)); -#endif + if ( ! man_valid_post(m)) + return(0); + if ( ! man_action_post(m)) + return(0); + return(1); } + +/* ARGSUSED */ +static int +man_args(struct man *m, int line, + int *pos, char *buf, char **v) +{ + + if (0 == buf[*pos]) + return(0); + + /* First parse non-quoted strings. */ + + if ('\"' != buf[*pos]) { + *v = &buf[*pos]; + + while (buf[*pos]) { + if (' ' == buf[*pos]) + if ('\\' != buf[*pos - 1]) + break; + (*pos)++; + } + + if (0 == buf[*pos]) + return(1); + + buf[(*pos)++] = 0; + + if (0 == buf[*pos]) + return(1); + + while (buf[*pos] && ' ' == buf[*pos]) + (*pos)++; + + if (buf[*pos]) + return(1); + + if ( ! man_vwarn(m, line, *pos, "trailing spaces")) + return(-1); + + return(1); + } + + /* + * If we're a quoted string (and quoted strings are allowed), + * then parse ahead to the next quote. If none's found, it's an + * error. After, parse to the next word. + */ + + *v = &buf[++(*pos)]; + + while (buf[*pos] && '\"' != buf[*pos]) + (*pos)++; + + if (0 == buf[*pos]) { + if ( ! man_vwarn(m, line, *pos, "unterminated quote")) + return(-1); + return(1); + } + + buf[(*pos)++] = 0; + if (0 == buf[*pos]) + return(1); + + while (buf[*pos] && ' ' == buf[*pos]) + (*pos)++; + + if (buf[*pos]) + return(1); + + if ( ! man_vwarn(m, line, *pos, "trailing spaces")) + return(-1); + return(1); +}