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