xref: /openbsd-src/usr.bin/rcs/rcsmerge.c (revision 099bc3622b4e1de69ecf60616221f4e660477a82)
1*099bc362Sguenther /*	$OpenBSD: rcsmerge.c,v 1.57 2016/08/26 09:02:54 guenther Exp $	*/
28ff001c5Sxsa /*
3db6f0a0cSxsa  * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
48ff001c5Sxsa  * All rights reserved.
58ff001c5Sxsa  *
68ff001c5Sxsa  * Redistribution and use in source and binary forms, with or without
78ff001c5Sxsa  * modification, are permitted provided that the following conditions
88ff001c5Sxsa  * are met:
98ff001c5Sxsa  *
108ff001c5Sxsa  * 1. Redistributions of source code must retain the above copyright
118ff001c5Sxsa  *    notice, this list of conditions and the following disclaimer.
128ff001c5Sxsa  * 2. The name of the author may not be used to endorse or promote products
138ff001c5Sxsa  *    derived from this software without specific prior written permission.
148ff001c5Sxsa  *
158ff001c5Sxsa  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
168ff001c5Sxsa  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
178ff001c5Sxsa  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
188ff001c5Sxsa  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
198ff001c5Sxsa  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
208ff001c5Sxsa  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
218ff001c5Sxsa  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
228ff001c5Sxsa  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
238ff001c5Sxsa  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
248ff001c5Sxsa  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258ff001c5Sxsa  */
268ff001c5Sxsa 
274781e2faSxsa #include <err.h>
284781e2faSxsa #include <stdio.h>
294781e2faSxsa #include <stdlib.h>
304781e2faSxsa #include <string.h>
31*099bc362Sguenther #include <time.h>
324781e2faSxsa #include <unistd.h>
338ff001c5Sxsa 
348ff001c5Sxsa #include "rcsprog.h"
35cd8dad74Sxsa #include "diff.h"
368ff001c5Sxsa 
378ff001c5Sxsa int
rcsmerge_main(int argc,char ** argv)388ff001c5Sxsa rcsmerge_main(int argc, char **argv)
398ff001c5Sxsa {
400ad4c3f2Sxsa 	int fd, ch, flags, kflag, status;
41b9fc9a72Sderaadt 	char fpath[PATH_MAX], r1[RCS_REV_BUFSZ], r2[RCS_REV_BUFSZ];
42950e09dcSxsa 	char *rev_str1, *rev_str2;
438ff001c5Sxsa 	RCSFILE *file;
4436076781Sray 	RCSNUM *rev1, *rev2;
45e82fbcfcSjoris 	BUF *bp;
468ff001c5Sxsa 
47913586deSxsa 	flags = 0;
480ad4c3f2Sxsa 	status = D_ERROR;
4936076781Sray 	rev1 = rev2 = NULL;
5036076781Sray 	rev_str1 = rev_str2 = NULL;
518ff001c5Sxsa 
5272c0a1d4Sray 	while ((ch = rcs_getopt(argc, argv, "AEek:p::q::r::TVx::z:")) != -1) {
538ff001c5Sxsa 		switch (ch) {
54f91f651dSxsa 		case 'A':
55f91f651dSxsa 			/*
56f91f651dSxsa 			 * kept for compatibility
57f91f651dSxsa 			 */
58f91f651dSxsa 			break;
59f91f651dSxsa 		case 'E':
60f91f651dSxsa 			flags |= MERGE_EFLAG;
61f91f651dSxsa 			flags |= MERGE_OFLAG;
62f91f651dSxsa 			break;
63f91f651dSxsa 		case 'e':
64f91f651dSxsa 			flags |= MERGE_EFLAG;
65db6f0a0cSxsa 			break;
668ff001c5Sxsa 		case 'k':
678ff001c5Sxsa 			kflag = rcs_kflag_get(rcs_optarg);
688ff001c5Sxsa 			if (RCS_KWEXP_INVAL(kflag)) {
6925a1df5bSxsa 				warnx("invalid RCS keyword substitution mode");
708ff001c5Sxsa 				(usage)();
718ff001c5Sxsa 			}
728ff001c5Sxsa 			break;
73e82fbcfcSjoris 		case 'p':
7436076781Sray 			rcs_setrevstr2(&rev_str1, &rev_str2, rcs_optarg);
758e965226Sxsa 			flags |= PIPEOUT;
76e82fbcfcSjoris 			break;
778ff001c5Sxsa 		case 'q':
7836076781Sray 			rcs_setrevstr2(&rev_str1, &rev_str2, rcs_optarg);
79913586deSxsa 			flags |= QUIET;
808ff001c5Sxsa 			break;
818ff001c5Sxsa 		case 'r':
8272c0a1d4Sray 			rcs_setrevstr2(&rev_str1, &rev_str2,
8372c0a1d4Sray 			    rcs_optarg ? rcs_optarg : "");
848ff001c5Sxsa 			break;
858ff001c5Sxsa 		case 'T':
868ff001c5Sxsa 			/*
878ff001c5Sxsa 			 * kept for compatibility
888ff001c5Sxsa 			 */
898ff001c5Sxsa 			break;
908ff001c5Sxsa 		case 'V':
918ff001c5Sxsa 			printf("%s\n", rcs_version);
928ff001c5Sxsa 			exit(0);
937518c1e9Sxsa 		case 'x':
944365263eSray 			/* Use blank extension if none given. */
954365263eSray 			rcs_suffixes = rcs_optarg ? rcs_optarg : "";
967518c1e9Sxsa 			break;
976baf4b21Sjoris 		case 'z':
986baf4b21Sjoris 			timezone_flag = rcs_optarg;
996baf4b21Sjoris 			break;
1008ff001c5Sxsa 		default:
101d3f3fa45Sray 			(usage)();
1028ff001c5Sxsa 		}
1038ff001c5Sxsa 	}
1048ff001c5Sxsa 
1058ff001c5Sxsa 	argc -= rcs_optind;
1068ff001c5Sxsa 	argv += rcs_optind;
1078ff001c5Sxsa 
10836076781Sray 	if (rev_str1 == NULL) {
10982ca7eaaSxsa 		warnx("no base revision number given");
110e82fbcfcSjoris 		(usage)();
111e82fbcfcSjoris 	}
112e82fbcfcSjoris 
1130ad4c3f2Sxsa 	if (argc < 1) {
1140ad4c3f2Sxsa 		warnx("no input file");
1150ad4c3f2Sxsa 		(usage)();
1160ad4c3f2Sxsa 	}
1178ff001c5Sxsa 
1180ad4c3f2Sxsa 	if (argc > 2 || (argc == 2 && argv[1] != NULL))
1190ad4c3f2Sxsa 		warnx("warning: excess arguments ignored");
1200ad4c3f2Sxsa 
121f3876e23Sray 	if ((fd = rcs_choosefile(argv[0], fpath, sizeof(fpath))) < 0)
12299e66255Sniallo 		err(status, "%s", fpath);
1238ff001c5Sxsa 
124913586deSxsa 	if (!(flags & QUIET))
1250ad4c3f2Sxsa 		(void)fprintf(stderr, "RCS file: %s\n", fpath);
126db6f0a0cSxsa 
1270ad4c3f2Sxsa 	if ((file = rcs_open(fpath, fd, RCS_READ)) == NULL)
1280ad4c3f2Sxsa 		return (status);
129e82fbcfcSjoris 
13072c0a1d4Sray 	if (strcmp(rev_str1, "") == 0) {
13172c0a1d4Sray 		rev1 = rcsnum_alloc();
13272c0a1d4Sray 		rcsnum_cpy(file->rf_head, rev1, 0);
13372c0a1d4Sray 	} else if ((rev1 = rcs_getrevnum(rev_str1, file)) == NULL)
1341c5ed35bSxsa 		errx(D_ERROR, "invalid revision: %s", rev_str1);
13572c0a1d4Sray 
13672c0a1d4Sray 	if (rev_str2 != NULL && strcmp(rev_str2, "") != 0) {
137e7816acdSray 		if ((rev2 = rcs_getrevnum(rev_str2, file)) == NULL)
1381c5ed35bSxsa 			errx(D_ERROR, "invalid revision: %s", rev_str2);
139e7816acdSray 	} else {
14036076781Sray 		rev2 = rcsnum_alloc();
14136076781Sray 		rcsnum_cpy(file->rf_head, rev2, 0);
14236076781Sray 	}
14336076781Sray 
1440ad4c3f2Sxsa 	if (rcsnum_cmp(rev1, rev2, 0) == 0)
1450ad4c3f2Sxsa 		goto out;
1460ad4c3f2Sxsa 
147f91f651dSxsa 	if ((bp = rcs_diff3(file, argv[0], rev1, rev2, flags)) == NULL)
14883ebbbd9Sxsa 		errx(D_ERROR, "failed to merge");
149fa63c61aSxsa 
150913586deSxsa 	if (!(flags & QUIET)) {
15136076781Sray 		(void)rcsnum_tostr(rev1, r1, sizeof(r1));
15236076781Sray 		(void)rcsnum_tostr(rev2, r2, sizeof(r2));
153ae4f6eacSxsa 
1540ad4c3f2Sxsa 		(void)fprintf(stderr, "Merging differences between %s and "
1550ad4c3f2Sxsa 		    "%s into %s%s\n", r1, r2, argv[0],
1568e965226Sxsa 		    (flags & PIPEOUT) ? "; result to stdout":"");
15736076781Sray 	}
158ae4f6eacSxsa 
1597602a44eSxsa 	if (diff3_conflicts != 0)
1607602a44eSxsa 		status = D_OVERLAPS;
1610ad4c3f2Sxsa 	else
1620ad4c3f2Sxsa 		status = 0;
1637602a44eSxsa 
16451c4a85dSray 	if (flags & PIPEOUT)
1657bb3ddb0Sray 		buf_write_fd(bp, STDOUT_FILENO);
16651c4a85dSray 	else {
167e82fbcfcSjoris 		/* XXX mode */
1687bb3ddb0Sray 		if (buf_write(bp, argv[0], 0644) < 0)
1697bb3ddb0Sray 			warnx("buf_write failed");
170e82fbcfcSjoris 
171e82fbcfcSjoris 	}
1720ad4c3f2Sxsa 
1737bb3ddb0Sray 	buf_free(bp);
17451c4a85dSray 
1750ad4c3f2Sxsa out:
1768ff001c5Sxsa 	rcs_close(file);
1770ad4c3f2Sxsa 	rcsnum_free(rev1);
1780ad4c3f2Sxsa 	rcsnum_free(rev2);
1797602a44eSxsa 	return (status);
1808ff001c5Sxsa }
1818ff001c5Sxsa 
182960e00beSotto __dead void
rcsmerge_usage(void)1838ff001c5Sxsa rcsmerge_usage(void)
1848ff001c5Sxsa {
1858ff001c5Sxsa 	fprintf(stderr,
186f3e94d53Sjmc 	    "usage: rcsmerge [-EV] [-kmode] [-p[rev]] [-q[rev]]\n"
1879097f537Sjmc 	    "                [-xsuffixes] [-ztz] -rrev file ...\n");
188960e00beSotto 
189960e00beSotto 	exit(D_ERROR);
1908ff001c5Sxsa }
191