xref: /dflybsd-src/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Merge RCS revisions.  */
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
486d7f5d3SJohn Marino    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
586d7f5d3SJohn Marino    Distributed under license by the Free Software Foundation, Inc.
686d7f5d3SJohn Marino 
786d7f5d3SJohn Marino This file is part of RCS.
886d7f5d3SJohn Marino 
986d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
1086d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
1186d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
1286d7f5d3SJohn Marino any later version.
1386d7f5d3SJohn Marino 
1486d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
1586d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1686d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1786d7f5d3SJohn Marino GNU General Public License for more details.
1886d7f5d3SJohn Marino 
1986d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
2086d7f5d3SJohn Marino along with RCS; see the file COPYING.
2186d7f5d3SJohn Marino If not, write to the Free Software Foundation,
2286d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino Report problems and direct all questions to:
2586d7f5d3SJohn Marino 
2686d7f5d3SJohn Marino     rcs-bugs@cs.purdue.edu
2786d7f5d3SJohn Marino 
2886d7f5d3SJohn Marino */
2986d7f5d3SJohn Marino 
3086d7f5d3SJohn Marino /*
3186d7f5d3SJohn Marino  * $FreeBSD: src/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c,v 1.7 1999/08/27 23:36:58 peter Exp $
3286d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c,v 1.2 2003/06/17 04:25:48 dillon Exp $
3386d7f5d3SJohn Marino  *
3486d7f5d3SJohn Marino  * Revision 5.15  1995/06/16 06:19:24  eggert
3586d7f5d3SJohn Marino  * Update FSF address.
3686d7f5d3SJohn Marino  *
3786d7f5d3SJohn Marino  * Revision 5.14  1995/06/01 16:23:43  eggert
3886d7f5d3SJohn Marino  * (main): Report an error if -kb, so don't worry about binary stdout.
3986d7f5d3SJohn Marino  * Punctuate messages properly.  Rewrite to avoid `goto end'.
4086d7f5d3SJohn Marino  *
4186d7f5d3SJohn Marino  * Revision 5.13  1994/03/17 14:05:48  eggert
4286d7f5d3SJohn Marino  * Specify subprocess input via file descriptor, not file name.  Remove lint.
4386d7f5d3SJohn Marino  *
4486d7f5d3SJohn Marino  * Revision 5.12  1993/11/09 17:40:15  eggert
4586d7f5d3SJohn Marino  * -V now prints version on stdout and exits.  Don't print usage twice.
4686d7f5d3SJohn Marino  *
4786d7f5d3SJohn Marino  * Revision 5.11  1993/11/03 17:42:27  eggert
4886d7f5d3SJohn Marino  * Add -A, -E, -e, -z.  Ignore -T.  Allow up to three file labels.
4986d7f5d3SJohn Marino  * Pass -Vn to `co'.  Pass unexpanded revision name to `co', so that Name works.
5086d7f5d3SJohn Marino  *
5186d7f5d3SJohn Marino  * Revision 5.10  1992/07/28  16:12:44  eggert
5286d7f5d3SJohn Marino  * Add -V.
5386d7f5d3SJohn Marino  *
5486d7f5d3SJohn Marino  * Revision 5.9  1992/01/24  18:44:19  eggert
5586d7f5d3SJohn Marino  * lint -> RCS_lint
5686d7f5d3SJohn Marino  *
5786d7f5d3SJohn Marino  * Revision 5.8  1992/01/06  02:42:34  eggert
5886d7f5d3SJohn Marino  * Update usage string.
5986d7f5d3SJohn Marino  *
6086d7f5d3SJohn Marino  * Revision 5.7  1991/11/20  17:58:09  eggert
6186d7f5d3SJohn Marino  * Don't Iopen(f, "r+"); it's not portable.
6286d7f5d3SJohn Marino  *
6386d7f5d3SJohn Marino  * Revision 5.6  1991/08/19  03:13:55  eggert
6486d7f5d3SJohn Marino  * Add -r$.  Tune.
6586d7f5d3SJohn Marino  *
6686d7f5d3SJohn Marino  * Revision 5.5  1991/04/21  11:58:27  eggert
6786d7f5d3SJohn Marino  * Add -x, RCSINIT, MS-DOS support.
6886d7f5d3SJohn Marino  *
6986d7f5d3SJohn Marino  * Revision 5.4  1991/02/25  07:12:43  eggert
7086d7f5d3SJohn Marino  * Merging a revision to itself is no longer an error.
7186d7f5d3SJohn Marino  *
7286d7f5d3SJohn Marino  * Revision 5.3  1990/11/01  05:03:50  eggert
7386d7f5d3SJohn Marino  * Remove unneeded setid check.
7486d7f5d3SJohn Marino  *
7586d7f5d3SJohn Marino  * Revision 5.2  1990/09/04  08:02:28  eggert
7686d7f5d3SJohn Marino  * Check for I/O error when reading working file.
7786d7f5d3SJohn Marino  *
7886d7f5d3SJohn Marino  * Revision 5.1  1990/08/29  07:14:04  eggert
7986d7f5d3SJohn Marino  * Add -q.  Pass -L options to merge.
8086d7f5d3SJohn Marino  *
8186d7f5d3SJohn Marino  * Revision 5.0  1990/08/22  08:13:41  eggert
8286d7f5d3SJohn Marino  * Propagate merge's exit status.
8386d7f5d3SJohn Marino  * Remove compile-time limits; use malloc instead.
8486d7f5d3SJohn Marino  * Make lock and temp files faster and safer.  Ansify and Posixate.  Add -V.
8586d7f5d3SJohn Marino  * Don't use access().  Tune.
8686d7f5d3SJohn Marino  *
8786d7f5d3SJohn Marino  * Revision 4.5  89/05/01  15:13:16  narten
8886d7f5d3SJohn Marino  * changed copyright header to reflect current distribution rules
8986d7f5d3SJohn Marino  *
9086d7f5d3SJohn Marino  * Revision 4.4  88/08/09  19:13:13  eggert
9186d7f5d3SJohn Marino  * Beware merging into a readonly file.
9286d7f5d3SJohn Marino  * Beware merging a revision to itself (no change).
9386d7f5d3SJohn Marino  * Use execv(), not system(); yield exit status like diff(1)'s.
9486d7f5d3SJohn Marino  *
9586d7f5d3SJohn Marino  * Revision 4.3  87/10/18  10:38:02  narten
9686d7f5d3SJohn Marino  * Updating version numbers. Changes relative to version 1.1
9786d7f5d3SJohn Marino  * actually relative to 4.1
9886d7f5d3SJohn Marino  *
9986d7f5d3SJohn Marino  * Revision 1.3  87/09/24  14:00:31  narten
10086d7f5d3SJohn Marino  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
10186d7f5d3SJohn Marino  * warnings)
10286d7f5d3SJohn Marino  *
10386d7f5d3SJohn Marino  * Revision 1.2  87/03/27  14:22:36  jenkins
10486d7f5d3SJohn Marino  * Port to suns
10586d7f5d3SJohn Marino  *
10686d7f5d3SJohn Marino  * Revision 4.1  83/03/28  11:14:57  wft
10786d7f5d3SJohn Marino  * Added handling of default branch.
10886d7f5d3SJohn Marino  *
10986d7f5d3SJohn Marino  * Revision 3.3  82/12/24  15:29:00  wft
11086d7f5d3SJohn Marino  * Added call to catchsig().
11186d7f5d3SJohn Marino  *
11286d7f5d3SJohn Marino  * Revision 3.2  82/12/10  21:32:02  wft
11386d7f5d3SJohn Marino  * Replaced getdelta() with gettree(); improved error messages.
11486d7f5d3SJohn Marino  *
11586d7f5d3SJohn Marino  * Revision 3.1  82/11/28  19:27:44  wft
11686d7f5d3SJohn Marino  * Initial revision.
11786d7f5d3SJohn Marino  *
11886d7f5d3SJohn Marino  */
11986d7f5d3SJohn Marino #include "rcsbase.h"
12086d7f5d3SJohn Marino 
12186d7f5d3SJohn Marino static char const co[] = CO;
12286d7f5d3SJohn Marino 
12386d7f5d3SJohn Marino mainProg(rcsmergeId, "rcsmerge", "$DragonFly: src/gnu/usr.bin/rcs/rcsmerge/rcsmerge.c,v 1.2 2003/06/17 04:25:48 dillon Exp $")
12486d7f5d3SJohn Marino {
12586d7f5d3SJohn Marino 	static char const cmdusage[] =
12686d7f5d3SJohn Marino 		"\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] -ksubst -{pq}[rev] -Vn -xsuff -zzone file";
12786d7f5d3SJohn Marino 	static char const quietarg[] = "-q";
12886d7f5d3SJohn Marino 
12986d7f5d3SJohn Marino 	register int i;
13086d7f5d3SJohn Marino 	char *a, **newargv;
13186d7f5d3SJohn Marino 	char const *arg[3];
13286d7f5d3SJohn Marino 	char const *rev[3], *xrev[3]; /*revision numbers*/
13386d7f5d3SJohn Marino 	char const *edarg, *expandarg, *suffixarg, *versionarg, *zonearg;
13486d7f5d3SJohn Marino         int tostdout;
13586d7f5d3SJohn Marino 	int status;
13686d7f5d3SJohn Marino 	RILE *workptr;
13786d7f5d3SJohn Marino 	struct buf commarg;
13886d7f5d3SJohn Marino 	struct buf numericrev; /* holds expanded revision number */
13986d7f5d3SJohn Marino 	struct hshentries *gendeltas; /* deltas to be generated */
14086d7f5d3SJohn Marino         struct hshentry * target;
14186d7f5d3SJohn Marino 
14286d7f5d3SJohn Marino 	bufautobegin(&commarg);
14386d7f5d3SJohn Marino 	bufautobegin(&numericrev);
14486d7f5d3SJohn Marino 	edarg = rev[1] = rev[2] = 0;
14586d7f5d3SJohn Marino 	status = 0; /* Keep lint happy.  */
14686d7f5d3SJohn Marino 	tostdout = false;
14786d7f5d3SJohn Marino 	expandarg = suffixarg = versionarg = zonearg = quietarg; /* no-op */
14886d7f5d3SJohn Marino 	suffixes = X_DEFAULT;
14986d7f5d3SJohn Marino 
15086d7f5d3SJohn Marino 	argc = getRCSINIT(argc, argv, &newargv);
15186d7f5d3SJohn Marino 	argv = newargv;
15286d7f5d3SJohn Marino 	while (a = *++argv,  0<--argc && *a++=='-') {
15386d7f5d3SJohn Marino 		switch (*a++) {
15486d7f5d3SJohn Marino                 case 'p':
15586d7f5d3SJohn Marino                         tostdout=true;
15686d7f5d3SJohn Marino 			goto revno;
15786d7f5d3SJohn Marino 
15886d7f5d3SJohn Marino 		case 'q':
15986d7f5d3SJohn Marino 			quietflag = true;
16086d7f5d3SJohn Marino 		revno:
16186d7f5d3SJohn Marino 			if (!*a)
16286d7f5d3SJohn Marino 				break;
16386d7f5d3SJohn Marino                         /* falls into -r */
16486d7f5d3SJohn Marino                 case 'r':
16586d7f5d3SJohn Marino 			if (!rev[1])
16686d7f5d3SJohn Marino 				rev[1] = a;
16786d7f5d3SJohn Marino 			else if (!rev[2])
16886d7f5d3SJohn Marino 				rev[2] = a;
16986d7f5d3SJohn Marino 			else
17086d7f5d3SJohn Marino 				error("too many revision numbers");
17186d7f5d3SJohn Marino                         break;
17286d7f5d3SJohn Marino 
17386d7f5d3SJohn Marino 		case 'A': case 'E': case 'e':
17486d7f5d3SJohn Marino 			if (*a)
17586d7f5d3SJohn Marino 				goto unknown;
17686d7f5d3SJohn Marino 			edarg = *argv;
17786d7f5d3SJohn Marino 			break;
17886d7f5d3SJohn Marino 
17986d7f5d3SJohn Marino 		case 'x':
18086d7f5d3SJohn Marino 			suffixarg = *argv;
18186d7f5d3SJohn Marino 			suffixes = a;
18286d7f5d3SJohn Marino 			break;
18386d7f5d3SJohn Marino 		case 'z':
18486d7f5d3SJohn Marino 			zonearg = *argv;
18586d7f5d3SJohn Marino 			zone_set(a);
18686d7f5d3SJohn Marino 			break;
18786d7f5d3SJohn Marino 		case 'T':
18886d7f5d3SJohn Marino 			/* Ignore -T, so that RCSINIT can contain -T.  */
18986d7f5d3SJohn Marino 			if (*a)
19086d7f5d3SJohn Marino 				goto unknown;
19186d7f5d3SJohn Marino 			break;
19286d7f5d3SJohn Marino 		case 'V':
19386d7f5d3SJohn Marino 			versionarg = *argv;
19486d7f5d3SJohn Marino 			setRCSversion(versionarg);
19586d7f5d3SJohn Marino 			break;
19686d7f5d3SJohn Marino 
19786d7f5d3SJohn Marino 		case 'k':
19886d7f5d3SJohn Marino 			expandarg = *argv;
19986d7f5d3SJohn Marino 			if (0 <= str2expmode(expandarg+2))
20086d7f5d3SJohn Marino 			    break;
20186d7f5d3SJohn Marino 			/* fall into */
20286d7f5d3SJohn Marino                 default:
20386d7f5d3SJohn Marino 		unknown:
20486d7f5d3SJohn Marino 			error("unknown option: %s%s", *argv, cmdusage);
20586d7f5d3SJohn Marino                 };
20686d7f5d3SJohn Marino         } /* end of option processing */
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino 	if (!rev[1]) faterror("no base revision number given");
20986d7f5d3SJohn Marino 
21086d7f5d3SJohn Marino 	/* Now handle all pathnames.  */
21186d7f5d3SJohn Marino 
21286d7f5d3SJohn Marino 	if (!nerror) {
21386d7f5d3SJohn Marino 	    if (argc < 1)
21486d7f5d3SJohn Marino 		faterror("no input file%s", cmdusage);
21586d7f5d3SJohn Marino 	    if (0 < pairnames(argc, argv, rcsreadopen, true, false)) {
21686d7f5d3SJohn Marino 
21786d7f5d3SJohn Marino                 if (argc>2  ||  (argc==2 && argv[1]))
21886d7f5d3SJohn Marino 			warn("excess arguments ignored");
21986d7f5d3SJohn Marino 		if (Expand == BINARY_EXPAND)
22086d7f5d3SJohn Marino 			workerror("merging binary files");
22186d7f5d3SJohn Marino 		diagnose("RCS file: %s\n", RCSname);
22286d7f5d3SJohn Marino 		if (!(workptr = Iopen(workname, FOPEN_R_WORK, (struct stat*)0)))
22386d7f5d3SJohn Marino 			efaterror(workname);
22486d7f5d3SJohn Marino 
22586d7f5d3SJohn Marino                 gettree();  /* reads in the delta tree */
22686d7f5d3SJohn Marino 
22786d7f5d3SJohn Marino 		if (!Head) rcsfaterror("no revisions present");
22886d7f5d3SJohn Marino 
22986d7f5d3SJohn Marino 		if (!*rev[1])
23086d7f5d3SJohn Marino 			rev[1]  =  Dbranch ? Dbranch : Head->num;
23186d7f5d3SJohn Marino 		if (fexpandsym(rev[1], &numericrev, workptr)
23286d7f5d3SJohn Marino 		    && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char*)0, &gendeltas))
23386d7f5d3SJohn Marino 		) {
23486d7f5d3SJohn Marino 		  xrev[1] = target->num;
23586d7f5d3SJohn Marino 		  if (!rev[2] || !*rev[2])
23686d7f5d3SJohn Marino 			rev[2]  =  Dbranch ? Dbranch : Head->num;
23786d7f5d3SJohn Marino 		  if (fexpandsym(rev[2], &numericrev, workptr)
23886d7f5d3SJohn Marino 		      && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char *)0, &gendeltas))
23986d7f5d3SJohn Marino 		  ) {
24086d7f5d3SJohn Marino 		    xrev[2] = target->num;
24186d7f5d3SJohn Marino 
24286d7f5d3SJohn Marino 		    if (strcmp(xrev[1],xrev[2]) == 0) {
24386d7f5d3SJohn Marino 		      if (tostdout) {
24486d7f5d3SJohn Marino 			fastcopy(workptr, stdout);
24586d7f5d3SJohn Marino 			Ofclose(stdout);
24686d7f5d3SJohn Marino 		      }
24786d7f5d3SJohn Marino 		    } else {
24886d7f5d3SJohn Marino 		      Izclose(&workptr);
24986d7f5d3SJohn Marino 
25086d7f5d3SJohn Marino 		      for (i=1; i<=2; i++) {
25186d7f5d3SJohn Marino 			diagnose("retrieving revision %s\n", xrev[i]);
25286d7f5d3SJohn Marino 			bufscpy(&commarg, "-p");
25386d7f5d3SJohn Marino 			bufscat(&commarg, rev[i]); /* not xrev[i], for $Name's sake */
25486d7f5d3SJohn Marino 			if (run(
25586d7f5d3SJohn Marino 				-1,
25686d7f5d3SJohn Marino 				/* Do not collide with merger.c maketemp().  */
25786d7f5d3SJohn Marino 				arg[i] = maketemp(i+2),
25886d7f5d3SJohn Marino 				co, quietarg, commarg.string,
25986d7f5d3SJohn Marino 				expandarg, suffixarg, versionarg, zonearg,
26086d7f5d3SJohn Marino 				RCSname, (char*)0
26186d7f5d3SJohn Marino 			))
26286d7f5d3SJohn Marino 				rcsfaterror("co failed");
26386d7f5d3SJohn Marino 		      }
26486d7f5d3SJohn Marino 		      diagnose("Merging differences between %s and %s into %s%s\n",
26586d7f5d3SJohn Marino 			       xrev[1], xrev[2], workname,
26686d7f5d3SJohn Marino 			       tostdout?"; result to stdout":"");
26786d7f5d3SJohn Marino 
26886d7f5d3SJohn Marino 		      arg[0] = xrev[0] = workname;
26986d7f5d3SJohn Marino 		      status = merge(tostdout, edarg, xrev, arg);
27086d7f5d3SJohn Marino 		    }
27186d7f5d3SJohn Marino 		  }
27286d7f5d3SJohn Marino 		}
27386d7f5d3SJohn Marino 
27486d7f5d3SJohn Marino 		Izclose(&workptr);
27586d7f5d3SJohn Marino 	    }
27686d7f5d3SJohn Marino         }
27786d7f5d3SJohn Marino 	tempunlink();
27886d7f5d3SJohn Marino 	exitmain(nerror ? DIFF_TROUBLE : status);
27986d7f5d3SJohn Marino }
28086d7f5d3SJohn Marino 
28186d7f5d3SJohn Marino #if RCS_lint
28286d7f5d3SJohn Marino #	define exiterr rmergeExit
28386d7f5d3SJohn Marino #endif
28486d7f5d3SJohn Marino 	void
exiterr()28586d7f5d3SJohn Marino exiterr()
28686d7f5d3SJohn Marino {
28786d7f5d3SJohn Marino 	tempunlink();
28886d7f5d3SJohn Marino 	_exit(DIFF_TROUBLE);
28986d7f5d3SJohn Marino }
290