3641 |
|
|
3642 |
|
|
3643 |
|
|
3644 |
|
/* Search for keywords in the *LEN bytes starting at *START. Return the |
3645 |
|
* struct rcs_keyword describing the keyword found, or NULL when none is found. |
3646 |
|
* On return, *START will point to the first character after the `$' |
3647 |
|
* introductin the keyword, *END will point to the trailing `$', and *LEN |
3648 |
|
* will be decremented by the number of characters *START was incremented by. |
3649 |
|
* |
3650 |
|
* Not sure how to delcare *START and *END as const here. I keep getting |
3651 |
|
* warnings. |
3652 |
|
*/ |
3653 |
|
static const struct rcs_keyword * |
3654 |
|
next_keyword (char **start, size_t *len, char **end) |
3655 |
|
{ |
3656 |
|
char *srch, *srch_next, *s = NULL; |
3657 |
|
size_t srch_len; |
3658 |
|
const struct rcs_keyword *keywords, *keyword = NULL; |
3659 |
|
|
3660 |
|
if (!config->keywords) config->keywords = new_keywords (); |
3661 |
|
keywords = config->keywords; |
3662 |
|
|
3663 |
|
srch = *start; |
3664 |
|
srch_len = *len; |
3665 |
|
TRACE (TRACE_DATA, "next_keyword: searching `%s'", srch); |
3666 |
|
while ((srch_next = memchr (srch, '$', srch_len))) |
3667 |
|
{ |
3668 |
|
const char *send; |
3669 |
|
size_t slen; |
3670 |
|
|
3671 |
|
srch_len -= (srch_next + 1) - srch; |
3672 |
|
srch = srch_next + 1; |
3673 |
|
|
3674 |
|
/* Look for the first non alphabetic character after the '$'. */ |
3675 |
|
send = srch + srch_len; |
3676 |
|
for (s = srch; s < send; s++) |
3677 |
|
if (!isalpha ((unsigned char) *s)) |
3678 |
|
break; |
3679 |
|
|
3680 |
|
/* If the first non alphabetic character is not '$' or ':', |
3681 |
|
then this is not an RCS keyword. */ |
3682 |
|
if (s == send || (*s != '$' && *s != ':')) |
3683 |
|
continue; |
3684 |
|
|
3685 |
|
/* See if this is one of the keywords. */ |
3686 |
|
slen = s - srch; |
3687 |
|
for (keyword = keywords; keyword->string; keyword++) |
3688 |
|
{ |
3689 |
|
if (keyword->expandit |
3690 |
|
&& keyword->len == slen |
3691 |
|
&& !strncmp (keyword->string, srch, slen)) |
3692 |
|
{ |
3693 |
|
break; |
3694 |
|
} |
3695 |
|
} |
3696 |
|
if (!keyword->string) |
3697 |
|
continue; |
3698 |
|
|
3699 |
|
/* If the keyword ends with a ':', then the old value consists |
3700 |
|
of the characters up to the next '$'. If there is no '$' |
3701 |
|
before the end of the line, though, then this wasn't an RCS |
3702 |
|
keyword after all. */ |
3703 |
|
|
3704 |
|
if (*s == ':') |
3705 |
|
{ |
3706 |
|
for (; s < send; s++) |
3707 |
|
if (*s == '$' || *s == '\n') |
3708 |
|
break; |
3709 |
|
if (s == send || *s != '$') |
3710 |
|
/* not resetting this the last time through this loop can cause |
3711 |
|
* erroneous return codes. |
3712 |
|
*/ |
3713 |
|
keyword = NULL; |
3714 |
|
} |
3715 |
|
|
3716 |
|
if (keyword) |
3717 |
|
break; |
3718 |
|
} |
3719 |
|
|
3720 |
|
if (keyword && keyword->string) |
3721 |
|
{ |
3722 |
|
*start = srch; |
3723 |
|
*end = s; |
3724 |
|
*len = srch_len; |
3725 |
|
TRACE (TRACE_DATA, |
3726 |
|
"next_keyword: returning keyword `%s' and remainder `%s'", |
3727 |
|
keyword->string, s); |
3728 |
|
return keyword; |
3729 |
|
} |
3730 |
|
/* else */ return NULL; |
3731 |
|
} |
3732 |
|
|
3733 |
|
|
3734 |
|
|
3735 |
|
bool contains_keyword (char *buf, size_t len) |
3736 |
|
{ |
3737 |
|
char *s; |
3738 |
|
return next_keyword (&buf, &len, &s); |
3739 |
|
} |
3740 |
|
|
3741 |
|
|
3742 |
|
|
3743 |
/* Expand RCS keywords in the memory buffer BUF of length LEN. This |
/* Expand RCS keywords in the memory buffer BUF of length LEN. This |
3744 |
applies to file RCS and version VERS. If NAME is not NULL, and is |
applies to file RCS and version VERS. If NAME is not NULL, and is |
3745 |
not a numeric revision, then it is the symbolic tag used for the |
not a numeric revision, then it is the symbolic tag used for the |
3762 |
struct expand_buffer *ebuf_last = NULL; |
struct expand_buffer *ebuf_last = NULL; |
3763 |
size_t ebuf_len = 0; |
size_t ebuf_len = 0; |
3764 |
char *locker; |
char *locker; |
3765 |
char *srch, *srch_next; |
char *srch, *s; |
3766 |
size_t srch_len; |
size_t srch_len; |
3767 |
const struct rcs_keyword *keywords; |
const struct rcs_keyword *keywords, *keyword; |
3768 |
|
|
3769 |
if (!config /* For `cvs init', config may not be set. */ |
if (!config /* For `cvs init', config may not be set. */ |
3770 |
||expand == KFLAG_O || expand == KFLAG_B) |
||expand == KFLAG_O || expand == KFLAG_B) |
3790 |
/* RCS keywords look like $STRING$ or $STRING: VALUE$. */ |
/* RCS keywords look like $STRING$ or $STRING: VALUE$. */ |
3791 |
srch = buf; |
srch = buf; |
3792 |
srch_len = len; |
srch_len = len; |
3793 |
while ((srch_next = memchr (srch, '$', srch_len)) != NULL) |
while ((keyword = next_keyword (&srch, &srch_len, &s))) |
3794 |
{ |
{ |
|
char *s, *send; |
|
|
size_t slen; |
|
|
const struct rcs_keyword *keyword; |
|
3795 |
char *value; |
char *value; |
3796 |
int free_value; |
int free_value; |
3797 |
char *sub; |
char *sub; |
3798 |
size_t sublen; |
size_t sublen; |
3799 |
|
|
|
srch_len -= (srch_next + 1) - srch; |
|
|
srch = srch_next + 1; |
|
|
|
|
|
/* Look for the first non alphabetic character after the '$'. */ |
|
|
send = srch + srch_len; |
|
|
for (s = srch; s < send; s++) |
|
|
if (! isalpha ((unsigned char) *s)) |
|
|
break; |
|
|
|
|
|
/* If the first non alphabetic character is not '$' or ':', |
|
|
then this is not an RCS keyword. */ |
|
|
if (s == send || (*s != '$' && *s != ':')) |
|
|
continue; |
|
|
|
|
|
/* See if this is one of the keywords. */ |
|
|
slen = s - srch; |
|
|
for (keyword = keywords; keyword->string != NULL; keyword++) |
|
|
{ |
|
|
if (keyword->expandit |
|
|
&& keyword->len == slen |
|
|
&& strncmp (keyword->string, srch, slen) == 0) |
|
|
{ |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (keyword->string == NULL) |
|
|
continue; |
|
|
|
|
|
/* If the keyword ends with a ':', then the old value consists |
|
|
of the characters up to the next '$'. If there is no '$' |
|
|
before the end of the line, though, then this wasn't an RCS |
|
|
keyword after all. */ |
|
|
if (*s == ':') |
|
|
{ |
|
|
for (; s < send; s++) |
|
|
if (*s == '$' || *s == '\n') |
|
|
break; |
|
|
if (s == send || *s != '$') |
|
|
continue; |
|
|
} |
|
|
|
|
3800 |
/* At this point we must replace the string from SRCH to S |
/* At this point we must replace the string from SRCH to S |
3801 |
with the expansion of the keyword KW. */ |
with the expansion of the keyword KEYWORD. */ |
3802 |
|
|
3803 |
/* Get the value to use. */ |
/* Get the value to use. */ |
3804 |
free_value = 0; |
free_value = 0; |