version 1.378, 2021/08/10 12:55:04 |
version 1.387, 2022/05/01 16:22:06 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
Line 227 static int roff_line_ignore(ROFF_ARGS); |
|
Line 227 static int roff_line_ignore(ROFF_ARGS); |
|
static void roff_man_alloc1(struct roff_man *); |
static void roff_man_alloc1(struct roff_man *); |
static void roff_man_free1(struct roff_man *); |
static void roff_man_free1(struct roff_man *); |
static int roff_manyarg(ROFF_ARGS); |
static int roff_manyarg(ROFF_ARGS); |
|
static int roff_mc(ROFF_ARGS); |
static int roff_noarg(ROFF_ARGS); |
static int roff_noarg(ROFF_ARGS); |
static int roff_nop(ROFF_ARGS); |
static int roff_nop(ROFF_ARGS); |
static int roff_nr(ROFF_ARGS); |
static int roff_nr(ROFF_ARGS); |
static int roff_onearg(ROFF_ARGS); |
static int roff_onearg(ROFF_ARGS); |
static enum roff_tok roff_parse(struct roff *, char *, int *, |
static enum roff_tok roff_parse(struct roff *, char *, int *, |
int, int); |
int, int); |
|
static int roff_parse_comment(struct roff *, struct buf *, |
|
int, int, char); |
static int roff_parsetext(struct roff *, struct buf *, |
static int roff_parsetext(struct roff *, struct buf *, |
int, int *); |
int, int *); |
static int roff_renamed(ROFF_ARGS); |
static int roff_renamed(ROFF_ARGS); |
|
static int roff_req_or_macro(ROFF_ARGS); |
static int roff_return(ROFF_ARGS); |
static int roff_return(ROFF_ARGS); |
static int roff_rm(ROFF_ARGS); |
static int roff_rm(ROFF_ARGS); |
static int roff_rn(ROFF_ARGS); |
static int roff_rn(ROFF_ARGS); |
Line 379 static struct roffmac roffs[TOKEN_NONE] = { |
|
Line 383 static struct roffmac roffs[TOKEN_NONE] = { |
|
{ roff_noarg, NULL, NULL, 0 }, /* fi */ |
{ roff_noarg, NULL, NULL, 0 }, /* fi */ |
{ roff_onearg, NULL, NULL, 0 }, /* ft */ |
{ roff_onearg, NULL, NULL, 0 }, /* ft */ |
{ roff_onearg, NULL, NULL, 0 }, /* ll */ |
{ roff_onearg, NULL, NULL, 0 }, /* ll */ |
{ roff_onearg, NULL, NULL, 0 }, /* mc */ |
{ roff_mc, NULL, NULL, 0 }, /* mc */ |
{ roff_noarg, NULL, NULL, 0 }, /* nf */ |
{ roff_noarg, NULL, NULL, 0 }, /* nf */ |
{ roff_onearg, NULL, NULL, 0 }, /* po */ |
{ roff_onearg, NULL, NULL, 0 }, /* po */ |
{ roff_onearg, NULL, NULL, 0 }, /* rj */ |
{ roff_onearg, NULL, NULL, 0 }, /* rj */ |
|
|
roff_man_free(struct roff_man *man) |
roff_man_free(struct roff_man *man) |
{ |
{ |
roff_man_free1(man); |
roff_man_free1(man); |
|
free(man->os_r); |
free(man); |
free(man); |
} |
} |
|
|
Line 1228 deroff(char **dest, const struct roff_node *n) |
|
Line 1233 deroff(char **dest, const struct roff_node *n) |
|
|
|
/* --- main functions of the roff parser ---------------------------------- */ |
/* --- main functions of the roff parser ---------------------------------- */ |
|
|
|
static int |
|
roff_parse_comment(struct roff *r, struct buf *buf, int ln, int pos, |
|
char newesc) |
|
{ |
|
struct roff_node *n; /* used for header comments */ |
|
const char *start; /* start of the string to process */ |
|
const char *cp; /* for RCS id parsing */ |
|
char *stesc; /* start of an escape sequence ('\\') */ |
|
char *ep; /* end of comment string */ |
|
int rcsid; /* kind of RCS id seen */ |
|
|
|
for (start = stesc = buf->buf + pos;; stesc++) { |
|
/* The line ends without continuation or comment. */ |
|
if (stesc[0] == '\0') |
|
return ROFF_CONT; |
|
|
|
/* Unescaped byte: skip it. */ |
|
if (stesc[0] != newesc) |
|
continue; |
|
|
|
/* Backslash at end of line requests line continuation. */ |
|
if (stesc[1] == '\0') { |
|
stesc[0] = '\0'; |
|
return ROFF_IGN | ROFF_APPEND; |
|
} |
|
|
|
/* Found a comment: process it. */ |
|
if (stesc[1] == '"' || stesc[1] == '#') |
|
break; |
|
|
|
/* Escaped escape character: skip them both. */ |
|
if (stesc[1] == newesc) |
|
stesc++; |
|
} |
|
|
|
/* Look for an RCS id in the comment. */ |
|
|
|
rcsid = 0; |
|
if ((cp = strstr(stesc + 2, "$" "OpenBSD")) != NULL) { |
|
rcsid = 1 << MANDOC_OS_OPENBSD; |
|
cp += 8; |
|
} else if ((cp = strstr(stesc + 2, "$" "NetBSD")) != NULL) { |
|
rcsid = 1 << MANDOC_OS_NETBSD; |
|
cp += 7; |
|
} |
|
if (cp != NULL && isalnum((unsigned char)*cp) == 0 && |
|
strchr(cp, '$') != NULL) { |
|
if (r->man->meta.rcsids & rcsid) |
|
mandoc_msg(MANDOCERR_RCS_REP, ln, |
|
(int)(stesc - buf->buf) + 2, "%s", stesc + 1); |
|
r->man->meta.rcsids |= rcsid; |
|
} |
|
|
|
/* Warn about trailing whitespace at the end of the comment. */ |
|
|
|
ep = strchr(stesc + 2, '\0') - 1; |
|
if (*ep == '\n') |
|
*ep-- = '\0'; |
|
if (*ep == ' ' || *ep == '\t') |
|
mandoc_msg(MANDOCERR_SPACE_EOL, |
|
ln, (int)(ep - buf->buf), NULL); |
|
|
|
/* Save comments preceding the title macro in the syntax tree. */ |
|
|
|
if (r->options & MPARSE_COMMENT) { |
|
while (*ep == ' ' || *ep == '\t') |
|
ep--; |
|
ep[1] = '\0'; |
|
n = roff_node_alloc(r->man, ln, stesc + 1 - buf->buf, |
|
ROFFT_COMMENT, TOKEN_NONE); |
|
n->string = mandoc_strdup(stesc + 2); |
|
roff_node_append(r->man, n); |
|
n->flags |= NODE_VALID | NODE_ENDED; |
|
r->man->next = ROFF_NEXT_SIBLING; |
|
} |
|
|
|
/* The comment requests line continuation. */ |
|
|
|
if (stesc[1] == '#') { |
|
*stesc = '\0'; |
|
return ROFF_IGN | ROFF_APPEND; |
|
} |
|
|
|
/* Discard the comment including preceding whitespace. */ |
|
|
|
while (stesc > start && stesc[-1] == ' ' && |
|
(stesc == start + 1 || stesc[-2] != '\\')) |
|
stesc--; |
|
*stesc = '\0'; |
|
return ROFF_CONT; |
|
} |
|
|
/* |
/* |
* In the current line, expand escape sequences that produce parsable |
* In the current line, expand escape sequences that produce parsable |
* input text. Also check the syntax of the remaining escape sequences, |
* input text. Also check the syntax of the remaining escape sequences, |
Line 1238 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
Line 1335 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
{ |
{ |
struct mctx *ctx; /* current macro call context */ |
struct mctx *ctx; /* current macro call context */ |
char ubuf[24]; /* buffer to print the number */ |
char ubuf[24]; /* buffer to print the number */ |
struct roff_node *n; /* used for header comments */ |
|
const char *start; /* start of the string to process */ |
const char *start; /* start of the string to process */ |
char *stesc; /* start of an escape sequence ('\\') */ |
char *stesc; /* start of an escape sequence ('\\') */ |
const char *esct; /* type of esccape sequence */ |
const char *esct; /* type of esccape sequence */ |
char *ep; /* end of comment string */ |
|
const char *stnam; /* start of the name, after "[(*" */ |
const char *stnam; /* start of the name, after "[(*" */ |
const char *cp; /* end of the name, e.g. before ']' */ |
const char *cp; /* end of the name, e.g. before ']' */ |
const char *res; /* the string to be substituted */ |
const char *res; /* the string to be substituted */ |
Line 1256 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
Line 1351 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
int npos; /* position in numeric expression */ |
int npos; /* position in numeric expression */ |
int arg_complete; /* argument not interrupted by eol */ |
int arg_complete; /* argument not interrupted by eol */ |
int quote_args; /* true for \\$@, false for \\$* */ |
int quote_args; /* true for \\$@, false for \\$* */ |
int done; /* no more input available */ |
|
int deftype; /* type of definition to paste */ |
int deftype; /* type of definition to paste */ |
int rcsid; /* kind of RCS id seen */ |
|
enum mandocerr err; /* for escape sequence problems */ |
enum mandocerr err; /* for escape sequence problems */ |
char sign; /* increment number register */ |
char sign; /* increment number register */ |
char term; /* character terminating the escape */ |
char term; /* character terminating the escape */ |
|
|
/* Search forward for comments. */ |
|
|
|
done = 0; |
|
start = buf->buf + pos; |
start = buf->buf + pos; |
for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { |
stesc = strchr(start, '\0') - 1; |
if (stesc[0] != newesc || stesc[1] == '\0') |
if (stesc >= start && *stesc == '\n') |
continue; |
|
stesc++; |
|
if (*stesc != '"' && *stesc != '#') |
|
continue; |
|
|
|
/* Comment found, look for RCS id. */ |
|
|
|
rcsid = 0; |
|
if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) { |
|
rcsid = 1 << MANDOC_OS_OPENBSD; |
|
cp += 8; |
|
} else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) { |
|
rcsid = 1 << MANDOC_OS_NETBSD; |
|
cp += 7; |
|
} |
|
if (cp != NULL && |
|
isalnum((unsigned char)*cp) == 0 && |
|
strchr(cp, '$') != NULL) { |
|
if (r->man->meta.rcsids & rcsid) |
|
mandoc_msg(MANDOCERR_RCS_REP, ln, |
|
(int)(stesc - buf->buf) + 1, |
|
"%s", stesc + 1); |
|
r->man->meta.rcsids |= rcsid; |
|
} |
|
|
|
/* Handle trailing whitespace. */ |
|
|
|
ep = strchr(stesc--, '\0') - 1; |
|
if (*ep == '\n') { |
|
done = 1; |
|
ep--; |
|
} |
|
if (*ep == ' ' || *ep == '\t') |
|
mandoc_msg(MANDOCERR_SPACE_EOL, |
|
ln, (int)(ep - buf->buf), NULL); |
|
|
|
/* |
|
* Save comments preceding the title macro |
|
* in the syntax tree. |
|
*/ |
|
|
|
if (newesc != ASCII_ESC && r->options & MPARSE_COMMENT) { |
|
while (*ep == ' ' || *ep == '\t') |
|
ep--; |
|
ep[1] = '\0'; |
|
n = roff_node_alloc(r->man, |
|
ln, stesc + 1 - buf->buf, |
|
ROFFT_COMMENT, TOKEN_NONE); |
|
n->string = mandoc_strdup(stesc + 2); |
|
roff_node_append(r->man, n); |
|
n->flags |= NODE_VALID | NODE_ENDED; |
|
r->man->next = ROFF_NEXT_SIBLING; |
|
} |
|
|
|
/* Line continuation with comment. */ |
|
|
|
if (stesc[1] == '#') { |
|
*stesc = '\0'; |
|
return ROFF_IGN | ROFF_APPEND; |
|
} |
|
|
|
/* Discard normal comments. */ |
|
|
|
while (stesc > start && stesc[-1] == ' ' && |
|
(stesc == start + 1 || stesc[-2] != '\\')) |
|
stesc--; |
|
*stesc = '\0'; |
|
break; |
|
} |
|
if (stesc == start) |
|
return ROFF_CONT; |
|
stesc--; |
|
|
|
/* Notice the end of the input. */ |
|
|
|
if (*stesc == '\n') { |
|
*stesc-- = '\0'; |
*stesc-- = '\0'; |
done = 1; |
|
} |
|
|
|
expand_count = 0; |
expand_count = 0; |
while (stesc >= start) { |
while (stesc >= start) { |
Line 1386 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
Line 1398 roff_expand(struct roff *r, struct buf *buf, int ln, i |
|
while (stesc > cp) |
while (stesc > cp) |
*stesc-- = '\\'; |
*stesc-- = '\\'; |
continue; |
continue; |
} else if (stesc[1] != '\0') { |
} else if (stesc[1] == '\0') { |
*stesc = '\\'; |
|
} else { |
|
*stesc-- = '\0'; |
*stesc-- = '\0'; |
if (done) |
continue; |
continue; |
} else |
else |
*stesc = '\\'; |
return ROFF_IGN | ROFF_APPEND; |
|
} |
|
|
|
/* Decide whether to expand or to check only. */ |
/* Decide whether to expand or to check only. */ |
|
|
term = '\0'; |
term = '\0'; |
cp = stesc + 1; |
cp = stesc + 1; |
if (*cp == 'E') |
while (*cp == 'E') |
cp++; |
cp++; |
esct = cp; |
esct = cp; |
switch (*esct) { |
switch (*esct) { |
Line 1853 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
Line 1861 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
assert(e == ROFF_CONT); |
assert(e == ROFF_CONT); |
} |
} |
|
|
/* Expand some escape sequences. */ |
/* Handle comments and escape sequences. */ |
|
|
|
e = roff_parse_comment(r, buf, ln, pos, r->escape); |
|
if ((e & ROFF_MASK) == ROFF_IGN) |
|
return e; |
|
assert(e == ROFF_CONT); |
|
|
e = roff_expand(r, buf, ln, pos, r->escape); |
e = roff_expand(r, buf, ln, pos, r->escape); |
if ((e & ROFF_MASK) == ROFF_IGN) |
if ((e & ROFF_MASK) == ROFF_IGN) |
return e; |
return e; |
Line 1903 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
Line 1916 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
/* |
/* |
* If a scope is open, go to the child handler for that macro, |
* If a scope is open, go to the child handler for that macro, |
* as it may want to preprocess before doing anything with it. |
* as it may want to preprocess before doing anything with it. |
* Don't do so if an equation is open. |
|
*/ |
*/ |
|
|
if (r->last) { |
if (r->last) { |
Line 1911 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
Line 1923 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs); |
return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs); |
} |
} |
|
|
/* No scope is open. This is a new request or macro. */ |
|
|
|
r->options &= ~MPARSE_COMMENT; |
r->options &= ~MPARSE_COMMENT; |
spos = pos; |
spos = pos; |
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
|
return roff_req_or_macro(r, t, buf, ln, spos, pos, offs); |
|
} |
|
|
/* Tables ignore most macros. */ |
/* |
|
* Handle a new request or macro. |
|
* May be called outside any scope or from inside a conditional scope. |
|
*/ |
|
static int |
|
roff_req_or_macro(ROFF_ARGS) { |
|
|
if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || |
/* For now, tables ignore most macros and some request. */ |
t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { |
|
|
if (r->tbl != NULL && (tok == TOKEN_NONE || tok == ROFF_TS || |
|
tok == ROFF_br || tok == ROFF_ce || tok == ROFF_rj || |
|
tok == ROFF_sp)) { |
mandoc_msg(MANDOCERR_TBLMACRO, |
mandoc_msg(MANDOCERR_TBLMACRO, |
ln, pos, "%s", buf->buf + spos); |
ln, ppos, "%s", buf->buf + ppos); |
if (t != TOKEN_NONE) |
if (tok != TOKEN_NONE) |
return ROFF_IGN; |
return ROFF_IGN; |
while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') |
while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') |
pos++; |
pos++; |
Line 1936 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
Line 1956 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
|
|
/* For now, let high level macros abort .ce mode. */ |
/* For now, let high level macros abort .ce mode. */ |
|
|
if (ctl && roffce_node != NULL && |
if (roffce_node != NULL && |
(t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || |
(tok == TOKEN_NONE || tok == ROFF_Dd || tok == ROFF_EQ || |
t == ROFF_TH || t == ROFF_TS)) { |
tok == ROFF_TH || tok == ROFF_TS)) { |
r->man->last = roffce_node; |
r->man->last = roffce_node; |
r->man->next = ROFF_NEXT_SIBLING; |
r->man->next = ROFF_NEXT_SIBLING; |
roffce_lines = 0; |
roffce_lines = 0; |
Line 1950 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
Line 1970 roff_parseln(struct roff *r, int ln, struct buf *buf, |
|
* Let the standard macro set parsers handle it. |
* Let the standard macro set parsers handle it. |
*/ |
*/ |
|
|
if (t == TOKEN_NONE) |
if (tok == TOKEN_NONE) |
return ROFF_CONT; |
return ROFF_CONT; |
|
|
/* Execute a roff request or a user defined macro. */ |
/* Execute a roff request or a user-defined macro. */ |
|
|
return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); |
return (*roffs[tok].proc)(r, tok, buf, ln, ppos, pos, offs); |
} |
} |
|
|
/* |
/* |
Line 1998 roff_endparse(struct roff *r) |
|
Line 2018 roff_endparse(struct roff *r) |
|
} |
} |
|
|
/* |
/* |
* Parse a roff node's type from the input buffer. This must be in the |
* Parse the request or macro name at buf[*pos]. |
* form of ".foo xxx" in the usual way. |
* Return ROFF_RENAMED, ROFF_USERDEF, or a ROFF_* token value. |
|
* For empty, undefined, mdoc(7), and man(7) macros, return TOKEN_NONE. |
|
* As a side effect, set r->current_string to the definition or to NULL. |
*/ |
*/ |
static enum roff_tok |
static enum roff_tok |
roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) |
roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) |
Line 2274 roff_block_sub(ROFF_ARGS) |
|
Line 2296 roff_block_sub(ROFF_ARGS) |
|
int i, j; |
int i, j; |
|
|
/* |
/* |
* First check whether a custom macro exists at this level. If |
* If a custom end marker is a user-defined or predefined macro |
* it does, then check against it. This is some of groff's |
* or a request, interpret it. |
* stranger behaviours. If we encountered a custom end-scope |
|
* tag and that tag also happens to be a "real" macro, then we |
|
* need to try interpreting it again as a real macro. If it's |
|
* not, then return ignore. Else continue. |
|
*/ |
*/ |
|
|
if (r->last->end) { |
if (r->last->end) { |
Line 2305 roff_block_sub(ROFF_ARGS) |
|
Line 2323 roff_block_sub(ROFF_ARGS) |
|
} |
} |
} |
} |
|
|
/* |
/* Handle the standard end marker. */ |
* If we have no custom end-query or lookup failed, then try |
|
* pulling it out of the hashtable. |
|
*/ |
|
|
|
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
|
if (t == ROFF_cblock) |
|
return roff_cblock(r, t, buf, ln, ppos, pos, offs); |
|
|
if (t != ROFF_cblock) { |
/* Not an end marker, so append the line to the block. */ |
if (tok != ROFF_ig) |
|
roff_setstr(r, r->last->name, buf->buf + ppos, 2); |
|
return ROFF_IGN; |
|
} |
|
|
|
return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); |
if (tok != ROFF_ig) |
|
roff_setstr(r, r->last->name, buf->buf + ppos, 2); |
|
return ROFF_IGN; |
} |
} |
|
|
static int |
static int |
|
|
roff_cond_sub(ROFF_ARGS) |
roff_cond_sub(ROFF_ARGS) |
{ |
{ |
struct roffnode *bl; |
struct roffnode *bl; |
int irc, rr; |
int irc, rr, spos; |
enum roff_tok t; |
enum roff_tok t; |
|
|
rr = 0; /* If arguments follow "\}", skip them. */ |
rr = 0; /* If arguments follow "\}", skip them. */ |
irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr); |
irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr); |
|
spos = pos; |
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
t = roff_parse(r, buf->buf, &pos, ln, ppos); |
|
|
/* For now, let high level macros abort .ce mode. */ |
|
|
|
if (roffce_node != NULL && |
|
(t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || |
|
t == ROFF_TH || t == ROFF_TS)) { |
|
r->man->last = roffce_node; |
|
r->man->next = ROFF_NEXT_SIBLING; |
|
roffce_lines = 0; |
|
roffce_node = NULL; |
|
} |
|
|
|
/* |
/* |
* Fully handle known macros when they are structurally |
* Handle requests and macros if the conditional evaluated |
* required or when the conditional evaluated to true. |
* to true or if they are structurally required. |
|
* The .break request is always handled specially. |
*/ |
*/ |
|
|
if (t == ROFF_break) { |
if (t == ROFF_break) { |
Line 2431 roff_cond_sub(ROFF_ARGS) |
|
Line 2437 roff_cond_sub(ROFF_ARGS) |
|
break; |
break; |
} |
} |
} |
} |
} else if (t != TOKEN_NONE && |
} else if (rr || (t < TOKEN_NONE && roffs[t].flags & ROFFMAC_STRUCT)) { |
(rr || roffs[t].flags & ROFFMAC_STRUCT)) |
irc |= roff_req_or_macro(r, t, buf, ln, spos, pos, offs); |
irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); |
if (irc & ROFF_WHILE) |
else |
irc &= ~(ROFF_LOOPCONT | ROFF_LOOPEXIT); |
irc |= rr ? ROFF_CONT : ROFF_IGN; |
} |
return irc; |
return irc; |
} |
} |
|
|
Line 3729 roff_eo(ROFF_ARGS) |
|
Line 3735 roff_eo(ROFF_ARGS) |
|
} |
} |
|
|
static int |
static int |
|
roff_mc(ROFF_ARGS) |
|
{ |
|
struct roff_node *n; |
|
char *cp; |
|
|
|
/* Parse the first argument. */ |
|
|
|
cp = buf->buf + pos; |
|
if (*cp != '\0') |
|
cp++; |
|
if (buf->buf[pos] == '\\') { |
|
switch (mandoc_escape((const char **)&cp, NULL, NULL)) { |
|
case ESCAPE_SPECIAL: |
|
case ESCAPE_UNICODE: |
|
case ESCAPE_NUMBERED: |
|
break; |
|
default: |
|
*cp = '\0'; |
|
mandoc_msg(MANDOCERR_MC_ESC, ln, pos, |
|
"mc %s", buf->buf + pos); |
|
buf->buf[pos] = '\0'; |
|
break; |
|
} |
|
} |
|
|
|
/* Ignore additional arguments. */ |
|
|
|
while (*cp == ' ') |
|
*cp++ = '\0'; |
|
if (*cp != '\0') { |
|
mandoc_msg(MANDOCERR_MC_DIST, ln, (int)(cp - buf->buf), |
|
"mc ... %s", cp); |
|
*cp = '\0'; |
|
} |
|
|
|
/* Create the .mc node. */ |
|
|
|
roff_elem_alloc(r->man, ln, ppos, tok); |
|
n = r->man->last; |
|
if (buf->buf[pos] != '\0') |
|
roff_word_alloc(r->man, ln, pos, buf->buf + pos); |
|
n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; |
|
r->man->last = n; |
|
r->man->next = ROFF_NEXT_SIBLING; |
|
return ROFF_IGN; |
|
} |
|
|
|
static int |
roff_nop(ROFF_ARGS) |
roff_nop(ROFF_ARGS) |
{ |
{ |
while (buf->buf[pos] == ' ') |
while (buf->buf[pos] == ' ') |
|
|
roff_shift(ROFF_ARGS) |
roff_shift(ROFF_ARGS) |
{ |
{ |
struct mctx *ctx; |
struct mctx *ctx; |
int levels, i; |
int argpos, levels, i; |
|
|
|
argpos = pos; |
levels = 1; |
levels = 1; |
if (buf->buf[pos] != '\0' && |
if (buf->buf[pos] != '\0' && |
roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) { |
roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) { |
Line 3885 roff_shift(ROFF_ARGS) |
|
Line 3940 roff_shift(ROFF_ARGS) |
|
ctx = r->mstack + r->mstackpos; |
ctx = r->mstack + r->mstackpos; |
if (levels > ctx->argc) { |
if (levels > ctx->argc) { |
mandoc_msg(MANDOCERR_SHIFT, |
mandoc_msg(MANDOCERR_SHIFT, |
ln, pos, "%d, but max is %d", levels, ctx->argc); |
ln, argpos, "%d, but max is %d", levels, ctx->argc); |
levels = ctx->argc; |
levels = ctx->argc; |
} |
} |
|
if (levels < 0) { |
|
mandoc_msg(MANDOCERR_ARG_NEG, ln, argpos, "shift %d", levels); |
|
levels = 0; |
|
} |
if (levels == 0) |
if (levels == 0) |
return ROFF_IGN; |
return ROFF_IGN; |
for (i = 0; i < levels; i++) |
for (i = 0; i < levels; i++) |
Line 3949 roff_userdef(ROFF_ARGS) |
|
Line 4008 roff_userdef(ROFF_ARGS) |
|
r->mstacksz += 8; |
r->mstacksz += 8; |
} |
} |
ctx = r->mstack + r->mstackpos; |
ctx = r->mstack + r->mstackpos; |
ctx->argsz = 0; |
|
ctx->argc = 0; |
ctx->argc = 0; |
ctx->argv = NULL; |
|
|
|
/* |
/* |
* Collect pointers to macro argument strings, |
* Collect pointers to macro argument strings, |