=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/cvs/rcs.c,v retrieving revision 1.195 retrieving revision 1.196 diff -u -r1.195 -r1.196 --- src/usr.bin/cvs/rcs.c 2007/01/12 19:28:12 1.195 +++ src/usr.bin/cvs/rcs.c 2007/01/12 23:32:01 1.196 @@ -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 * All rights reserved. @@ -236,6 +236,8 @@ 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 @@ 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 @@ u_int j, found; u_char *c, *kwstr, *start, *end, *fin; char expbuf[256], buf[256]; - struct tm tb; char *fmt; size_t len; @@ -3037,4 +3028,413 @@ } return (rev); +} + +/* + * rcs_rev_getlines() + * + * Get the entire contents of revision from the RCSFILE 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 from the RCSFILE 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 from the rcsfile to + * file descriptor . + */ +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 to a temporary file whose path is + * specified using