diff options
-rw-r--r-- | main.c | 15 | ||||
-rw-r--r-- | mandoc.h | 3 | ||||
-rw-r--r-- | roff.c | 79 |
3 files changed, 89 insertions, 8 deletions
@@ -773,6 +773,14 @@ mwarn(void *arg, int line, int col, const char *msg) return(1); } +static const char * const mandocerrs[MANDOCERR_MAX] = { + "ok", + "multi-line scope open on exit", + "request for scope closure when no matching scope is open", + "line arguments will be lost", + "memory exhausted" +}; + /* * XXX: this is experimental code that will eventually become the * generic means of covering all warnings and errors! @@ -785,7 +793,12 @@ mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg) cp = (struct curparse *)arg; - /*fprintf(stderr, "%s:%d:%d: %s\n", cp->file, ln, col + 1, msg);*/ + fprintf(stderr, "%s:%d:%d: %s", cp->file, + ln, col + 1, mandocerrs[t]); + + if (msg) + fprintf(stderr, ": %s", msg); + fputc('\n', stderr); return(1); } @@ -25,6 +25,9 @@ enum mandocerr { MANDOCERR_NOSCOPE, /* request scope close w/none open */ #define MANDOCERR_WARNING MANDOCERR_SCOPEEXIT + MANDOCERR_ARGSLOST, /* line arguments will be lost */ +#define MANDOCERR_ERROR MANDOCERR_ARGSLOST + MANDOCERR_MEM, /* memory exhausted */ #define MANDOCERR_FATAL MANDOCERR_MEM @@ -44,6 +44,7 @@ struct roff { struct roffnode { enum rofft tok; /* type of node */ struct roffnode *parent; /* up one in stack */ + char *end; /* custom end-token */ int line; /* parse line */ int col; /* parse col */ }; @@ -267,21 +268,52 @@ roff_ignore(ROFF_ARGS) static enum rofferr roff_sub_ig(ROFF_ARGS) { - enum rofft t; - int pos; + int i, j; /* Ignore free-text lines. */ if ('.' != (*bufp)[ppos]) return(ROFF_IGN); - /* Ignore macros unless it's a closing macro. */ + if (r->last->end) { + /* + * Allow a macro to break us, if we've defined a special + * one for the case. Old groff didn't allow spaces to + * buffer the macro, but new groff does. Whee! + */ + i = ppos + 1; + while ((*bufp)[i] && ' ' == (*bufp)[i]) + i++; + + if ('\0' == (*bufp)[i]) + return(ROFF_IGN); + + for (j = 0; r->last->end[j]; i++, j++) + if ((*bufp)[i] != r->last->end[j]) + return(ROFF_IGN); + + if (r->last->end[j]) + return(ROFF_IGN); + if ((*bufp)[i] && ' ' != (*bufp)[i]) + return(ROFF_IGN); - t = roff_parse(*bufp, &pos); - if (ROFF_close != t) + while (' ' == (*bufp)[i]) + i++; + } else if (ROFF_close != roff_parse(*bufp, &i)) return(ROFF_IGN); + /* + * Pop off the ignoring context and warn if we're going to lose + * any of our remaining arguments. + */ + roffnode_pop(r); + + if ('\0' == (*bufp)[i]) + return(ROFF_IGN); + if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL)) + return(ROFF_ERR); + return(ROFF_IGN); } @@ -303,9 +335,42 @@ roff_new_close(ROFF_ARGS) static enum rofferr roff_new_ig(ROFF_ARGS) { + int i; + + if ( ! roffnode_push(r, ROFF_ig, ln, ppos)) + return(ROFF_ERR); + + i = (int)ppos; + while ((*bufp)[i] && ' ' != (*bufp)[i]) + i++; + + if (i == (int)ppos) + return(ROFF_IGN); + if ((*bufp)[i]) + if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL)) + return(ROFF_ERR); - return(roffnode_push(r, ROFF_ig, ln, ppos) ? - ROFF_IGN : ROFF_ERR); + /* + * If `.ig' has arguments, the first argument (up to the next + * whitespace) is interpreted as an argument marking the macro + * close. Thus, `.ig foo' will close at `.foo'. + * + * NOTE: the closing macro `.foo' in the above case is not + * allowed to have leading spaces with old groff! Thus `.foo' + * != `. foo'. Oh yeah, everything after the `.foo' is lost. + * Merry fucking Christmas. + */ + + r->last->end = malloc((size_t)i - ppos + 1); + if (NULL == r->last->end) { + (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL); + return(ROFF_ERR); + } + + memcpy(r->last->end, &(*bufp)[ppos], (size_t)i - ppos); + r->last->end[(size_t)i - ppos] = '\0'; + + return(ROFF_IGN); } |