diff options
Diffstat (limited to 'usr.bin/rcs/rcs.c')
-rw-r--r-- | usr.bin/rcs/rcs.c | 119 |
1 files changed, 64 insertions, 55 deletions
diff --git a/usr.bin/rcs/rcs.c b/usr.bin/rcs/rcs.c index b3d784ec579..f5412e6b447 100644 --- a/usr.bin/rcs/rcs.c +++ b/usr.bin/rcs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.23 2006/07/11 18:36:32 markus Exp $ */ +/* $OpenBSD: rcs.c,v 1.24 2006/07/21 00:21:52 ray Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -2567,15 +2567,14 @@ rcs_strprint(const u_char *str, size_t slen, FILE *stream) static BUF * rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) { - ptrdiff_t c_offset, sizdiff, start_offset; - size_t i; + BUF *newbuf; int kwtype; u_int j, found; - u_char *c, *data, *kwstr, *start, *end, *tbuf, *fin; + u_char *c, *kwstr, *start, *end, *fin; char expbuf[256], buf[256]; struct tm tb; char *fmt; - size_t len, tbuflen; + size_t len; kwtype = 0; kwstr = NULL; @@ -2591,13 +2590,29 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) c = rcs_buf_get(bp); found = 0; - for (i = 0; i < len; i++) { + /* Final character in buffer. */ + fin = c + len - 1; + + /* If no keywords exist, return original BUF. */ + while (c < fin && !found) { if (*c == '$') { + size_t clen; + + /* Skip initial `$'. */ c++; - i++; + /* Number of characters between c and fin, inclusive. */ + clen = fin - c + 1; for (j = 0; j < RCS_NKWORDS; j++) { - if (!strncmp(c, rcs_expkw[j].kw_str, - strlen(rcs_expkw[j].kw_str))) { + 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] == ':')) { found = 1; kwstr = rcs_expkw[j].kw_str; kwtype = rcs_expkw[j].kw_type; @@ -2610,11 +2625,8 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) if (found == 0) return (bp); - rcs_buf_putc(bp, '\0'); - data = rcs_buf_release(bp); - c = data; - fin = c + len; - len++; + /* If no keywords are found, return original buffer. */ + newbuf = bp; /* * Keyword formats: @@ -2623,9 +2635,11 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) */ 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++; @@ -2634,14 +2648,26 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) 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++) { - if (!strncmp(c, rcs_expkw[j].kw_str, - strlen(rcs_expkw[j].kw_str))) { + 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] == ':')) { found = 1; kwstr = rcs_expkw[j].kw_str; kwtype = rcs_expkw[j].kw_type; + c += kwlen; break; } } @@ -2652,20 +2678,13 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) 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 == ':') { - while (*c++) { + for (; c <= fin; ++c) { if (*c == '$' || *c == '\n') break; } @@ -2675,7 +2694,6 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) continue; } } - c_offset = c - data; end = c + 1; /* start constructing the expansion */ @@ -2755,38 +2773,29 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf)) errx(1, "rcs_expand_keywords: string truncated"); - 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; - - 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); + /* 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; + + /* tmpbuf is now ready, free old newbuf if allocated here. */ + if (newbuf != bp) + rcs_buf_free(newbuf); + newbuf = tmpbuf; } } - bp = rcs_buf_alloc(len - 1, BUF_AUTOEXT); - rcs_buf_set(bp, data, len - 1, 0); - xfree(data); - - return (bp); + return (newbuf); } /* |