version 1.24, 2006/07/21 00:21:52 |
version 1.25, 2006/07/21 00:47:35 |
|
|
static BUF * |
static BUF * |
rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) |
rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) |
{ |
{ |
BUF *newbuf; |
ptrdiff_t c_offset, sizdiff, start_offset; |
|
size_t i; |
int kwtype; |
int kwtype; |
u_int j, found; |
u_int j, found; |
u_char *c, *kwstr, *start, *end, *fin; |
u_char *c, *data, *kwstr, *start, *end, *tbuf, *fin; |
char expbuf[256], buf[256]; |
char expbuf[256], buf[256]; |
struct tm tb; |
struct tm tb; |
char *fmt; |
char *fmt; |
size_t len; |
size_t len, tbuflen; |
|
|
kwtype = 0; |
kwtype = 0; |
kwstr = NULL; |
kwstr = NULL; |
|
|
|
|
c = rcs_buf_get(bp); |
c = rcs_buf_get(bp); |
found = 0; |
found = 0; |
/* Final character in buffer. */ |
for (i = 0; i < len; i++) { |
fin = c + len - 1; |
|
|
|
/* If no keywords exist, return original BUF. */ |
|
while (c < fin && !found) { |
|
if (*c == '$') { |
if (*c == '$') { |
size_t clen; |
|
|
|
/* Skip initial `$'. */ |
|
c++; |
c++; |
/* Number of characters between c and fin, inclusive. */ |
i++; |
clen = fin - c + 1; |
|
for (j = 0; j < RCS_NKWORDS; j++) { |
for (j = 0; j < RCS_NKWORDS; j++) { |
size_t kwlen; |
if (!strncmp(c, rcs_expkw[j].kw_str, |
|
strlen(rcs_expkw[j].kw_str))) { |
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; |
found = 1; |
kwstr = rcs_expkw[j].kw_str; |
kwstr = rcs_expkw[j].kw_str; |
kwtype = rcs_expkw[j].kw_type; |
kwtype = rcs_expkw[j].kw_type; |
|
|
if (found == 0) |
if (found == 0) |
return (bp); |
return (bp); |
|
|
/* If no keywords are found, return original buffer. */ |
rcs_buf_putc(bp, '\0'); |
newbuf = bp; |
data = rcs_buf_release(bp); |
|
c = data; |
|
fin = c + len; |
|
len++; |
|
|
/* |
/* |
* Keyword formats: |
* Keyword formats: |
|
|
*/ |
*/ |
for (; c < fin; c++) { |
for (; c < fin; c++) { |
if (*c == '$') { |
if (*c == '$') { |
BUF *tmpbuf; |
|
size_t clen; |
|
|
|
/* remember start of this possible keyword */ |
/* remember start of this possible keyword */ |
start = c; |
start = c; |
|
start_offset = start - data; |
|
|
/* first following character has to be alphanumeric */ |
/* first following character has to be alphanumeric */ |
c++; |
c++; |
|
|
continue; |
continue; |
} |
} |
|
|
/* Number of characters between c and fin, inclusive. */ |
|
clen = fin - c + 1; |
|
|
|
/* look for any matching keywords */ |
/* look for any matching keywords */ |
found = 0; |
found = 0; |
for (j = 0; j < RCS_NKWORDS; j++) { |
for (j = 0; j < RCS_NKWORDS; j++) { |
size_t kwlen; |
if (!strncmp(c, rcs_expkw[j].kw_str, |
|
strlen(rcs_expkw[j].kw_str))) { |
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; |
found = 1; |
kwstr = rcs_expkw[j].kw_str; |
kwstr = rcs_expkw[j].kw_str; |
kwtype = rcs_expkw[j].kw_type; |
kwtype = rcs_expkw[j].kw_type; |
c += kwlen; |
|
break; |
break; |
} |
} |
} |
} |
|
|
continue; |
continue; |
} |
} |
|
|
|
/* next character has to be ':' or '$' */ |
|
c += strlen(kwstr); |
|
if (*c != ':' && *c != '$') { |
|
c = start; |
|
continue; |
|
} |
|
|
/* |
/* |
* if the next character was ':' we need to look for |
* if the next character was ':' we need to look for |
* an '$' before the end of the line to be sure it is |
* an '$' before the end of the line to be sure it is |
* in fact a keyword. |
* in fact a keyword. |
*/ |
*/ |
if (*c == ':') { |
if (*c == ':') { |
for (; c <= fin; ++c) { |
while (*c++) { |
if (*c == '$' || *c == '\n') |
if (*c == '$' || *c == '\n') |
break; |
break; |
} |
} |
|
|
continue; |
continue; |
} |
} |
} |
} |
|
c_offset = c - data; |
end = c + 1; |
end = c + 1; |
|
|
/* start constructing the expansion */ |
/* start constructing the expansion */ |
|
|
if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf)) |
if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf)) |
errx(1, "rcs_expand_keywords: string truncated"); |
errx(1, "rcs_expand_keywords: string truncated"); |
|
|
/* Concatenate everything together. */ |
sizdiff = strlen(expbuf) - (end - start); |
tmpbuf = rcs_buf_alloc(len + strlen(expbuf), BUF_AUTOEXT); |
tbuflen = fin - end; |
/* Append everything before keyword. */ |
tbuf = xmalloc(tbuflen); |
rcs_buf_append(tmpbuf, rcs_buf_get(newbuf), |
memcpy(tbuf, end, tbuflen); |
start - (unsigned char *)rcs_buf_get(newbuf)); |
/* only realloc if we have to */ |
/* Append keyword. */ |
if (sizdiff > 0) { |
rcs_buf_append(tmpbuf, expbuf, strlen(expbuf)); |
char *newdata; |
/* Point c to end of keyword. */ |
|
c = rcs_buf_get(tmpbuf) + rcs_buf_len(tmpbuf) - 1; |
|
/* Append everything after keyword. */ |
|
rcs_buf_append(tmpbuf, end, |
|
((unsigned char *)rcs_buf_get(newbuf) + rcs_buf_len(newbuf)) - end); |
|
/* Point fin to end of data. */ |
|
fin = rcs_buf_get(tmpbuf) + rcs_buf_len(tmpbuf) - 1; |
|
|
|
/* tmpbuf is now ready, free old newbuf if allocated here. */ |
len += sizdiff; |
if (newbuf != bp) |
newdata = xrealloc(data, 1, len); |
rcs_buf_free(newbuf); |
data = newdata; |
newbuf = tmpbuf; |
/* |
|
* ensure string pointers are not invalidated |
|
* after realloc() |
|
*/ |
|
start = data + start_offset; |
|
fin = data + len; |
|
c = data + c_offset; |
|
} |
|
memcpy(start, expbuf, strlen(expbuf) + 1); |
|
start += strlen(expbuf); |
|
memcpy(start, tbuf, tbuflen); |
|
xfree(tbuf); |
|
c = start + strlen(expbuf); |
} |
} |
} |
} |
|
|
return (newbuf); |
bp = rcs_buf_alloc(len - 1, BUF_AUTOEXT); |
|
rcs_buf_set(bp, data, len - 1, 0); |
|
xfree(data); |
|
|
|
return (bp); |
} |
} |
|
|
/* |
/* |