/* three-way file merge internals */

/* Copyright 1991, 1992, 1993, 1994 Paul Eggert
   Distributed under license by the Free Software Foundation, Inc.

This file is part of RCS.

RCS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

RCS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with RCS; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

Report problems and direct all questions to:

    rcs-bugs@cs.purdue.edu

*/

#include "rcsbase.h"

libId(mergerId, "$Id: merger.c,v 1.5 1994/03/17 14:05:48 eggert Exp $")

	static char const *normalize_arg P((char const*,char**));
	static char const *
normalize_arg(s, b)
	char const *s;
	char **b;
/*
 * If S looks like an option, prepend ./ to it.  Yield the result.
 * Set *B to the address of any storage that was allocated..
 */
{
	char *t;
	switch (*s) {
		case '-': case '+':
			*b = t = testalloc(strlen(s) + 3);
			VOID sprintf(t, ".%c%s", SLASH, s);
			return t;
		default:
			*b = 0;
			return s;
	}
}

	int
merge(tostdout, edarg, label, argv)
	int tostdout;
	char const *edarg;
	char const *const label[3];
	char const *const argv[3];
/*
 * Do `merge [-p] EDARG -L l0 -L l1 -L l2 a0 a1 a2',
 * where TOSTDOUT specifies whether -p is present,
 * EDARG gives the editing type (e.g. "-A", or null for the default),
 * LABEL gives l0, l1 and l2, and ARGV gives a0, a1 and a2.
 * Yield DIFF_SUCCESS or DIFF_FAILURE.
 */
{
	register int i;
	FILE *f;
	RILE *rt;
	char const *a[3], *t;
	char *b[3];
	int s;
#if !DIFF3_BIN
	char const *d[2];
#endif

	for (i=3; 0<=--i; )
		a[i] = normalize_arg(argv[i], &b[i]);
	
	if (!edarg)
#		if DIFF3_A
			edarg = "-A";
#		else
			edarg = "-E";
#		endif

#if DIFF3_BIN
	t = 0;
	if (!tostdout)
		t = maketemp(0);
	s = run(
		-1, t,
		DIFF3, edarg, "-am", "-L", label[0],
#		if DIFF3_A
			"-L", label[1],
#		endif
		"-L", label[2],
		a[0], a[1], a[2], (char*)0
	);
	switch (s) {
		case DIFF_SUCCESS:
			break;
		case DIFF_FAILURE:
			warn("conflicts during merge");
			break;
		default:
			exiterr();
	}
	if (t) {
		if (!(f = fopen(argv[0], FOPEN_W)))
			efaterror(argv[0]);
		if (!(rt = Iopen(t, FOPEN_R, (struct stat*)0)))
			efaterror(t);
		fastcopy(rt, f);
		Ifclose(rt);
		Ofclose(f);
	}
#else
	for (i=0; i<2; i++)
		switch (run(
			-1, d[i]=maketemp(i),
			DIFF, a[i], a[2], (char*)0
		)) {
			case DIFF_FAILURE: case DIFF_SUCCESS: break;
			default: faterror("diff failed");
		}
	t = maketemp(2);
	s = run(
		-1, t,
		DIFF3, edarg, d[0], d[1], a[0], a[1], a[2],
		label[0], label[2], (char*)0
	);
	if (s != DIFF_SUCCESS) {
		s = DIFF_FAILURE;
		warn("overlaps or other problems during merge");
	}
	if (!(f = fopen(t, "a+")))
		efaterror(t);
	aputs(tostdout ? "1,$p\n" : "w\n",  f);
	Orewind(f);
	aflush(f);
	if (run(fileno(f), (char*)0, ED, "-", a[0], (char*)0))
		exiterr();
	Ofclose(f);
#endif

	tempunlink();
	for (i=3; 0<=--i; )
		if (b[i])
			tfree(b[i]);
	return s;
}
