diff options
author | Niall O'Higgins <niallo@cvs.openbsd.org> | 2007-01-12 23:32:02 +0000 |
---|---|---|
committer | Niall O'Higgins <niallo@cvs.openbsd.org> | 2007-01-12 23:32:02 +0000 |
commit | 86f3195293e0fc04a8930e13107efd5e54ca8fcf (patch) | |
tree | 24889af202d55ee5c1824b74c7f20c6ec9d4a0e5 | |
parent | 11e0f6ff64cc91fb9fcf64fb108cddba85fe5c26 (diff) |
major re-work of the RCS api. this results in 100x performance improvements in some places and much
reduced memory usage. note that only checkout has been fully converted to use the new high-performance
functions. other codepaths (e.g. update) still use the old method which is provided for backwards
compatibility. we can convert the remaining slow bits over to the new api piece-by-piece.
"commit this, now" joris@
brad@ tested, too.
-rw-r--r-- | usr.bin/cvs/checkout.c | 26 | ||||
-rw-r--r-- | usr.bin/cvs/commit.c | 8 | ||||
-rw-r--r-- | usr.bin/cvs/cvs.h | 4 | ||||
-rw-r--r-- | usr.bin/cvs/diff.c | 6 | ||||
-rw-r--r-- | usr.bin/cvs/diff3.c | 29 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 4 | ||||
-rw-r--r-- | usr.bin/cvs/import.c | 22 | ||||
-rw-r--r-- | usr.bin/cvs/rcs.c | 428 | ||||
-rw-r--r-- | usr.bin/cvs/rcs.h | 6 | ||||
-rw-r--r-- | usr.bin/cvs/update.c | 15 |
10 files changed, 466 insertions, 82 deletions
diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c index bc4f9ff2eb6..9dd24b3cd2e 100644 --- a/usr.bin/cvs/checkout.c +++ b/usr.bin/cvs/checkout.c @@ -1,4 +1,4 @@ -/* $OpenBSD: checkout.c,v 1.69 2007/01/03 22:28:30 joris Exp $ */ +/* $OpenBSD: checkout.c,v 1.70 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -169,23 +169,29 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, BUF *bp, int flags) struct timeval tv[2]; char *p, *entry, rev[16], timebuf[64], tbuf[32], stickytag[32]; + nbp = NULL; + rcsnum_tostr(rnum, rev, sizeof(rev)); cvs_log(LP_TRACE, "cvs_checkout_file(%s, %s, %d) -> %s", cf->file_path, rev, flags, (cvs_server_active) ? "to client" : "to disk"); - nbp = rcs_kwexp_buf(bp, cf->file_rcs, rnum); + if (bp != NULL) if (flags & CO_DUMP) { if (cvs_server_active) { cvs_printf("dump file %s to client\n", cf->file_path); } else { - if (cvs_buf_write_fd(nbp, STDOUT_FILENO) == -1) - fatal("cvs_checkout_file: %s", strerror(errno)); + if (nbp == NULL) { + rcs_rev_write_fd(cf->file_rcs, rnum, + STDOUT_FILENO, 1); + } else { + if (cvs_buf_write_fd(nbp, STDOUT_FILENO == -1)) + fatal("cvs_checkout_file: %s", strerror(errno)); + } } - cvs_buf_free(nbp); return; } @@ -203,10 +209,12 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, BUF *bp, int flags) if (cf->fd == -1) fatal("cvs_checkout_file: open: %s", strerror(errno)); - if (cvs_buf_write_fd(nbp, cf->fd) == -1) - fatal("cvs_checkout_file: %s", strerror(errno)); - - cvs_buf_free(nbp); + if (nbp == NULL) { + rcs_rev_write_fd(cf->file_rcs, rnum, cf->fd, 1); + } else { + if (cvs_buf_write_fd(nbp, STDOUT_FILENO == -1)) + fatal("cvs_checkout_file: %s", strerror(errno)); + } if (fchmod(cf->fd, 0644) == -1) fatal("cvs_checkout_file: fchmod: %s", strerror(errno)); diff --git a/usr.bin/cvs/commit.c b/usr.bin/cvs/commit.c index 28cec83e6b3..9281b878826 100644 --- a/usr.bin/cvs/commit.c +++ b/usr.bin/cvs/commit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: commit.c,v 1.93 2007/01/12 19:28:12 joris Exp $ */ +/* $OpenBSD: commit.c,v 1.94 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org> @@ -291,7 +291,7 @@ cvs_commit_local(struct cvs_file *cf) d = commit_diff_file(cf); if (cf->file_status == FILE_REMOVED) { - b = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); + b = rcs_rev_getbuf(cf->file_rcs, cf->file_rcs->rf_head); if (b == NULL) fatal("cvs_commit_local: failed to get HEAD"); } else { @@ -401,13 +401,13 @@ commit_diff_file(struct cvs_file *cf) fatal("commit_diff_file: failed to load '%s'", cf->file_path); } else { - b1 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); + b1 = rcs_rev_getbuf(cf->file_rcs, cf->file_rcs->rf_head); if (b1 == NULL) fatal("commit_diff_file: failed to load HEAD"); b1 = rcs_kwexp_buf(b1, cf->file_rcs, cf->file_rcs->rf_head); } - if ((b2 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) + if ((b2 = rcs_rev_getbuf(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) fatal("commit_diff_file: failed to load HEAD for '%s'", cf->file_path); diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h index 0182af44319..099fe95891f 100644 --- a/usr.bin/cvs/cvs.h +++ b/usr.bin/cvs/cvs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cvs.h,v 1.127 2007/01/12 09:27:25 xsa Exp $ */ +/* $OpenBSD: cvs.h,v 1.128 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -28,8 +28,8 @@ #define CVS_H #include "rcs.h" -#include "xmalloc.h" #include "util.h" +#include "xmalloc.h" #include "file.h" #include "repository.h" #include "worklist.h" diff --git a/usr.bin/cvs/diff.c b/usr.bin/cvs/diff.c index 3e3ba0b7f6f..5ca0bacf17c 100644 --- a/usr.bin/cvs/diff.c +++ b/usr.bin/cvs/diff.c @@ -1,4 +1,4 @@ -/* $OpenBSD: diff.c,v 1.111 2007/01/11 10:37:18 xsa Exp $ */ +/* $OpenBSD: diff.c,v 1.112 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -209,7 +209,7 @@ cvs_diff_local(struct cvs_file *cf) diff_rev1 = r1; rcsnum_tostr(r1, rbuf , sizeof(rbuf)); cvs_printf("retrieving revision %s\n", rbuf); - if ((b1 = rcs_getrev(cf->file_rcs, r1)) == NULL) + if ((b1 = rcs_rev_getbuf(cf->file_rcs, r1)) == NULL) fatal("failed to retrieve revision %s", rbuf); b1 = rcs_kwexp_buf(b1, cf->file_rcs, r1); @@ -223,7 +223,7 @@ cvs_diff_local(struct cvs_file *cf) cf->file_status != FILE_REMOVED) { rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); cvs_printf("retrieving revision %s\n", rbuf); - if ((b2 = rcs_getrev(cf->file_rcs, diff_rev2)) == NULL) + if ((b2 = rcs_rev_getbuf(cf->file_rcs, diff_rev2)) == NULL) fatal("failed to retrieve revision %s", rbuf); b2 = rcs_kwexp_buf(b2, cf->file_rcs, diff_rev2); diff --git a/usr.bin/cvs/diff3.c b/usr.bin/cvs/diff3.c index cde14172d0e..b7a43e097aa 100644 --- a/usr.bin/cvs/diff3.c +++ b/usr.bin/cvs/diff3.c @@ -1,4 +1,4 @@ -/* $OpenBSD: diff3.c,v 1.31 2007/01/12 17:25:33 joris Exp $ */ +/* $OpenBSD: diff3.c,v 1.32 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (C) Caldera International Inc. 2001-2002. @@ -72,7 +72,7 @@ static const char copyright[] = #ifndef lint static const char rcsid[] = - "$OpenBSD: diff3.c,v 1.31 2007/01/12 17:25:33 joris Exp $"; + "$OpenBSD: diff3.c,v 1.32 2007/01/12 23:32:01 niallo Exp $"; #endif /* not lint */ #include "includes.h" @@ -173,16 +173,6 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1, if ((b1 = cvs_buf_load_fd(workfd, BUF_AUTOEXT)) == NULL) goto out; - if (verbose == 1) - cvs_printf("Retrieving revision %s\n", r1); - if ((b2 = rcs_getrev(rf, rev1)) == NULL) - goto out; - - if (verbose == 1) - cvs_printf("Retrieving revision %s\n", r2); - if ((b3 = rcs_getrev(rf, rev2)) == NULL) - goto out; - d1 = cvs_buf_alloc((size_t)128, BUF_AUTOEXT); d2 = cvs_buf_alloc((size_t)128, BUF_AUTOEXT); diffb = cvs_buf_alloc((size_t)128, BUF_AUTOEXT); @@ -192,11 +182,12 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1, (void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", cvs_tmpdir); cvs_buf_write_stmp(b1, path1, NULL); - cvs_buf_write_stmp(b2, path2, NULL); - cvs_buf_write_stmp(b3, path3, NULL); - - cvs_buf_free(b2); - b2 = NULL; + if (verbose == 1) + cvs_printf("Retrieving revision %s\n", r1); + rcs_rev_write_stmp(rf, rev1, path2, 0); + if (verbose == 1) + cvs_printf("Retrieving revision %s\n", r2); + rcs_rev_write_stmp(rf, rev2, path3, 0); cvs_diffreg(path1, path3, d1); cvs_diffreg(path2, path3, d2); @@ -249,10 +240,6 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1, out: if (b1 != NULL) cvs_buf_free(b1); - if (b2 != NULL) - cvs_buf_free(b2); - if (b3 != NULL) - cvs_buf_free(b3); if (d1 != NULL) cvs_buf_free(d1); if (d2 != NULL) diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index 3e6973cca5f..d6f18c34c46 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.167 2007/01/12 19:28:12 joris Exp $ */ +/* $OpenBSD: file.c,v 1.168 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> @@ -665,7 +665,7 @@ cvs_file_classify(struct cvs_file *cf, const char *tag, int loud) } if (ismodified == 1 && cf->fd != -1 && cf->file_rcs != NULL) { - b1 = rcs_getrev(cf->file_rcs, cf->file_rcsrev); + b1 = rcs_rev_getbuf(cf->file_rcs, cf->file_rcsrev); if (b1 == NULL) fatal("failed to get HEAD revision for comparison"); diff --git a/usr.bin/cvs/import.c b/usr.bin/cvs/import.c index 552479cd3b1..bdb551d48bf 100644 --- a/usr.bin/cvs/import.c +++ b/usr.bin/cvs/import.c @@ -1,4 +1,4 @@ -/* $OpenBSD: import.c,v 1.60 2007/01/12 17:25:33 joris Exp $ */ +/* $OpenBSD: import.c,v 1.61 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -259,7 +259,7 @@ import_update(struct cvs_file *cf) fatal("import_update: rcsnum_parse failed"); if (rev != NULL) { - if ((b1 = rcs_getrev(cf->file_rcs, rev)) == NULL) + if ((b1 = rcs_rev_getbuf(cf->file_rcs, rev)) == NULL) fatal("import_update: failed to grab revision"); if ((b2 = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT)) == NULL) @@ -331,15 +331,12 @@ static char * import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) { char *delta, *p1, *p2; - BUF *b1, *b2, *b3; + BUF *b1, *b2; if ((b1 = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT)) == NULL) fatal("import_get_rcsdiff: failed loading %s", cf->file_path); - if ((b2 = rcs_getrev(cf->file_rcs, rev)) == NULL) - fatal("import_get_rcsdiff: failed loading revision"); - - b3 = cvs_buf_alloc(128, BUF_AUTOEXT); + b2 = cvs_buf_alloc(128, BUF_AUTOEXT); if (cvs_noexec != 1) { (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); @@ -347,11 +344,10 @@ import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) cvs_buf_free(b1); (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); - cvs_buf_write_stmp(b2, p2, NULL); - cvs_buf_free(b2); + rcs_rev_write_stmp(cf->file_rcs, rev, p2, 0); diff_format = D_RCSDIFF; - if (cvs_diffreg(p2, p1, b3) == D_ERROR) + if (cvs_diffreg(p2, p1, b2) == D_ERROR) fatal("import_get_rcsdiff: failed to get RCS patch"); (void)unlink(p1); @@ -363,15 +359,13 @@ import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) xfree(p2); } - cvs_buf_putc(b3, '\0'); - delta = cvs_buf_release(b3); + cvs_buf_putc(b2, '\0'); + delta = cvs_buf_release(b2); if (b1 != NULL) cvs_buf_free(b1); if (b2 != NULL) cvs_buf_free(b2); - if (b3 != NULL) - cvs_buf_free(b3); return (delta); } diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c index 14d5dd7f729..1ec2c8fb66b 100644 --- a/usr.bin/cvs/rcs.c +++ b/usr.bin/cvs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.195 2007/01/12 19:28:12 joris Exp $ */ +/* $OpenBSD: rcs.c,v 1.196 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -236,6 +236,8 @@ static void rcs_growbuf(RCSFILE *); static void rcs_strprint(const u_char *, size_t, FILE *); static BUF *rcs_expand_keywords(char *, struct rcs_delta *, BUF *, int); +static void rcs_kwexp_line(char *, struct rcs_delta *, struct cvs_line *, + int mode); RCSFILE * rcs_open(const char *path, int fd, int flags, ...) @@ -1404,25 +1406,15 @@ rcs_rev_remove(RCSFILE *rf, RCSNUM *rev) newdeltatext = NULL; prevbuf = nextbuf = NULL; - if (prevrdp != NULL) { - if ((prevbuf = rcs_getrev(rf, prevrdp->rd_num)) == NULL) - fatal("error getting revision"); - } - if (prevrdp != NULL && nextrdp != NULL) { - if ((nextbuf = rcs_getrev(rf, nextrdp->rd_num)) == NULL) - fatal("error getting revision"); - newdiff = cvs_buf_alloc(64, BUF_AUTOEXT); /* calculate new diff */ (void)xasprintf(&path_tmp1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); - cvs_buf_write_stmp(nextbuf, path_tmp1, NULL); - cvs_buf_free(nextbuf); + rcs_rev_write_stmp(rf, nextrdp->rd_num, path_tmp1, 0); (void)xasprintf(&path_tmp2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); - cvs_buf_write_stmp(prevbuf, path_tmp2, NULL); - cvs_buf_free(prevbuf); + rcs_rev_write_stmp(rf, prevrdp->rd_num, path_tmp2, 0); diff_format = D_RCSDIFF; if (cvs_diffreg(path_tmp1, path_tmp2, newdiff) == D_ERROR) @@ -2600,7 +2592,6 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) u_int j, found; u_char *c, *kwstr, *start, *end, *fin; char expbuf[256], buf[256]; - struct tm tb; char *fmt; size_t len; @@ -3038,3 +3029,412 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) return (rev); } + +/* + * rcs_rev_getlines() + * + * Get the entire contents of revision <rev> from the RCSFILE <rfp> and + * return it as a pointer to a struct cvs_lines. + */ +struct cvs_lines * +rcs_rev_getlines(RCSFILE *rfp, RCSNUM *frev) +{ + size_t i, plen; + int done, nextroot, found; + RCSNUM *tnum, *bnum; + struct rcs_branch *brp; + struct rcs_delta *hrdp, *trdp, *rdp; + u_char *patch; + struct cvs_lines *dlines, *plines; + + if ((hrdp = rcs_findrev(rfp, rfp->rf_head)) == NULL) + fatal("rcs_rev_write_fd: no HEAD revision"); + + tnum = frev; + rcs_parse_deltatexts(rfp, hrdp->rd_num); + + /* revision on branch, get the branch root */ + nextroot = 2; + if (RCSNUM_ISBRANCHREV(tnum)) { + bnum = rcsnum_alloc(); + rcsnum_cpy(tnum, bnum, nextroot); + } else { + bnum = tnum; + } + + dlines = cvs_splitlines(hrdp->rd_text, hrdp->rd_tlen); + + done = 0; + + rdp = hrdp; + if (!rcsnum_differ(rdp->rd_num, bnum)) + goto next; + + if ((rdp = rcs_findrev(rfp, hrdp->rd_next)) == NULL) + goto done; + +again: + for (;;) { + if (rdp->rd_next->rn_len != 0) { + trdp = rcs_findrev(rfp, rdp->rd_next); + if (trdp == NULL) + fatal("failed to grab next revision"); + } + + if (rdp->rd_tlen == 0) { + rcs_parse_deltatexts(rfp, rdp->rd_num); + if (rdp->rd_tlen == 0) { + if (!rcsnum_differ(rdp->rd_num, bnum)) + break; + rdp = trdp; + continue; + } + } + + plen = rdp->rd_tlen; + patch = rdp->rd_text; + plines = cvs_splitlines(patch, plen); + rcs_patch_lines(dlines, plines); + cvs_freelines(plines); + + if (!rcsnum_differ(rdp->rd_num, bnum)) + break; + + rdp = trdp; + } + +next: + if (!rcsnum_differ(rdp->rd_num, frev)) + done = 1; + + if (RCSNUM_ISBRANCHREV(frev) && done != 1) { + nextroot += 2; + rcsnum_cpy(frev, bnum, nextroot); + + TAILQ_FOREACH(brp, &(rdp->rd_branches), rb_list) { + found = 1; + for (i = 0; i < nextroot - 1; i++) { + if (brp->rb_num->rn_id[i] != bnum->rn_id[i]) { + found = 0; + break; + } + } + + break; + } + + if (brp == NULL) + fatal("expected branch not found on branch list"); + + if ((rdp = rcs_findrev(rfp, brp->rb_num)) == NULL) + fatal("rcs_rev_write_fd: failed to get delta for target rev"); + + goto again; + } +done: + if (bnum != tnum) + rcsnum_free(bnum); + + return (dlines); +} + +/* + * rcs_rev_getbuf() + * + * XXX: This is really really slow and should be avoided if at all possible! + * + * Get the entire contents of revision <rev> from the RCSFILE <rfp> and + * return it as a BUF pointer. + */ +BUF * +rcs_rev_getbuf(RCSFILE *rfp, RCSNUM *rev) +{ + struct cvs_lines *lines; + struct cvs_line *lp; + BUF *bp; + + lines = rcs_rev_getlines(rfp, rev); + bp = cvs_buf_alloc(1024, BUF_AUTOEXT); + TAILQ_FOREACH(lp, &lines->l_lines, l_list) { + if (lp->l_line == NULL) + continue; + cvs_buf_append(bp, lp->l_line, lp->l_len); + } + + cvs_freelines(lines); + + return (bp); +} + +/* + * rcs_rev_write_fd() + * + * Write the entire contents of revision <frev> from the rcsfile <rfp> to + * file descriptor <fd>. + */ +void +rcs_rev_write_fd(RCSFILE *rfp, RCSNUM *rev, int fd, int mode) +{ + int expmode; + struct rcs_delta *rdp; + struct cvs_lines *lines; + struct cvs_line *lp; + + lines = rcs_rev_getlines(rfp, rev); + /* keyword expansion if necessary */ + if (!(mode & RCS_KWEXP_NONE)) { + if (rfp->rf_expand != NULL) + expmode = rcs_kwexp_get(rfp); + else + expmode = RCS_KWEXP_DEFAULT; + + if (!(expmode & RCS_KWEXP_NONE)) { + if ((rdp = rcs_findrev(rfp, rev)) == NULL) + fatal("could not fetch revision"); + rcs_kwexp_lines(rfp->rf_path, rdp, lines, expmode); + } + } + TAILQ_FOREACH(lp, &lines->l_lines, l_list) { + if (lp->l_line == NULL) + continue; + if (write(fd, lp->l_line, lp->l_len) == -1) + fatal("rcs_rev_write_fd: %s", strerror(errno)); + } + + /* XXX: do we need to call futimes(2) on the output fd? */ + + cvs_freelines(lines); + +} + +/* + * rcs_rev_write_stmp() + * + * Write the contents of the rev <rev> to a temporary file whose path is + * specified using <template> (see mkstemp(3)). NB. This function will modify + * <template>, as per mkstemp. + */ +void +rcs_rev_write_stmp(RCSFILE *rfp, RCSNUM *rev, char *template, int mode) +{ + int fd; + + if ((fd = mkstemp(template)) == -1) + fatal("mkstemp: `%s': %s", template, strerror(errno)); + + cvs_worklist_add(template, &temp_files); + rcs_rev_write_fd(rfp, rev, fd, mode); + + (void)close(fd); +} + +static void +rcs_kwexp_line(char *rcsfile, struct rcs_delta *rdp, struct cvs_line *line, + int mode) +{ + int kwtype; + u_int j, found; + u_char *c, *kwstr, *start, *end, *fin; + char expbuf[256], buf[256]; + char *fmt; + size_t len; + + kwtype = 0; + kwstr = NULL; + + len = line->l_len; + if (len == 0) + return; + + c = line->l_line; + found = 0; + /* Final character in buffer. */ + fin = c + len - 1; + + /* + * Keyword formats: + * $Keyword$ + * $Keyword: value$ + */ + for (; c < fin; c++) { + if (*c == '$') { + BUF *tmpbuf; + size_t clen, tlen; + + /* remember start of this possible keyword */ + start = c; + + /* first following character has to be alphanumeric */ + c++; + if (!isalpha(*c)) { + c = start; + 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] == ':')) { + found = 1; + kwstr = rcs_expkw[j].kw_str; + kwtype = rcs_expkw[j].kw_type; + c += kwlen; + break; + } + } + + /* unknown keyword, continue looking */ + if (found == 0) { + 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) { + if (*c == '$' || *c == '\n') + break; + } + + if (*c != '$') { + c = start; + continue; + } + } + end = c + 1; + + /* start constructing the expansion */ + expbuf[0] = '\0'; + + if (mode & RCS_KWEXP_NAME) { + if (strlcat(expbuf, "$", sizeof(expbuf)) >= sizeof(expbuf) || + strlcat(expbuf, kwstr, sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: truncated"); + if ((mode & RCS_KWEXP_VAL) && + strlcat(expbuf, ": ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: truncated"); + } + + /* + * order matters because of RCS_KW_ID and + * RCS_KW_HEADER here + */ + if (mode & RCS_KWEXP_VAL) { + if (kwtype & RCS_KW_RCSFILE) { + if (!(kwtype & RCS_KW_FULLPATH)) + (void)strlcat(expbuf, basename(rcsfile), sizeof(expbuf)); + else + (void)strlcat(expbuf, rcsfile, sizeof(expbuf)); + if (strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: truncated"); + } + + if (kwtype & RCS_KW_REVISION) { + rcsnum_tostr(rdp->rd_num, buf, sizeof(buf)); + if (strlcat(buf, " ", sizeof(buf)) >= sizeof(buf) || + strlcat(expbuf, buf, sizeof(expbuf)) >= sizeof(buf)) + fatal("rcs_expand_keywords: truncated"); + } + + if (kwtype & RCS_KW_DATE) { + fmt = "%Y/%m/%d %H:%M:%S "; + + strftime(buf, sizeof(buf), fmt, &rdp->rd_date); + if (strlcat(expbuf, buf, sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + } + + if (kwtype & RCS_KW_AUTHOR) { + if (strlcat(expbuf, rdp->rd_author, sizeof(expbuf)) >= sizeof(expbuf) || + strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + } + + if (kwtype & RCS_KW_STATE) { + if (strlcat(expbuf, rdp->rd_state, sizeof(expbuf)) >= sizeof(expbuf) || + strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + } + + /* order does not matter anymore below */ + if (kwtype & RCS_KW_LOG) + if (strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + + if (kwtype & RCS_KW_SOURCE) { + if (strlcat(expbuf, rcsfile, sizeof(expbuf)) >= sizeof(expbuf) || + strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + } + + if (kwtype & RCS_KW_NAME) + if (strlcat(expbuf, " ", sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: string truncated"); + } + + /* end the expansion */ + if (mode & RCS_KWEXP_NAME) + if (strlcat(expbuf, "$", + sizeof(expbuf)) >= sizeof(expbuf)) + fatal("rcs_expand_keywords: truncated"); + + /* Concatenate everything together. */ + tmpbuf = cvs_buf_alloc(len + strlen(expbuf), BUF_AUTOEXT); + /* Append everything before keyword. */ + cvs_buf_append(tmpbuf, line->l_line, + start - (unsigned char *)line->l_line); + /* Append keyword. */ + cvs_buf_append(tmpbuf, expbuf, strlen(expbuf)); + /* Point c to end of keyword. */ + tlen = cvs_buf_len(tmpbuf) - 1; + /* Append everything after keyword. */ + cvs_buf_append(tmpbuf, end, + ((unsigned char *)line->l_line + line->l_len) - end); + c = cvs_buf_get(tmpbuf) + tlen; + /* Point fin to end of data. */ + fin = cvs_buf_get(tmpbuf) + cvs_buf_len(tmpbuf) - 1; + /* Recalculate new length. */ + len = cvs_buf_len(tmpbuf); + + /* tmpbuf is now ready, convert to string */ + line->l_len = len; + line->l_line = cvs_buf_release(tmpbuf); + } + } +} + +/* + * rcs_kwexp_lines() + * + * Do keyword expansion of cvs_lines struct, if necessary. + * Any lines which need expansion are allocated memory in a separate malloc() + * from the original, and l_needsfree is set to 1. cvs_freelines() will check + * for this and free if necessary. This basically gives us 'copy-on-write' + * semantics for expansion of keywords, so we do the minimum work required. + * + * On error, return NULL. + */ +void +rcs_kwexp_lines(char *rcsfile, struct rcs_delta *rdp, struct cvs_lines *lines, + int mode) +{ + struct cvs_line *lp; + TAILQ_FOREACH(lp, &lines->l_lines, l_list) + rcs_kwexp_line(rcsfile, rdp, lp, mode); +} diff --git a/usr.bin/cvs/rcs.h b/usr.bin/cvs/rcs.h index c55d089d0de..311233c4a37 100644 --- a/usr.bin/cvs/rcs.h +++ b/usr.bin/cvs/rcs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.h,v 1.70 2007/01/12 17:25:33 joris Exp $ */ +/* $OpenBSD: rcs.h,v 1.71 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -26,7 +26,6 @@ #ifndef RCS_H #define RCS_H - #include "buf.h" #define RCS_DIFF_MAXARG 32 @@ -216,6 +215,7 @@ typedef struct rcs_file { } RCSFILE; extern int rcs_errno; +struct cvs_lines; RCSFILE *rcs_open(const char *, int, int, ...); void rcs_close(RCSFILE *); @@ -245,6 +245,8 @@ const char *rcs_comment_lookup(const char *); const char *rcs_comment_get(RCSFILE *); void rcs_comment_set(RCSFILE *, const char *); BUF *rcs_kwexp_buf(BUF *, RCSFILE *, RCSNUM *); +void rcs_kwexp_lines(char *, struct rcs_delta *, + struct cvs_lines *, int); void rcs_kwexp_set(RCSFILE *, int); int rcs_kwexp_get(RCSFILE *); int rcs_rev_add(RCSFILE *, RCSNUM *, const char *, time_t, diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c index 19108f9f73d..c5b75d72aaf 100644 --- a/usr.bin/cvs/update.c +++ b/usr.bin/cvs/update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: update.c,v 1.83 2007/01/11 17:44:18 niallo Exp $ */ +/* $OpenBSD: update.c,v 1.84 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -302,15 +302,12 @@ cvs_update_local(struct cvs_file *cf) } if (print && cf->file_status != FILE_UNKNOWN) { - bp = rcs_getrev(cf->file_rcs, cf->file_rcsrev); - if (bp == NULL) - fatal("cvs_update_local: failed to get HEAD"); rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf)); if (verbosity > 1) cvs_printf("%s\nChecking out %s\n" "RCS:\t%s\nVERS:\t%s\n***************\n", RCS_DIFF_DIV, cf->file_path, cf->file_rpath, rbuf); - cvs_checkout_file(cf, cf->file_rcsrev, bp, CO_DUMP); + cvs_checkout_file(cf, cf->file_rcsrev, NULL, CO_DUMP); return; } @@ -340,18 +337,14 @@ cvs_update_local(struct cvs_file *cf) case FILE_LOST: case FILE_CHECKOUT: case FILE_PATCH: - bp = rcs_getrev(cf->file_rcs, cf->file_rcsrev); - if (bp == NULL) - fatal("cvs_update_local: failed to get HEAD"); - if (tag != NULL) flags = CO_SETSTICKY; - cvs_checkout_file(cf, cf->file_rcsrev, bp, flags); + cvs_checkout_file(cf, cf->file_rcsrev, NULL, flags); cvs_printf("U %s\n", cf->file_path); break; case FILE_MERGE: - bp = cvs_diff3(cf->file_rcs, cf->file_path, cf->fd, + cvs_diff3(cf->file_rcs, cf->file_path, cf->fd, cf->file_ent->ce_rev, cf->file_rcsrev, 1); if (bp == NULL) fatal("cvs_update_local: failed to merge"); |