version 1.204, 2014/04/07 15:07:13 |
version 1.205, 2014/04/07 21:00:08 |
Line 493 static enum rofferr |
|
Line 493 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 */ |
|
|
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) |
|
continue; |
|
|
|
/* If it is escaped, skip it. */ |
|
|
|
for (cp = stesc - 1; cp >= start; cp--) |
|
if ('\\' != *cp) |
|
break; |
|
|
|
if (0 == (stesc - cp) % 2) { |
|
stesc = cp; |
|
continue; |
|
} |
|
|
/* |
/* |
* The second character must be an asterisk or an n. |
* Everything except user-defined strings and number |
* If it isn't, skip it anyway: It is escaped, |
* registers is only checked, not expanded. |
* so it can't start another escape sequence. |
|
*/ |
*/ |
|
|
if ('\0' == *cp) |
cp = stesc + 1; |
return(ROFF_CONT); |
|
|
|
switch (*cp) { |
switch (*cp) { |
case ('*'): |
case ('*'): |
res = NULL; |
res = NULL; |
|
|
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) { |
switch (*++cp) { |
case ('\0'): |
case ('\0'): |
return(ROFF_CONT); |
continue; |
case ('('): |
case ('('): |
cp++; |
cp++; |
maxl = 2; |
maxl = 2; |
|
|
(MANDOCERR_BADESCAPE, |
(MANDOCERR_BADESCAPE, |
r->parse, ln, |
r->parse, ln, |
(int)(stesc - *bufp), NULL); |
(int)(stesc - *bufp), NULL); |
return(ROFF_CONT); |
continue; |
} |
} |
if (0 == maxl && ']' == *cp) |
if (0 == maxl && ']' == *cp) |
break; |
break; |
|
|
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 + (maxl ? 0 : 1), *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); |
} |
} |