version 1.204, 2014/04/07 15:07:13 |
version 1.206, 2014/04/08 01:37:27 |
Line 485 roff_alloc(struct mparse *parse, int options) |
|
Line 485 roff_alloc(struct mparse *parse, int options) |
|
} |
} |
|
|
/* |
/* |
* In the current line, expand user-defined strings ("\*") |
* In the current line, expand escape sequences that tend to get |
* and references to number registers ("\n"). |
* used in numerical expressions and conditional requests. |
* Also check the syntax of other escape sequences. |
* Also check the syntax of the remaining escape sequences. |
*/ |
*/ |
static enum rofferr |
static enum rofferr |
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) |
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) |
{ |
{ |
char ubuf[12]; /* buffer to print the number */ |
char ubuf[12]; /* buffer to print the number */ |
|
const char *start; /* start of the string to process */ |
const char *stesc; /* start of an escape sequence ('\\') */ |
const char *stesc; /* start of an escape sequence ('\\') */ |
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 */ |
char *nbuf; /* new buffer to copy bufp to */ |
char *nbuf; /* new buffer to copy bufp to */ |
size_t nsz; /* size of the new buffer */ |
|
size_t maxl; /* expected length of the escape name */ |
size_t maxl; /* expected length of the escape name */ |
size_t naml; /* actual length of the escape name */ |
size_t naml; /* actual length of the escape name */ |
|
size_t ressz; /* size of the replacement string */ |
int expand_count; /* to avoid infinite loops */ |
int expand_count; /* to avoid infinite loops */ |
|
int npos; /* position in numeric expression */ |
|
int irc; /* return code from roff_evalnum() */ |
|
char term; /* character terminating the escape */ |
|
|
expand_count = 0; |
expand_count = 0; |
|
start = *bufp + pos; |
|
stesc = strchr(start, '\0') - 1; |
|
while (stesc-- > start) { |
|
|
again: |
/* Search backwards for the next backslash. */ |
cp = *bufp + pos; |
|
while (NULL != (cp = strchr(cp, '\\'))) { |
|
stesc = cp++; |
|
|
|
/* |
if ('\\' != *stesc) |
* The second character must be an asterisk or an n. |
continue; |
* If it isn't, skip it anyway: It is escaped, |
|
* so it can't start another escape sequence. |
|
*/ |
|
|
|
if ('\0' == *cp) |
/* If it is escaped, skip it. */ |
return(ROFF_CONT); |
|
|
|
|
for (cp = stesc - 1; cp >= start; cp--) |
|
if ('\\' != *cp) |
|
break; |
|
|
|
if (0 == (stesc - cp) % 2) { |
|
stesc = cp; |
|
continue; |
|
} |
|
|
|
/* Decide whether to expand or to check only. */ |
|
|
|
term = '\0'; |
|
cp = stesc + 1; |
switch (*cp) { |
switch (*cp) { |
case ('*'): |
case ('*'): |
res = NULL; |
res = NULL; |
break; |
break; |
|
case ('B'): |
|
/* FALLTHROUGH */ |
|
case ('w'): |
|
term = cp[1]; |
|
/* FALLTHROUGH */ |
case ('n'): |
case ('n'): |
res = ubuf; |
res = ubuf; |
break; |
break; |
default: |
default: |
if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL)) |
if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) |
continue; |
mandoc_msg(MANDOCERR_BADESCAPE, r->parse, |
mandoc_msg |
ln, (int)(stesc - *bufp), NULL); |
(MANDOCERR_BADESCAPE, r->parse, |
continue; |
ln, (int)(stesc - *bufp), NULL); |
|
return(ROFF_CONT); |
|
} |
} |
|
|
cp++; |
if (EXPAND_LIMIT < ++expand_count) { |
|
mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, |
|
ln, (int)(stesc - *bufp), NULL); |
|
return(ROFF_IGN); |
|
} |
|
|
/* |
/* |
* The third character decides the length |
* The third character decides the length |
|
|
* Save a pointer to the name. |
* Save a pointer to the name. |
*/ |
*/ |
|
|
switch (*cp) { |
if ('\0' == term) { |
case ('\0'): |
switch (*++cp) { |
return(ROFF_CONT); |
case ('\0'): |
case ('('): |
maxl = 0; |
cp++; |
break; |
maxl = 2; |
case ('('): |
break; |
cp++; |
case ('['): |
maxl = 2; |
cp++; |
break; |
|
case ('['): |
|
cp++; |
|
term = ']'; |
|
maxl = 0; |
|
break; |
|
default: |
|
maxl = 1; |
|
break; |
|
} |
|
} else { |
|
cp += 2; |
maxl = 0; |
maxl = 0; |
break; |
|
default: |
|
maxl = 1; |
|
break; |
|
} |
} |
stnam = cp; |
stnam = cp; |
|
|
|
|
(MANDOCERR_BADESCAPE, |
(MANDOCERR_BADESCAPE, |
r->parse, ln, |
r->parse, ln, |
(int)(stesc - *bufp), NULL); |
(int)(stesc - *bufp), NULL); |
return(ROFF_CONT); |
break; |
} |
} |
if (0 == maxl && ']' == *cp) |
if (0 == maxl && *cp == term) { |
|
cp++; |
break; |
break; |
|
} |
} |
} |
|
|
/* |
/* |
|
|
* undefined, resume searching for escapes. |
* undefined, resume searching for escapes. |
*/ |
*/ |
|
|
if (NULL == res) |
switch (stesc[1]) { |
|
case ('*'): |
res = roff_getstrn(r, stnam, naml); |
res = roff_getstrn(r, stnam, naml); |
else |
break; |
|
case ('B'): |
|
npos = 0; |
|
irc = roff_evalnum(stnam, &npos, NULL, 0); |
|
ubuf[0] = irc && stnam + npos + 1 == cp |
|
? '1' : '0'; |
|
ubuf[1] = '\0'; |
|
break; |
|
case ('n'): |
snprintf(ubuf, sizeof(ubuf), "%d", |
snprintf(ubuf, sizeof(ubuf), "%d", |
roff_getregn(r, stnam, naml)); |
roff_getregn(r, stnam, naml)); |
|
break; |
|
case ('w'): |
|
snprintf(ubuf, sizeof(ubuf), "%d", |
|
24 * (int)naml); |
|
break; |
|
} |
|
|
if (NULL == res) { |
if (NULL == res) { |
mandoc_msg |
mandoc_msg |
|
|
ln, (int)(stesc - *bufp), NULL); |
ln, (int)(stesc - *bufp), NULL); |
res = ""; |
res = ""; |
} |
} |
|
ressz = strlen(res); |
|
|
/* Replace the escape sequence by the string. */ |
/* Replace the escape sequence by the string. */ |
|
|
pos = stesc - *bufp; |
*szp += ressz + 1; |
|
nbuf = mandoc_malloc(*szp); |
|
|
nsz = *szp + strlen(res) + 1; |
|
nbuf = mandoc_malloc(nsz); |
|
|
|
strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1)); |
strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1)); |
strlcat(nbuf, res, nsz); |
strlcat(nbuf, res, *szp); |
strlcat(nbuf, cp + (maxl ? 0 : 1), nsz); |
strlcat(nbuf, cp, *szp); |
|
|
free(*bufp); |
/* Prepare for the next replacement. */ |
|
|
|
start = nbuf + pos; |
|
stesc = nbuf + (stesc - *bufp) + ressz; |
|
free(*bufp); |
*bufp = nbuf; |
*bufp = nbuf; |
*szp = nsz; |
|
|
|
if (EXPAND_LIMIT >= ++expand_count) |
|
goto again; |
|
|
|
/* Just leave the string unexpanded. */ |
|
mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL); |
|
return(ROFF_IGN); |
|
} |
} |
return(ROFF_CONT); |
return(ROFF_CONT); |
} |
} |
Line 1118 roff_cond_text(ROFF_ARGS) |
|
Line 1156 roff_cond_text(ROFF_ARGS) |
|
static int |
static int |
roff_getnum(const char *v, int *pos, int *res) |
roff_getnum(const char *v, int *pos, int *res) |
{ |
{ |
int p, n; |
int myres, n, p; |
|
|
|
if (NULL == res) |
|
res = &myres; |
|
|
p = *pos; |
p = *pos; |
n = v[p] == '-'; |
n = v[p] == '-'; |
if (n) |
if (n) |
Line 1422 roff_evalpar(const char *v, int *pos, int *res) |
|
Line 1463 roff_evalpar(const char *v, int *pos, int *res) |
|
if ( ! roff_evalnum(v, pos, res, 1)) |
if ( ! roff_evalnum(v, pos, res, 1)) |
return(0); |
return(0); |
|
|
/* If the trailing parenthesis is missing, ignore the error. */ |
/* |
|
* Omission of the closing parenthesis |
|
* is an error in validation mode, |
|
* but ignored in evaluation mode. |
|
*/ |
|
|
if (')' == v[*pos]) |
if (')' == v[*pos]) |
(*pos)++; |
(*pos)++; |
|
else if (NULL == res) |
|
return(0); |
|
|
return(1); |
return(1); |
} |
} |
Line 1469 roff_evalnum(const char *v, int *pos, int *res, int sk |
|
Line 1517 roff_evalnum(const char *v, int *pos, int *res, int sk |
|
if (skipwhite) |
if (skipwhite) |
while (isspace((unsigned char)v[*pos])) |
while (isspace((unsigned char)v[*pos])) |
(*pos)++; |
(*pos)++; |
|
|
|
if (NULL == res) |
|
continue; |
|
|
switch (operator) { |
switch (operator) { |
case ('+'): |
case ('+'): |