=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/rcs/rcs.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- src/usr.bin/rcs/rcs.c 2006/07/21 00:21:52 1.24 +++ src/usr.bin/rcs/rcs.c 2006/07/21 00:47:35 1.25 @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.24 2006/07/21 00:21:52 ray Exp $ */ +/* $OpenBSD: rcs.c,v 1.25 2006/07/21 00:47:35 ray Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau * All rights reserved. @@ -2567,14 +2567,15 @@ static BUF * 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; 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]; struct tm tb; char *fmt; - size_t len; + size_t len, tbuflen; kwtype = 0; kwstr = NULL; @@ -2590,29 +2591,13 @@ c = rcs_buf_get(bp); found = 0; - /* Final character in buffer. */ - fin = c + len - 1; - - /* If no keywords exist, return original BUF. */ - while (c < fin && !found) { + for (i = 0; i < len; i++) { if (*c == '$') { - size_t clen; - - /* Skip initial `$'. */ c++; - /* Number of characters between c and fin, inclusive. */ - clen = fin - c + 1; + i++; for (j = 0; j < RCS_NKWORDS; j++) { - size_t kwlen; - - 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] == ':')) { + if (!strncmp(c, rcs_expkw[j].kw_str, + strlen(rcs_expkw[j].kw_str))) { found = 1; kwstr = rcs_expkw[j].kw_str; kwtype = rcs_expkw[j].kw_type; @@ -2625,8 +2610,11 @@ if (found == 0) return (bp); - /* If no keywords are found, return original buffer. */ - newbuf = bp; + rcs_buf_putc(bp, '\0'); + data = rcs_buf_release(bp); + c = data; + fin = c + len; + len++; /* * Keyword formats: @@ -2635,11 +2623,9 @@ */ for (; c < fin; c++) { if (*c == '$') { - BUF *tmpbuf; - size_t clen; - /* remember start of this possible keyword */ start = c; + start_offset = start - data; /* first following character has to be alphanumeric */ c++; @@ -2648,26 +2634,14 @@ continue; } - /* Number of characters between c and fin, inclusive. */ - clen = fin - c + 1; - /* look for any matching keywords */ found = 0; for (j = 0; j < RCS_NKWORDS; j++) { - size_t kwlen; - - 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] == ':')) { + if (!strncmp(c, rcs_expkw[j].kw_str, + strlen(rcs_expkw[j].kw_str))) { found = 1; kwstr = rcs_expkw[j].kw_str; kwtype = rcs_expkw[j].kw_type; - c += kwlen; break; } } @@ -2678,13 +2652,20 @@ 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 * an '$' before the end of the line to be sure it is * in fact a keyword. */ if (*c == ':') { - for (; c <= fin; ++c) { + while (*c++) { if (*c == '$' || *c == '\n') break; } @@ -2694,6 +2675,7 @@ continue; } } + c_offset = c - data; end = c + 1; /* start constructing the expansion */ @@ -2773,29 +2755,38 @@ if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf)) errx(1, "rcs_expand_keywords: string truncated"); - /* Concatenate everything together. */ - tmpbuf = rcs_buf_alloc(len + strlen(expbuf), BUF_AUTOEXT); - /* Append everything before keyword. */ - rcs_buf_append(tmpbuf, rcs_buf_get(newbuf), - start - (unsigned char *)rcs_buf_get(newbuf)); - /* Append keyword. */ - rcs_buf_append(tmpbuf, expbuf, strlen(expbuf)); - /* 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; + sizdiff = strlen(expbuf) - (end - start); + tbuflen = fin - end; + tbuf = xmalloc(tbuflen); + memcpy(tbuf, end, tbuflen); + /* only realloc if we have to */ + if (sizdiff > 0) { + char *newdata; - /* tmpbuf is now ready, free old newbuf if allocated here. */ - if (newbuf != bp) - rcs_buf_free(newbuf); - newbuf = tmpbuf; + len += sizdiff; + newdata = xrealloc(data, 1, len); + data = newdata; + /* + * 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); } /*