summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris Vink <joris@cvs.openbsd.org>2008-03-08 20:26:35 +0000
committerJoris Vink <joris@cvs.openbsd.org>2008-03-08 20:26:35 +0000
commitf180fa31bef240be9e356681d7f12aa11cec5f8b (patch)
treec184dbcda05d69b8cb1bfed5886e59067766b1cc
parent22b225cb417a08d1f3be81c45427e2232d860a85 (diff)
add checkout/update -j support.
still has some rough edges.
-rw-r--r--usr.bin/cvs/add.c6
-rw-r--r--usr.bin/cvs/checkout.c17
-rw-r--r--usr.bin/cvs/cvs.h6
-rw-r--r--usr.bin/cvs/diff.h4
-rw-r--r--usr.bin/cvs/diff3.c67
-rw-r--r--usr.bin/cvs/file.c5
-rw-r--r--usr.bin/cvs/rcs.c68
-rw-r--r--usr.bin/cvs/remove.c6
-rw-r--r--usr.bin/cvs/update.c161
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);
+}