diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2008-03-08 20:26:35 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2008-03-08 20:26:35 +0000 |
commit | f180fa31bef240be9e356681d7f12aa11cec5f8b (patch) | |
tree | c184dbcda05d69b8cb1bfed5886e59067766b1cc | |
parent | 22b225cb417a08d1f3be81c45427e2232d860a85 (diff) |
add checkout/update -j support.
still has some rough edges.
-rw-r--r-- | usr.bin/cvs/add.c | 6 | ||||
-rw-r--r-- | usr.bin/cvs/checkout.c | 17 | ||||
-rw-r--r-- | usr.bin/cvs/cvs.h | 6 | ||||
-rw-r--r-- | usr.bin/cvs/diff.h | 4 | ||||
-rw-r--r-- | usr.bin/cvs/diff3.c | 67 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 5 | ||||
-rw-r--r-- | usr.bin/cvs/rcs.c | 68 | ||||
-rw-r--r-- | usr.bin/cvs/remove.c | 6 | ||||
-rw-r--r-- | usr.bin/cvs/update.c | 161 |
9 files changed, 276 insertions, 64 deletions
diff --git a/usr.bin/cvs/add.c b/usr.bin/cvs/add.c index 047ceca978b..6bc9063a1bb 100644 --- a/usr.bin/cvs/add.c +++ b/usr.bin/cvs/add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: add.c,v 1.95 2008/03/01 21:29:36 deraadt Exp $ */ +/* $OpenBSD: add.c,v 1.96 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> @@ -27,7 +27,6 @@ extern char *__progname; -void cvs_add_local(struct cvs_file *); void cvs_add_entry(struct cvs_file *); void cvs_add_remote(struct cvs_file *); @@ -145,7 +144,8 @@ cvs_add_local(struct cvs_file *cf) { cvs_log(LP_TRACE, "cvs_add_local(%s)", cf->file_path); - cvs_file_classify(cf, cvs_directory_tag); + if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_UPDATE) + cvs_file_classify(cf, cvs_directory_tag); /* dont use `cvs add *' */ if (strcmp(cf->file_name, ".") == 0 || diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c index 5e4fa7d2930..d2c64e104ac 100644 --- a/usr.bin/cvs/checkout.c +++ b/usr.bin/cvs/checkout.c @@ -1,4 +1,4 @@ -/* $OpenBSD: checkout.c,v 1.141 2008/02/29 21:43:57 joris Exp $ */ +/* $OpenBSD: checkout.c,v 1.142 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -98,6 +98,14 @@ cvs_checkout(int argc, char **argv) dflag = optarg; checkout_target_dir = dflag; break; + case 'j': + if (cvs_join_rev1 == NULL) + cvs_join_rev1 = optarg; + else if (cvs_join_rev2 == NULL) + cvs_join_rev2 = optarg; + else + fatal("too many -j options"); + break; case 'k': reset_option = 0; koptstr = optarg; @@ -459,14 +467,14 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, char *tag, int co_flags) } cf->fd = open(cf->file_path, - O_CREAT | O_WRONLY | O_TRUNC); + O_CREAT | O_RDWR | O_TRUNC); if (cf->fd == -1) fatal("cvs_checkout_file: open: %s", strerror(errno)); rcs_rev_write_fd(cf->file_rcs, rnum, cf->fd, 0); } else { - cvs_merge_file(cf, 1); + cvs_merge_file(cf, (cvs_join_rev1 == NULL)); } if (fchmod(cf->fd, 0644) == -1) @@ -534,12 +542,13 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, char *tag, int co_flags) ent = cvs_ent_open(cf->file_wd); cvs_ent_add(ent, entry); cvs_ent_close(ent, ENT_SYNC); + cf->file_ent = cvs_ent_parse(entry); xfree(entry); } } else { if (co_flags & CO_MERGE) { (void)unlink(cf->file_path); - cvs_merge_file(cf, 1); + cvs_merge_file(cf, (cvs_join_rev1 == NULL)); tosend = cf->file_path; fd = cf->fd; } diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h index 261ff058162..d9aa05f96b9 100644 --- a/usr.bin/cvs/cvs.h +++ b/usr.bin/cvs/cvs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cvs.h,v 1.162 2008/03/01 21:29:36 deraadt Exp $ */ +/* $OpenBSD: cvs.h,v 1.163 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -291,6 +291,8 @@ typedef struct cvs_entries { } CVSENTRIES; extern char *checkout_target_dir; +extern char *cvs_join_rev1; +extern char *cvs_join_rev2; extern struct module_checkout *current_module; extern char *module_repo_root; @@ -397,6 +399,8 @@ void cvs_update_local(struct cvs_file *); void cvs_update_enterdir(struct cvs_file *); void cvs_update_leavedir(struct cvs_file *); void cvs_checkout_file(struct cvs_file *, RCSNUM *, char *, int); +void cvs_remove_local(struct cvs_file *); +void cvs_add_local(struct cvs_file *); int update_has_conflict_markers(struct cvs_file *); #define CO_MERGE 0x01 diff --git a/usr.bin/cvs/diff.h b/usr.bin/cvs/diff.h index 2b488f20c48..60d629d3e4b 100644 --- a/usr.bin/cvs/diff.h +++ b/usr.bin/cvs/diff.h @@ -1,4 +1,4 @@ -/* $OpenBSD: diff.h,v 1.16 2008/02/27 22:34:04 joris Exp $ */ +/* $OpenBSD: diff.h,v 1.17 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (C) Caldera International Inc. 2001-2002. * All rights reserved. @@ -105,5 +105,7 @@ extern char diffargs[128]; extern BUF *diffbuf; extern RCSNUM *diff_rev1; extern RCSNUM *diff_rev2; +extern RCSNUM *d3rev1; +extern RCSNUM *d3rev2; #endif diff --git a/usr.bin/cvs/diff3.c b/usr.bin/cvs/diff3.c index f98c55e4584..36aa0cff974 100644 --- a/usr.bin/cvs/diff3.c +++ b/usr.bin/cvs/diff3.c @@ -1,4 +1,4 @@ -/* $OpenBSD: diff3.c,v 1.46 2008/03/08 11:53:36 joris Exp $ */ +/* $OpenBSD: diff3.c,v 1.47 2008/03/08 20:26:34 joris 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.46 2008/03/08 11:53:36 joris Exp $"; + "$OpenBSD: diff3.c,v 1.47 2008/03/08 20:26:34 joris Exp $"; #endif /* not lint */ #include <ctype.h> @@ -115,8 +115,8 @@ struct diff { static size_t szchanges; -static struct diff *d13; -static struct diff *d23; +static struct diff *d13 = NULL; +static struct diff *d23 = NULL; /* * "de" is used to gather editing scripts. These are later spewed out in @@ -125,8 +125,8 @@ static struct diff *d23; * look (!?). Array overlap indicates which sections in "de" correspond to * lines that are different in all three files. */ -static struct diff *de; -static char *overlap; +static struct diff *de = NULL; +static char *overlap = NULL; static int overlapcnt = 0; static FILE *fp[3]; static int cline[3]; /* # of the last-read line in each file (0-2) */ @@ -159,6 +159,8 @@ static void increase(void); static int diff3_internal(int, char **, const char *, const char *); int diff3_conflicts = 0; +RCSNUM *d3rev1 = NULL; +RCSNUM *d3rev2 = NULL; static int fds[5]; @@ -176,8 +178,9 @@ cvs_merge_file(struct cvs_file *cf, int verbose) overlapcnt = 0; b1 = b2 = b3 = d1 = d2 = diffb = NULL; - rcsnum_tostr(cf->file_ent->ce_rev, r1, sizeof(r1)); - rcsnum_tostr(cf->file_rcsrev, r2, sizeof(r2)); + + rcsnum_tostr(d3rev1, r1, sizeof(r1)); + rcsnum_tostr(d3rev2, r2, sizeof(r2)); b1 = cvs_buf_load_fd(cf->fd); d1 = cvs_buf_alloc(128); @@ -191,11 +194,10 @@ cvs_merge_file(struct cvs_file *cf, int verbose) fds[2] = cvs_buf_write_stmp(b1, path1, NULL); if (verbose == 1) cvs_printf("Retrieving revision %s\n", r1); - fds[3] = rcs_rev_write_stmp(cf->file_rcs, cf->file_ent->ce_rev, - path2, 0); + fds[3] = rcs_rev_write_stmp(cf->file_rcs, d3rev1, path2, 0); if (verbose == 1) cvs_printf("Retrieving revision %s\n", r2); - fds[4] = rcs_rev_write_stmp(cf->file_rcs, cf->file_rcsrev, path3, 0); + fds[4] = rcs_rev_write_stmp(cf->file_rcs, d3rev2, path3, 0); cvs_diffreg(path1, path3, fds[2], fds[4], d1); cvs_diffreg(path2, path3, fds[3], fds[4], d2); @@ -232,11 +234,13 @@ cvs_merge_file(struct cvs_file *cf, int verbose) dlen = cvs_buf_len(b1); data = cvs_buf_release(b1); - cvs_printf("Merging differences between %s and %s into `%s'\n", - r1, r2, cf->file_path); + if (verbose == 1) + cvs_printf("Merging differences between %s and %s into `%s'\n", + r1, r2, cf->file_path); dlines = cvs_splitlines(data, dlen); plines = cvs_splitlines(patch, plen); + ed_patch_lines(dlines, plines); cvs_freelines(plines); @@ -271,11 +275,7 @@ cvs_merge_file(struct cvs_file *cf, int verbose) for (i = 0; i < 3; i++) fclose(fp[i]); - (void)unlink(path1); - (void)unlink(path2); - (void)unlink(path3); - (void)unlink(dp13); - (void)unlink(dp23); + cvs_worklist_run(&temp_files, cvs_worklist_unlink); xfree(path1); xfree(path2); @@ -290,7 +290,6 @@ diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) size_t m, n; int i; - /* XXX */ eflag = 3; oflag = 1; @@ -300,6 +299,21 @@ diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) (void)xsnprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", fmark); (void)xsnprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", rmark); + szchanges = 0; + memset(last, 0, sizeof(last)); + memset(cline, 0, sizeof(cline)); + if (d13 != NULL) + xfree(d13); + if (d23 != NULL) + xfree(d23); + if (overlap != NULL) + xfree(overlap); + if (de != NULL) + xfree(de); + + overlap = NULL; + de = d13 = d23 = NULL; + increase(); /* fds[0] and fds[1] are closed in readin() */ @@ -319,7 +333,7 @@ diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) int ed_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines) { - char op, *ep; + char op, *ep, *p; struct cvs_line *sort, *lp, *dlp, *ndlp, *insert_after; int start, end, i, lineno; u_char tmp; @@ -333,18 +347,21 @@ ed_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines) /* Skip blank lines */ if (lp->l_len < 2) continue; + /* NUL-terminate line buffer for strtol() safety. */ tmp = lp->l_line[lp->l_len - 1]; lp->l_line[lp->l_len - 1] = '\0'; - /* len - 1 is NUL terminator so we use len - 2 for 'op' */ + op = lp->l_line[strlen(lp->l_line) - 1]; start = (int)strtol(lp->l_line, &ep, 10); + /* Restore the last byte of the buffer */ lp->l_line[lp->l_len - 1] = tmp; + if (op == 'a') { if (start > dlines->l_nblines || start < 0 || *ep != 'a') - fatal("ed_patch_lines"); + fatal("ed_patch_lines %d", start); } else if (op == 'c') { if (start > dlines->l_nblines || start < 0 || (*ep != ',' && *ep != 'c')) @@ -358,6 +375,8 @@ ed_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines) } else { end = start; } + } else { + fatal("invalid op %c found while merging", op); } @@ -397,7 +416,9 @@ ed_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines) if (lp == NULL) fatal("ed_patch_lines"); - if (!memcmp(lp->l_line, ".", 1)) + if (lp->l_len == 2 && + lp->l_line[0] == '.' && + lp->l_line[1] == '\n') break; TAILQ_REMOVE(&(plines->l_lines), lp, l_list); diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index 899da1b8d09..24cf94c5f4d 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.226 2008/03/01 21:29:37 deraadt Exp $ */ +/* $OpenBSD: file.c,v 1.227 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> @@ -748,7 +748,8 @@ cvs_file_classify(struct cvs_file *cf, const char *tag) } if (ismodified == 1 && cf->fd != -1 && cf->file_rcs != NULL && - cf->file_ent != NULL && !RCSNUM_ISBRANCH(cf->file_ent->ce_rev)) { + cf->file_ent != NULL && !RCSNUM_ISBRANCH(cf->file_ent->ce_rev) && + cf->file_ent->ce_status != CVS_ENT_ADDED) { b1 = rcs_rev_getbuf(cf->file_rcs, cf->file_ent->ce_rev, 0); b2 = cvs_buf_load_fd(cf->fd); diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c index 56f1fbd7de3..afbf38e4e7e 100644 --- a/usr.bin/cvs/rcs.c +++ b/usr.bin/cvs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.257 2008/03/08 11:53:36 joris Exp $ */ +/* $OpenBSD: rcs.c,v 1.258 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -2622,14 +2622,6 @@ rcs_get_revision(const char *revstr, RCSFILE *rfp) if ((rdp = rcs_findrev(rfp, brp->rb_num)) == NULL) fatal("rcs_get_revision: could not fetch branch " "delta"); - /* Find the latest delta on that branch */ - for (;;) { - if (rdp->rd_next->rn_len == 0) - break; - if ((rdp = rcs_findrev(rfp, rdp->rd_next)) == NULL) - fatal("rcs_get_revision: could not fetch " - "branch delta"); - } rcsnum_cpy(rdp->rd_num, frev, 0); return (frev); } @@ -3448,6 +3440,7 @@ RCSNUM * rcs_translate_tag(const char *revstr, RCSFILE *rfp) { int follow; + time_t deltatime; char branch[CVS_REV_BUFSZ]; RCSNUM *brev, *frev, *rev; struct rcs_delta *rdp, *trdp; @@ -3464,7 +3457,32 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) } if ((rev = rcs_get_revision(revstr, rfp)) == NULL) - return NULL; + return (NULL); + + if ((rdp = rcs_findrev(rfp, rev)) == NULL) + fatal("rcs_translate_tag: cannot find revision"); + + if (cvs_specified_date == -1) { + + /* XXX */ + if (rev->rn_len < 4) { + return (rev); + } + + /* Find the latest delta on that branch */ + rcsnum_free(rev); + for (;;) { + if (rdp->rd_next->rn_len == 0) + break; + if ((rdp = rcs_findrev(rfp, rdp->rd_next)) == NULL) + fatal("rcs_get_revision: could not fetch " + "branch delta"); + } + + rev = rcsnum_alloc(); + rcsnum_cpy(rdp->rd_num, rev, 0); + return (rev); + } /* let's see if we must follow a branch */ if (!strcmp(revstr, RCS_HEAD_BRANCH)) @@ -3478,11 +3496,8 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) follow = 0; } - if ((rdp = rcs_findrev(rfp, rev)) == NULL) - fatal("rcs_translate_tag: cannot find revision"); - - if (cvs_specified_date == -1) - return rev; + if (frev != NULL) + rcsnum_tostr(frev, branch, sizeof(branch)); if (frev != NULL) { brev = rcsnum_revtobr(frev); @@ -3492,10 +3507,23 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) rcsnum_free(rev); do { - if (timelocal(&(rdp->rd_date)) < cvs_specified_date) { - rev = rcsnum_alloc(); - rcsnum_cpy(rdp->rd_num, rev, 0); - return rev; + deltatime = timelocal(&(rdp->rd_date)); + + if (RCSNUM_ISBRANCHREV(rdp->rd_num)) { + if (deltatime > cvs_specified_date) { + trdp = TAILQ_PREV(rdp, rcs_dlist, rd_list); + if (trdp == NULL) + trdp = rdp; + rev = rcsnum_alloc(); + rcsnum_cpy(trdp->rd_num, rev, 0); + return (rev); + } + } else { + if (deltatime < cvs_specified_date) { + rev = rcsnum_alloc(); + rcsnum_cpy(rdp->rd_num, rev, 0); + return (rev); + } } if (follow && rdp->rd_next->rn_len != 0) { @@ -3510,6 +3538,6 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) follow = 0; } while (follow); - return NULL; + return (NULL); } diff --git a/usr.bin/cvs/remove.c b/usr.bin/cvs/remove.c index 3f4afeaa6e4..e8797cb22af 100644 --- a/usr.bin/cvs/remove.c +++ b/usr.bin/cvs/remove.c @@ -1,4 +1,4 @@ -/* $OpenBSD: remove.c,v 1.72 2008/02/09 20:04:00 xsa Exp $ */ +/* $OpenBSD: remove.c,v 1.73 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> * @@ -24,7 +24,6 @@ extern char *__progname; -void cvs_remove_local(struct cvs_file *); void cvs_remove_force(struct cvs_file *); static int force_remove = 0; @@ -147,7 +146,8 @@ cvs_remove_local(struct cvs_file *cf) return; } - cvs_file_classify(cf, cvs_directory_tag); + if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_UPDATE) + cvs_file_classify(cf, cvs_directory_tag); if (cf->file_status == FILE_UNKNOWN) { if (verbosity > 1) diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c index 7e65d7a38c9..ecad4cc5566 100644 --- a/usr.bin/cvs/update.c +++ b/usr.bin/cvs/update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: update.c,v 1.135 2008/03/02 19:05:34 tobias Exp $ */ +/* $OpenBSD: update.c,v 1.136 2008/03/08 20:26:34 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -32,12 +32,15 @@ int build_dirs = 0; int reset_option = 0; int reset_tag = 0; char *cvs_specified_tag = NULL; +char *cvs_join_rev1 = NULL; +char *cvs_join_rev2 = NULL; static char *koptstr; static char *dateflag = NULL; static int Aflag = 0; static void update_clear_conflict(struct cvs_file *); +static void update_join_file(struct cvs_file *); struct cvs_cmd cvs_cmd_update = { CVS_OP_UPDATE, CVS_USE_WDIR, "update", @@ -83,6 +86,12 @@ cvs_update(int argc, char **argv) case 'I': break; case 'j': + if (cvs_join_rev1 == NULL) + cvs_join_rev1 = optarg; + else if (cvs_join_rev2 == NULL) + cvs_join_rev2 = optarg; + else + fatal("too many -j options"); break; case 'k': reset_option = 0; @@ -301,10 +310,9 @@ cvs_update_leavedir(struct cvs_file *cf) void cvs_update_local(struct cvs_file *cf) { - char *tag; - int ent_kflag, rcs_kflag, ret, flags; CVSENTRIES *entlist; - char rbuf[CVS_REV_BUFSZ]; + int ent_kflag, rcs_kflag, ret, flags; + char *tag, rbuf[CVS_REV_BUFSZ]; cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path); @@ -417,6 +425,8 @@ cvs_update_local(struct cvs_file *cf) cvs_history_add(CVS_HISTORY_UPDATE_CO, cf, NULL); break; case FILE_MERGE: + d3rev1 = cf->file_ent->ce_rev; + d3rev2 = cf->file_rcsrev; cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_MERGE); if (diff3_conflicts != 0) { @@ -457,6 +467,9 @@ cvs_update_local(struct cvs_file *cf) default: break; } + + if (cvs_join_rev1 != NULL) + update_join_file(cf); } static void @@ -465,7 +478,7 @@ update_clear_conflict(struct cvs_file *cf) time_t now; CVSENTRIES *entlist; char *entry, revbuf[CVS_REV_BUFSZ], timebuf[CVS_TIME_BUFSZ]; - char sticky[CVS_ENT_MAXLINELEN]; + char sticky[CVS_ENT_MAXLINELEN], opt[4]; cvs_log(LP_TRACE, "update_clear_conflict(%s)", cf->file_path); @@ -476,13 +489,17 @@ update_clear_conflict(struct cvs_file *cf) rcsnum_tostr(cf->file_rcsrev, revbuf, sizeof(revbuf)); sticky[0] = '\0'; - if (cf->file_ent->ce_tag != NULL) + if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL) (void)xsnprintf(sticky, sizeof(sticky), "T%s", cf->file_ent->ce_tag); + opt[0] = '\0'; + if (cf->file_ent != NULL && cf->file_ent->ce_opts != NULL) + strlcpy(opt, cf->file_ent->ce_opts, sizeof(opt)); + entry = xmalloc(CVS_ENT_MAXLINELEN); cvs_ent_line_str(cf->file_name, revbuf, timebuf, - cf->file_ent->ce_opts ? : "", sticky, 0, 0, + opt[0] != '\0' ? opt : "", sticky, 0, 0, entry, CVS_ENT_MAXLINELEN); entlist = cvs_ent_open(cf->file_wd); @@ -539,3 +556,133 @@ update_has_conflict_markers(struct cvs_file *cf) xfree(content); return (conflict); } + +void +update_join_file(struct cvs_file *cf) +{ + int flag; + time_t told; + RCSNUM *rev1, *rev2; + const char *state1, *state2; + char rbuf[CVS_REV_BUFSZ], *jrev1, *jrev2, *p; + + rev1 = rev2 = NULL; + jrev1 = jrev2 = NULL; + + jrev1 = xstrdup(cvs_join_rev1); + if (cvs_join_rev2 != NULL) + jrev2 = xstrdup(cvs_join_rev2); + + if (jrev2 == NULL) { + jrev2 = jrev1; + jrev1 = NULL; + } + + told = cvs_specified_date; + + if ((p = strrchr(jrev2, ':')) != NULL) { + (*p++) = '\0'; + cvs_specified_date = cvs_date_parse(p); + } + + rev2 = rcs_translate_tag(jrev2, cf->file_rcs); + cvs_specified_date = told; + + if (jrev1 != NULL) { + if ((p = strrchr(jrev1, ':')) != NULL) { + (*p++) = '\0'; + cvs_specified_date = cvs_date_parse(p); + } + + rev1 = rcs_translate_tag(jrev1, cf->file_rcs); + cvs_specified_date = told; + } else { + if (rev2 == NULL) + goto out; + + rev1 = rcsnum_alloc(); + rcsnum_cpy(cf->file_rcsrev, rev1, 0); + } + + state1 = state2 = RCS_STATE_DEAD; + + if (rev1 != NULL) + state1 = rcs_state_get(cf->file_rcs, rev1); + if (rev2 != NULL) + state2 = rcs_state_get(cf->file_rcs, rev2); + + if (rev2 == NULL || !strcmp(state2, RCS_STATE_DEAD)) { + if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) + goto out; + + if (cf->file_status == FILE_REMOVED || + cf->file_rcs->rf_dead == 1) + goto out; + + if (cf->file_status == FILE_MODIFIED || + cf->file_status == FILE_ADDED) + goto out; + + (void)unlink(cf->file_path); + (void)close(cf->fd); + cf->fd = -1; + cvs_remove_local(cf); + goto out; + } + + if (cf->file_ent != NULL) { + if (!rcsnum_cmp(cf->file_ent->ce_rev, rev2, 0)) + goto out; + } + + if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) { + if (cf->fd != -1) { + cvs_printf("%s exists but has been added in %s\n", + cf->file_path, cvs_join_rev2); + } else { + cvs_checkout_file(cf, cf->file_rcsrev, NULL, 0); + cvs_add_local(cf); + } + goto out; + } + + if (cf->fd == -1) + goto out; + + flag = rcs_kwexp_get(cf->file_rcs); + if (flag & RCS_KWEXP_NONE) { + cvs_printf("non-mergable file: %s needs merge!\n", + cf->file_path); + goto out; + } + + cvs_printf("joining "); + rcsnum_tostr(rev1, rbuf, sizeof(rbuf)); + cvs_printf("%s ", rbuf); + + rcsnum_tostr(rev2, rbuf, sizeof(rbuf)); + cvs_printf("%s ", rbuf); + + rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf)); + cvs_printf("into %s (%s)\n", cf->file_path, rbuf); + + d3rev1 = rev1; + d3rev2 = rev2; + cvs_checkout_file(cf, cf->file_rcsrev, NULL, CO_MERGE); + + if (diff3_conflicts == 0) { + update_clear_conflict(cf); + cvs_history_add(CVS_HISTORY_UPDATE_MERGED, cf, NULL); + } + +out: + if (rev1 != NULL) + rcsnum_free(rev1); + if (rev2 != NULL) + rcsnum_free(rev2); + + if (jrev1 != NULL) + xfree(jrev1); + if (jrev2 != NULL) + xfree(jrev2); +} |