111894Speter/* Merge RCS revisions.  */
29Sjkh
311894Speter/* Copyright 1982, 1988, 1989 Walter Tichy
411894Speter   Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
59Sjkh   Distributed under license by the Free Software Foundation, Inc.
69Sjkh
79SjkhThis file is part of RCS.
89Sjkh
99SjkhRCS is free software; you can redistribute it and/or modify
109Sjkhit under the terms of the GNU General Public License as published by
119Sjkhthe Free Software Foundation; either version 2, or (at your option)
129Sjkhany later version.
139Sjkh
149SjkhRCS is distributed in the hope that it will be useful,
159Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of
169SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
179SjkhGNU General Public License for more details.
189Sjkh
199SjkhYou should have received a copy of the GNU General Public License
2011894Speteralong with RCS; see the file COPYING.
2111894SpeterIf not, write to the Free Software Foundation,
2211894Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
239Sjkh
249SjkhReport problems and direct all questions to:
259Sjkh
269Sjkh    rcs-bugs@cs.purdue.edu
279Sjkh
289Sjkh*/
299Sjkh
3011894Speter/*
3111894Speter * Revision 5.15  1995/06/16 06:19:24  eggert
3211894Speter * Update FSF address.
338858Srgrimes *
3411894Speter * Revision 5.14  1995/06/01 16:23:43  eggert
3511894Speter * (main): Report an error if -kb, so don't worry about binary stdout.
3611894Speter * Punctuate messages properly.  Rewrite to avoid `goto end'.
3711894Speter *
3811894Speter * Revision 5.13  1994/03/17 14:05:48  eggert
3911894Speter * Specify subprocess input via file descriptor, not file name.  Remove lint.
4011894Speter *
4111894Speter * Revision 5.12  1993/11/09 17:40:15  eggert
4211894Speter * -V now prints version on stdout and exits.  Don't print usage twice.
4311894Speter *
4411894Speter * Revision 5.11  1993/11/03 17:42:27  eggert
4511894Speter * Add -A, -E, -e, -z.  Ignore -T.  Allow up to three file labels.
4611894Speter * Pass -Vn to `co'.  Pass unexpanded revision name to `co', so that Name works.
4711894Speter *
4811894Speter * Revision 5.10  1992/07/28  16:12:44  eggert
4911894Speter * Add -V.
5011894Speter *
5111894Speter * Revision 5.9  1992/01/24  18:44:19  eggert
5211894Speter * lint -> RCS_lint
5311894Speter *
5411894Speter * Revision 5.8  1992/01/06  02:42:34  eggert
5511894Speter * Update usage string.
5611894Speter *
579Sjkh * Revision 5.7  1991/11/20  17:58:09  eggert
589Sjkh * Don't Iopen(f, "r+"); it's not portable.
599Sjkh *
609Sjkh * Revision 5.6  1991/08/19  03:13:55  eggert
619Sjkh * Add -r$.  Tune.
629Sjkh *
639Sjkh * Revision 5.5  1991/04/21  11:58:27  eggert
649Sjkh * Add -x, RCSINIT, MS-DOS support.
659Sjkh *
669Sjkh * Revision 5.4  1991/02/25  07:12:43  eggert
679Sjkh * Merging a revision to itself is no longer an error.
689Sjkh *
699Sjkh * Revision 5.3  1990/11/01  05:03:50  eggert
709Sjkh * Remove unneeded setid check.
719Sjkh *
729Sjkh * Revision 5.2  1990/09/04  08:02:28  eggert
739Sjkh * Check for I/O error when reading working file.
749Sjkh *
759Sjkh * Revision 5.1  1990/08/29  07:14:04  eggert
769Sjkh * Add -q.  Pass -L options to merge.
779Sjkh *
789Sjkh * Revision 5.0  1990/08/22  08:13:41  eggert
799Sjkh * Propagate merge's exit status.
809Sjkh * Remove compile-time limits; use malloc instead.
819Sjkh * Make lock and temp files faster and safer.  Ansify and Posixate.  Add -V.
829Sjkh * Don't use access().  Tune.
839Sjkh *
849Sjkh * Revision 4.5  89/05/01  15:13:16  narten
859Sjkh * changed copyright header to reflect current distribution rules
868858Srgrimes *
879Sjkh * Revision 4.4  88/08/09  19:13:13  eggert
889Sjkh * Beware merging into a readonly file.
899Sjkh * Beware merging a revision to itself (no change).
909Sjkh * Use execv(), not system(); yield exit status like diff(1)'s.
918858Srgrimes *
929Sjkh * Revision 4.3  87/10/18  10:38:02  narten
938858Srgrimes * Updating version numbers. Changes relative to version 1.1
949Sjkh * actually relative to 4.1
958858Srgrimes *
969Sjkh * Revision 1.3  87/09/24  14:00:31  narten
978858Srgrimes * Sources now pass through lint (if you ignore printf/sprintf/fprintf
989Sjkh * warnings)
998858Srgrimes *
1009Sjkh * Revision 1.2  87/03/27  14:22:36  jenkins
1019Sjkh * Port to suns
1028858Srgrimes *
1039Sjkh * Revision 4.1  83/03/28  11:14:57  wft
1049Sjkh * Added handling of default branch.
1058858Srgrimes *
1069Sjkh * Revision 3.3  82/12/24  15:29:00  wft
1079Sjkh * Added call to catchsig().
1089Sjkh *
1099Sjkh * Revision 3.2  82/12/10  21:32:02  wft
1109Sjkh * Replaced getdelta() with gettree(); improved error messages.
1119Sjkh *
1129Sjkh * Revision 3.1  82/11/28  19:27:44  wft
1139Sjkh * Initial revision.
1149Sjkh *
1159Sjkh */
1169Sjkh#include "rcsbase.h"
1179Sjkh
1189Sjkhstatic char const co[] = CO;
1199Sjkh
12050472SpetermainProg(rcsmergeId, "rcsmerge", "$FreeBSD$")
1219Sjkh{
1229Sjkh	static char const cmdusage[] =
12311894Speter		"\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] -ksubst -{pq}[rev] -Vn -xsuff -zzone file";
1249Sjkh	static char const quietarg[] = "-q";
1259Sjkh
1269Sjkh	register int i;
1279Sjkh	char *a, **newargv;
1289Sjkh	char const *arg[3];
12911894Speter	char const *rev[3], *xrev[3]; /*revision numbers*/
13011894Speter	char const *edarg, *expandarg, *suffixarg, *versionarg, *zonearg;
1319Sjkh        int tostdout;
1329Sjkh	int status;
1339Sjkh	RILE *workptr;
1349Sjkh	struct buf commarg;
1359Sjkh	struct buf numericrev; /* holds expanded revision number */
1369Sjkh	struct hshentries *gendeltas; /* deltas to be generated */
1379Sjkh        struct hshentry * target;
1389Sjkh
1399Sjkh	bufautobegin(&commarg);
1409Sjkh	bufautobegin(&numericrev);
14111894Speter	edarg = rev[1] = rev[2] = 0;
1429Sjkh	status = 0; /* Keep lint happy.  */
1439Sjkh	tostdout = false;
14411894Speter	expandarg = suffixarg = versionarg = zonearg = quietarg; /* no-op */
1459Sjkh	suffixes = X_DEFAULT;
1469Sjkh
1479Sjkh	argc = getRCSINIT(argc, argv, &newargv);
1489Sjkh	argv = newargv;
1499Sjkh	while (a = *++argv,  0<--argc && *a++=='-') {
1509Sjkh		switch (*a++) {
1519Sjkh                case 'p':
1529Sjkh                        tostdout=true;
1539Sjkh			goto revno;
1549Sjkh
1559Sjkh		case 'q':
1569Sjkh			quietflag = true;
1579Sjkh		revno:
1589Sjkh			if (!*a)
1599Sjkh				break;
1609Sjkh                        /* falls into -r */
1619Sjkh                case 'r':
16211894Speter			if (!rev[1])
1639Sjkh				rev[1] = a;
16411894Speter			else if (!rev[2])
16511894Speter				rev[2] = a;
1669Sjkh			else
16711894Speter				error("too many revision numbers");
1689Sjkh                        break;
16911894Speter
17011894Speter		case 'A': case 'E': case 'e':
17111894Speter			if (*a)
17211894Speter				goto unknown;
17311894Speter			edarg = *argv;
17411894Speter			break;
17511894Speter
1769Sjkh		case 'x':
17711894Speter			suffixarg = *argv;
1789Sjkh			suffixes = a;
1799Sjkh			break;
18011894Speter		case 'z':
18111894Speter			zonearg = *argv;
18211894Speter			zone_set(a);
18311894Speter			break;
18411894Speter		case 'T':
18511894Speter			/* Ignore -T, so that RCSINIT can contain -T.  */
18611894Speter			if (*a)
18711894Speter				goto unknown;
18811894Speter			break;
1899Sjkh		case 'V':
1909Sjkh			versionarg = *argv;
1919Sjkh			setRCSversion(versionarg);
1929Sjkh			break;
1939Sjkh
1949Sjkh		case 'k':
1959Sjkh			expandarg = *argv;
1969Sjkh			if (0 <= str2expmode(expandarg+2))
1979Sjkh			    break;
1989Sjkh			/* fall into */
1999Sjkh                default:
20011894Speter		unknown:
20111894Speter			error("unknown option: %s%s", *argv, cmdusage);
2029Sjkh                };
2039Sjkh        } /* end of option processing */
2049Sjkh
20511894Speter	if (!rev[1]) faterror("no base revision number given");
2069Sjkh
20711894Speter	/* Now handle all pathnames.  */
2089Sjkh
20911894Speter	if (!nerror) {
21011894Speter	    if (argc < 1)
21111894Speter		faterror("no input file%s", cmdusage);
21211894Speter	    if (0 < pairnames(argc, argv, rcsreadopen, true, false)) {
2139Sjkh
21411894Speter                if (argc>2  ||  (argc==2 && argv[1]))
21511894Speter			warn("excess arguments ignored");
21611894Speter		if (Expand == BINARY_EXPAND)
21711894Speter			workerror("merging binary files");
21811894Speter		diagnose("RCS file: %s\n", RCSname);
21911894Speter		if (!(workptr = Iopen(workname, FOPEN_R_WORK, (struct stat*)0)))
22011894Speter			efaterror(workname);
2219Sjkh
2229Sjkh                gettree();  /* reads in the delta tree */
2239Sjkh
22411894Speter		if (!Head) rcsfaterror("no revisions present");
2259Sjkh
22611894Speter		if (!*rev[1])
2279Sjkh			rev[1]  =  Dbranch ? Dbranch : Head->num;
22811894Speter		if (fexpandsym(rev[1], &numericrev, workptr)
22911894Speter		    && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char*)0, &gendeltas))
23011894Speter		) {
23111894Speter		  xrev[1] = target->num;
23211894Speter		  if (!rev[2] || !*rev[2])
23311894Speter			rev[2]  =  Dbranch ? Dbranch : Head->num;
23411894Speter		  if (fexpandsym(rev[2], &numericrev, workptr)
23511894Speter		      && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char *)0, &gendeltas))
23611894Speter		  ) {
23711894Speter		    xrev[2] = target->num;
2389Sjkh
23911894Speter		    if (strcmp(xrev[1],xrev[2]) == 0) {
24011894Speter		      if (tostdout) {
24111894Speter			fastcopy(workptr, stdout);
24211894Speter			Ofclose(stdout);
24311894Speter		      }
24411894Speter		    } else {
24511894Speter		      Izclose(&workptr);
2469Sjkh
24711894Speter		      for (i=1; i<=2; i++) {
24811894Speter			diagnose("retrieving revision %s\n", xrev[i]);
2499Sjkh			bufscpy(&commarg, "-p");
25011894Speter			bufscat(&commarg, rev[i]); /* not xrev[i], for $Name's sake */
2519Sjkh			if (run(
25211894Speter				-1,
2539Sjkh				/* Do not collide with merger.c maketemp().  */
25411894Speter				arg[i] = maketemp(i+2),
25511894Speter				co, quietarg, commarg.string,
25611894Speter				expandarg, suffixarg, versionarg, zonearg,
25711894Speter				RCSname, (char*)0
2589Sjkh			))
25911894Speter				rcsfaterror("co failed");
26011894Speter		      }
26111894Speter		      diagnose("Merging differences between %s and %s into %s%s\n",
26211894Speter			       xrev[1], xrev[2], workname,
26311894Speter			       tostdout?"; result to stdout":"");
26411894Speter
26511894Speter		      arg[0] = xrev[0] = workname;
26611894Speter		      status = merge(tostdout, edarg, xrev, arg);
26711894Speter		    }
26811894Speter		  }
2699Sjkh		}
2709Sjkh
27111894Speter		Izclose(&workptr);
27211894Speter	    }
2739Sjkh        }
2749Sjkh	tempunlink();
2759Sjkh	exitmain(nerror ? DIFF_TROUBLE : status);
2769Sjkh}
2779Sjkh
27811894Speter#if RCS_lint
2799Sjkh#	define exiterr rmergeExit
2809Sjkh#endif
28111894Speter	void
2829Sjkhexiterr()
2839Sjkh{
2849Sjkh	tempunlink();
2859Sjkh	_exit(DIFF_TROUBLE);
2869Sjkh}
287