diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2015-10-17 00:21:07 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2015-10-17 00:21:07 +0000 |
commit | 7458ebbfeabd0fc88f99200855485fe117765efe (patch) | |
tree | ba2a974eaf37b6fd348a214d94d5d8cbd718f3be /mdoc_argv.c | |
parent | 8b031eb4b738371ee017dd07426252443d1760db (diff) | |
download | mandoc-7458ebbfeabd0fc88f99200855485fe117765efe.tar.gz |
Very tricky diff to fix macro interpretation and spacing around tabs
in .Bl -column; it took me more than a day to get this right.
Triggered by a loosely related bug report from tim@.
The lesson for you is: Use .Ta macros in .Bl -column, avoid tabs,
or you are in for surprises: The last word before a tab is not
interpreted as a macro (unless there is a blank in between), the
first word after a tab isn't either (unless there is a blank in
between), and a blank after a tab causes a leading blank in the
respective output cell. Yes, "blank", "tab", "blank tab" and "tab
blank" all have different semantics; if you write code relying on
that, good luck maintaining it afterwards...
Diffstat (limited to 'mdoc_argv.c')
-rw-r--r-- | mdoc_argv.c | 60 |
1 files changed, 45 insertions, 15 deletions
diff --git a/mdoc_argv.c b/mdoc_argv.c index dd671420..49c8e04a 100644 --- a/mdoc_argv.c +++ b/mdoc_argv.c @@ -449,11 +449,10 @@ args(struct roff_man *mdoc, int line, int *pos, { char *p; int pairs; - enum margserr rc; if (buf[*pos] == '\0') { if (mdoc->flags & MDOC_PHRASELIT && - ! (mdoc->flags & MDOC_PPHRASE)) { + ! (mdoc->flags & MDOC_PHRASE)) { mandoc_msg(MANDOCERR_ARG_QUOTE, mdoc->parse, line, *pos, NULL); mdoc->flags &= ~MDOC_PHRASELIT; @@ -473,18 +472,41 @@ args(struct roff_man *mdoc, int line, int *pos, if (fl == ARGSFL_TABSEP) { if ((p = strchr(*v, '\t')) != NULL) { - /* Skip any blank characters after the tab. */ + + /* + * Words right before and right after + * tab characters are not parsed, + * unless there is a blank in between. + */ + + if (p[-1] != ' ') + mdoc->flags |= MDOC_PHRASEQL; + if (p[1] != ' ') + mdoc->flags |= MDOC_PHRASEQN; + + /* + * One or more blanks after a tab cause + * one leading blank in the next column. + * So skip all but one of them. + */ + *pos += (int)(p - *v) + 1; - while (buf[*pos] == ' ') + while (buf[*pos] == ' ' && buf[*pos + 1] == ' ') (*pos)++; - rc = ARGS_PPHRASE; + + /* + * A tab at the end of an input line + * switches to the next column. + */ + + if (buf[*pos] == '\0' || buf[*pos + 1] == '\0') + mdoc->flags |= MDOC_PHRASEQN; } else { p = strchr(*v, '\0'); if (p[-1] == ' ') mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, line, *pos, NULL); *pos += (int)(p - *v); - rc = ARGS_PEND; } /* Skip any trailing blank characters. */ @@ -493,7 +515,7 @@ args(struct roff_man *mdoc, int line, int *pos, p--; *p = '\0'; - return rc; + return ARGS_PHRASE; } /* @@ -504,11 +526,11 @@ args(struct roff_man *mdoc, int line, int *pos, * Whitespace is NOT involved in literal termination. */ - if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) { - if ( ! (MDOC_PHRASELIT & mdoc->flags)) + if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') { + if ( ! (mdoc->flags & MDOC_PHRASELIT)) *v = &buf[++(*pos)]; - if (MDOC_PPHRASE & mdoc->flags) + if (mdoc->flags & MDOC_PHRASE) mdoc->flags |= MDOC_PHRASELIT; pairs = 0; @@ -528,11 +550,10 @@ args(struct roff_man *mdoc, int line, int *pos, if (pairs) buf[*pos - pairs] = '\0'; - if ('\0' == buf[*pos]) { - if (MDOC_PPHRASE & mdoc->flags) - return ARGS_QWORD; - mandoc_msg(MANDOCERR_ARG_QUOTE, - mdoc->parse, line, *pos, NULL); + if (buf[*pos] == '\0') { + if ( ! (mdoc->flags & MDOC_PHRASE)) + mandoc_msg(MANDOCERR_ARG_QUOTE, + mdoc->parse, line, *pos, NULL); return ARGS_QWORD; } @@ -555,6 +576,15 @@ args(struct roff_man *mdoc, int line, int *pos, p = &buf[*pos]; *v = mandoc_getarg(mdoc->parse, &p, line, pos); + /* + * After parsing the last word in this phrase, + * tell lookup() whether or not to interpret it. + */ + + if (*p == '\0' && mdoc->flags & MDOC_PHRASEQL) { + mdoc->flags &= ~MDOC_PHRASEQL; + mdoc->flags |= MDOC_PHRASEQF; + } return ARGS_WORD; } |