version 1.76, 2011/05/20 19:21:10 |
version 1.77, 2011/07/06 15:36:52 |
|
|
struct rcs_kw rcs_expkw[] = { |
struct rcs_kw rcs_expkw[] = { |
{ "Author", RCS_KW_AUTHOR }, |
{ "Author", RCS_KW_AUTHOR }, |
{ "Date", RCS_KW_DATE }, |
{ "Date", RCS_KW_DATE }, |
|
{ "Locker", RCS_KW_LOCKER }, |
{ "Header", RCS_KW_HEADER }, |
{ "Header", RCS_KW_HEADER }, |
{ "Id", RCS_KW_ID }, |
{ "Id", RCS_KW_ID }, |
{ "OpenBSD", RCS_KW_ID }, |
{ "OpenBSD", RCS_KW_ID }, |
|
|
* On error, return NULL. |
* On error, return NULL. |
*/ |
*/ |
static BUF * |
static BUF * |
rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) |
rcs_expand_keywords(char *rcsfile_in, struct rcs_delta *rdp, BUF *bp, int mode) |
{ |
{ |
BUF *newbuf; |
BUF *newbuf; |
|
u_char *c, *kw, *fin; |
|
char buf[256], *tmpf, resolved[MAXPATHLEN], *rcsfile; |
|
u_char *line, *line2; |
|
u_int i, j; |
int kwtype; |
int kwtype; |
u_int j, found; |
int found; |
u_char *c, *kwstr, *start, *end, *fin; |
|
char expbuf[256], buf[256]; |
|
struct tm tb; |
struct tm tb; |
char *fmt; |
|
size_t len; |
|
|
|
kwtype = 0; |
|
kwstr = NULL; |
|
|
|
/* |
|
* -z support for RCS |
|
*/ |
|
tb = rdp->rd_date; |
tb = rdp->rd_date; |
if (timezone_flag != NULL) |
if (timezone_flag != NULL) |
rcs_set_tz(timezone_flag, rdp, &tb); |
rcs_set_tz(timezone_flag, rdp, &tb); |
|
|
len = buf_len(bp); |
if (realpath(rcsfile_in, resolved) == NULL) |
|
rcsfile = rcsfile_in; |
|
else |
|
rcsfile = resolved; |
|
|
c = buf_get(bp); |
newbuf = buf_alloc(buf_len(bp)); |
found = 0; |
|
/* Final character in buffer. */ |
|
fin = c + len - 1; |
|
|
|
/* If no keywords are found, return original buffer. */ |
|
newbuf = bp; |
|
|
|
/* |
/* |
* Keyword formats: |
* Keyword formats: |
* $Keyword$ |
* $Keyword$ |
* $Keyword: value$ |
* $Keyword: value$ |
*/ |
*/ |
for (; c < fin; c++) { |
c = buf_get(bp); |
if (*c == '$') { |
fin = c + buf_len(bp); |
BUF *tmpbuf; |
/* Copying to newbuf is deferred until the first keyword. */ |
size_t clen; |
found = 0; |
|
|
/* remember start of this possible keyword */ |
while (c < fin) { |
start = c; |
kw = memchr(c, '$', fin - c); |
|
if (kw == NULL) |
|
break; |
|
++kw; |
|
if (found) { |
|
/* Copy everything up to and including the $. */ |
|
buf_append(newbuf, c, kw - c); |
|
} |
|
c = kw; |
|
/* c points after the $ now. */ |
|
if (c == fin) |
|
break; |
|
if (!isalpha(*c)) /* all valid keywords start with a letter */ |
|
continue; |
|
|
/* first following character has to be alphanumeric */ |
for (i = 0; i < RCS_NKWORDS; ++i) { |
c++; |
size_t kwlen; |
if (!isalpha(*c)) { |
|
c = start; |
kwlen = strlen(rcs_expkw[i].kw_str); |
continue; |
/* |
|
* kwlen must be less than clen since clen includes |
|
* either a terminating `$' or a `:'. |
|
*/ |
|
if (c + kwlen < fin && |
|
memcmp(c , rcs_expkw[i].kw_str, kwlen) == 0 && |
|
(c[kwlen] == '$' || c[kwlen] == ':')) { |
|
c += kwlen; |
|
break; |
} |
} |
|
} |
|
if (i == RCS_NKWORDS) |
|
continue; |
|
kwtype = rcs_expkw[i].kw_type; |
|
|
/* Number of characters between c and fin, inclusive. */ |
/* |
clen = fin - c + 1; |
* If the next character is ':' we need to look for an '$' |
|
* before the end of the line to be sure it is in fact a |
/* look for any matching keywords */ |
* keyword. |
found = 0; |
*/ |
for (j = 0; j < RCS_NKWORDS; j++) { |
if (*c == ':') { |
size_t kwlen; |
for (; c < fin; ++c) { |
|
if (*c == '$' || *c == '\n') |
kwlen = strlen(rcs_expkw[j].kw_str); |
|
/* |
|
* kwlen must be less than clen since clen |
|
* includes either a terminating `$' or a `:'. |
|
*/ |
|
if (kwlen < clen && |
|
memcmp(c, rcs_expkw[j].kw_str, kwlen) == 0 && |
|
(c[kwlen] == '$' || c[kwlen] == ':')) { |
|
found = 1; |
|
kwstr = rcs_expkw[j].kw_str; |
|
kwtype = rcs_expkw[j].kw_type; |
|
c += kwlen; |
|
break; |
break; |
} |
|
} |
} |
|
|
/* unknown keyword, continue looking */ |
if (*c != '$') { |
if (found == 0) { |
if (found) |
c = start; |
buf_append(newbuf, kw, c - kw); |
continue; |
continue; |
} |
} |
|
} |
|
++c; |
|
|
/* |
if (!found) { |
* if the next character was ':' we need to look for |
found = 1; |
* an '$' before the end of the line to be sure it is |
/* Copy everything up to and including the $. */ |
* in fact a keyword. |
buf_append(newbuf, buf_get(bp), kw - buf_get(bp)); |
*/ |
} |
if (*c == ':') { |
|
for (; c <= fin; ++c) { |
|
if (*c == '$' || *c == '\n') |
|
break; |
|
} |
|
|
|
if (*c != '$') { |
if (mode & RCS_KWEXP_NAME) { |
c = start; |
buf_puts(newbuf, rcs_expkw[i].kw_str); |
continue; |
if (mode & RCS_KWEXP_VAL) |
} |
buf_puts(newbuf, ": "); |
|
} |
|
|
|
/* Order matters because of RCS_KW_ID and RCS_KW_HEADER. */ |
|
if (mode & RCS_KWEXP_VAL) { |
|
if (kwtype & (RCS_KW_RCSFILE|RCS_KW_LOG)) { |
|
if ((kwtype & RCS_KW_FULLPATH) || |
|
(tmpf = strrchr(rcsfile, '/')) == NULL) |
|
buf_puts(newbuf, rcsfile); |
|
else |
|
buf_puts(newbuf, tmpf + 1); |
|
buf_putc(newbuf, ' '); |
} |
} |
end = c + 1; |
|
|
|
/* start constructing the expansion */ |
if (kwtype & RCS_KW_REVISION) { |
expbuf[0] = '\0'; |
rcsnum_tostr(rdp->rd_num, buf, sizeof(buf)); |
|
buf_puts(newbuf, buf); |
|
buf_putc(newbuf, ' '); |
|
} |
|
|
if (mode & RCS_KWEXP_NAME) { |
if (kwtype & RCS_KW_DATE) { |
char *tmp; |
strftime(buf, sizeof(buf), |
|
"%Y/%m/%d %H:%M:%S ", &tb); |
|
buf_puts(newbuf, buf); |
|
} |
|
|
(void)xasprintf(&tmp, "$%s%s", kwstr, |
if (kwtype & RCS_KW_AUTHOR) { |
(mode & RCS_KWEXP_VAL) ? ": " : ""); |
buf_puts(newbuf, rdp->rd_author); |
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(expbuf)) |
buf_putc(newbuf, ' '); |
errx(1, "rcs_expand_keywords: string truncated"); |
|
xfree(tmp); |
|
} |
} |
|
|
/* |
if (kwtype & RCS_KW_STATE) { |
* order matters because of RCS_KW_ID and |
buf_puts(newbuf, rdp->rd_state); |
* RCS_KW_HEADER here |
buf_putc(newbuf, ' '); |
*/ |
} |
if (mode & RCS_KWEXP_VAL) { |
|
if (kwtype & RCS_KW_RCSFILE) { |
|
char *tmp; |
|
|
|
(void)xasprintf(&tmp, "%s ", |
/* Order does not matter anymore below. */ |
(kwtype & RCS_KW_FULLPATH) ? rcsfile : basename(rcsfile)); |
if (kwtype & RCS_KW_SOURCE) { |
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(expbuf)) |
buf_puts(newbuf, rcsfile); |
errx(1, "rcs_expand_keywords: string truncated"); |
buf_putc(newbuf, ' '); |
xfree(tmp); |
} |
} |
|
|
|
if (kwtype & RCS_KW_REVISION) { |
if (kwtype & RCS_KW_NAME) |
char *tmp; |
buf_putc(newbuf, ' '); |
|
|
rcsnum_tostr(rdp->rd_num, buf, sizeof(buf)); |
if ((kwtype & RCS_KW_LOCKER)) { |
(void)xasprintf(&tmp, "%s ", buf); |
if (rdp->rd_locker) { |
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(buf)) |
buf_puts(newbuf, rdp->rd_locker); |
errx(1, "rcs_expand_keywords: string truncated"); |
buf_putc(newbuf, ' '); |
xfree(tmp); |
|
} |
} |
|
} |
|
} |
|
|
if (kwtype & RCS_KW_DATE) { |
/* End the expansion. */ |
if (timezone_flag != NULL) |
if (mode & RCS_KWEXP_NAME) |
fmt = "%Y/%m/%d %H:%M:%S%z "; |
buf_putc(newbuf, '$'); |
else |
|
fmt = "%Y/%m/%d %H:%M:%S "; |
|
|
|
strftime(buf, sizeof(buf), fmt, &tb); |
if (kwtype & RCS_KW_LOG) { |
if (strlcat(expbuf, buf, sizeof(expbuf)) >= sizeof(expbuf)) |
line = memrchr(buf_get(bp), '\n', kw - buf_get(bp) - 1); |
errx(1, "rcs_expand_keywords: string truncated"); |
if (line == NULL) |
} |
line = buf_get(bp); |
|
else |
|
++line; |
|
line2 = kw - 1; |
|
while (line2 > line && line2[-1] == ' ') |
|
--line2; |
|
|
if (kwtype & RCS_KW_AUTHOR) { |
buf_putc(newbuf, '\n'); |
char *tmp; |
buf_append(newbuf, line, kw - 1 - line); |
|
buf_puts(newbuf, "Revision "); |
|
rcsnum_tostr(rdp->rd_num, buf, sizeof(buf)); |
|
buf_puts(newbuf, buf); |
|
buf_puts(newbuf, " "); |
|
strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", &tb); |
|
buf_puts(newbuf, buf); |
|
|
(void)xasprintf(&tmp, "%s ", rdp->rd_author); |
buf_puts(newbuf, " "); |
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(expbuf)) |
buf_puts(newbuf, rdp->rd_author); |
errx(1, "rcs_expand_keywords: string truncated"); |
buf_putc(newbuf, '\n'); |
xfree(tmp); |
|
} |
|
|
|
if (kwtype & RCS_KW_STATE) { |
for (i = 0; rdp->rd_log[i]; i += j) { |
char *tmp; |
j = strcspn(rdp->rd_log + i, "\n"); |
|
if (j == 0) |
(void)xasprintf(&tmp, "%s ", rdp->rd_state); |
buf_append(newbuf, line, line2 - line); |
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(expbuf)) |
else |
errx(1, "rcs_expand_keywords: string truncated"); |
buf_append(newbuf, line, kw - 1 - line); |
xfree(tmp); |
if (rdp->rd_log[i + j]) |
} |
++j; |
|
buf_append(newbuf, rdp->rd_log + i, j); |
/* order does not matter anymore below */ |
|
if (kwtype & RCS_KW_LOG) |
|
if (strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) |
|
errx(1, "rcs_expand_keywords: string truncated"); |
|
|
|
if (kwtype & RCS_KW_SOURCE) { |
|
char *tmp; |
|
|
|
(void)xasprintf(&tmp, "%s ", rcsfile); |
|
if (strlcat(expbuf, tmp, sizeof(expbuf)) >= sizeof(expbuf)) |
|
errx(1, "rcs_expand_keywords: string truncated"); |
|
xfree(tmp); |
|
} |
|
|
|
if (kwtype & RCS_KW_NAME) |
|
if (strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) |
|
errx(1, "rcs_expand_keywords: string truncated"); |
|
} |
} |
|
buf_append(newbuf, line, line2 - line); |
/* end the expansion */ |
for (j = 0; c + j < fin; ++j) { |
if (mode & RCS_KWEXP_NAME) |
if (c[j] != ' ') |
if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf)) |
break; |
errx(1, "rcs_expand_keywords: string truncated"); |
} |
|
if (c + j == fin || c[j] == '\n') |
/* Concatenate everything together. */ |
c += j; |
tmpbuf = buf_alloc(len + strlen(expbuf)); |
|
/* Append everything before keyword. */ |
|
buf_append(tmpbuf, buf_get(newbuf), |
|
start - (unsigned char *)buf_get(newbuf)); |
|
/* Append keyword. */ |
|
buf_append(tmpbuf, expbuf, strlen(expbuf)); |
|
/* Point c to end of keyword. */ |
|
c = buf_get(tmpbuf) + buf_len(tmpbuf) - 1; |
|
/* Append everything after keyword. */ |
|
buf_append(tmpbuf, end, |
|
((unsigned char *)buf_get(newbuf) + buf_len(newbuf)) - end); |
|
/* Point fin to end of data. */ |
|
fin = buf_get(tmpbuf) + buf_len(tmpbuf) - 1; |
|
/* Recalculate new length. */ |
|
len = buf_len(tmpbuf); |
|
|
|
/* tmpbuf is now ready, free old newbuf if allocated here. */ |
|
if (newbuf != bp) |
|
buf_free(newbuf); |
|
newbuf = tmpbuf; |
|
} |
} |
} |
} |
|
|
return (newbuf); |
if (found) { |
|
buf_append(newbuf, c, fin - c); |
|
buf_free(bp); |
|
return (newbuf); |
|
} else { |
|
buf_free(newbuf); |
|
return (bp); |
|
} |
} |
} |
|
|
/* |
/* |