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