111894Speter/* Merge RCS revisions. */ 29Sjkh 311894Speter/* Copyright 1982, 1988, 1989 Walter Tichy 411894Speter Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 59Sjkh Distributed under license by the Free Software Foundation, Inc. 69Sjkh 79SjkhThis file is part of RCS. 89Sjkh 99SjkhRCS is free software; you can redistribute it and/or modify 109Sjkhit under the terms of the GNU General Public License as published by 119Sjkhthe Free Software Foundation; either version 2, or (at your option) 129Sjkhany later version. 139Sjkh 149SjkhRCS is distributed in the hope that it will be useful, 159Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of 169SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179SjkhGNU General Public License for more details. 189Sjkh 199SjkhYou should have received a copy of the GNU General Public License 2011894Speteralong with RCS; see the file COPYING. 2111894SpeterIf not, write to the Free Software Foundation, 2211894Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 239Sjkh 249SjkhReport problems and direct all questions to: 259Sjkh 269Sjkh rcs-bugs@cs.purdue.edu 279Sjkh 289Sjkh*/ 299Sjkh 3011894Speter/* 3111894Speter * Revision 5.15 1995/06/16 06:19:24 eggert 3211894Speter * Update FSF address. 338858Srgrimes * 3411894Speter * Revision 5.14 1995/06/01 16:23:43 eggert 3511894Speter * (main): Report an error if -kb, so don't worry about binary stdout. 3611894Speter * Punctuate messages properly. Rewrite to avoid `goto end'. 3711894Speter * 3811894Speter * Revision 5.13 1994/03/17 14:05:48 eggert 3911894Speter * Specify subprocess input via file descriptor, not file name. Remove lint. 4011894Speter * 4111894Speter * Revision 5.12 1993/11/09 17:40:15 eggert 4211894Speter * -V now prints version on stdout and exits. Don't print usage twice. 4311894Speter * 4411894Speter * Revision 5.11 1993/11/03 17:42:27 eggert 4511894Speter * Add -A, -E, -e, -z. Ignore -T. Allow up to three file labels. 4611894Speter * Pass -Vn to `co'. Pass unexpanded revision name to `co', so that Name works. 4711894Speter * 4811894Speter * Revision 5.10 1992/07/28 16:12:44 eggert 4911894Speter * Add -V. 5011894Speter * 5111894Speter * Revision 5.9 1992/01/24 18:44:19 eggert 5211894Speter * lint -> RCS_lint 5311894Speter * 5411894Speter * Revision 5.8 1992/01/06 02:42:34 eggert 5511894Speter * Update usage string. 5611894Speter * 579Sjkh * Revision 5.7 1991/11/20 17:58:09 eggert 589Sjkh * Don't Iopen(f, "r+"); it's not portable. 599Sjkh * 609Sjkh * Revision 5.6 1991/08/19 03:13:55 eggert 619Sjkh * Add -r$. Tune. 629Sjkh * 639Sjkh * Revision 5.5 1991/04/21 11:58:27 eggert 649Sjkh * Add -x, RCSINIT, MS-DOS support. 659Sjkh * 669Sjkh * Revision 5.4 1991/02/25 07:12:43 eggert 679Sjkh * Merging a revision to itself is no longer an error. 689Sjkh * 699Sjkh * Revision 5.3 1990/11/01 05:03:50 eggert 709Sjkh * Remove unneeded setid check. 719Sjkh * 729Sjkh * Revision 5.2 1990/09/04 08:02:28 eggert 739Sjkh * Check for I/O error when reading working file. 749Sjkh * 759Sjkh * Revision 5.1 1990/08/29 07:14:04 eggert 769Sjkh * Add -q. Pass -L options to merge. 779Sjkh * 789Sjkh * Revision 5.0 1990/08/22 08:13:41 eggert 799Sjkh * Propagate merge's exit status. 809Sjkh * Remove compile-time limits; use malloc instead. 819Sjkh * Make lock and temp files faster and safer. Ansify and Posixate. Add -V. 829Sjkh * Don't use access(). Tune. 839Sjkh * 849Sjkh * Revision 4.5 89/05/01 15:13:16 narten 859Sjkh * changed copyright header to reflect current distribution rules 868858Srgrimes * 879Sjkh * Revision 4.4 88/08/09 19:13:13 eggert 889Sjkh * Beware merging into a readonly file. 899Sjkh * Beware merging a revision to itself (no change). 909Sjkh * Use execv(), not system(); yield exit status like diff(1)'s. 918858Srgrimes * 929Sjkh * Revision 4.3 87/10/18 10:38:02 narten 938858Srgrimes * Updating version numbers. Changes relative to version 1.1 949Sjkh * actually relative to 4.1 958858Srgrimes * 969Sjkh * Revision 1.3 87/09/24 14:00:31 narten 978858Srgrimes * Sources now pass through lint (if you ignore printf/sprintf/fprintf 989Sjkh * warnings) 998858Srgrimes * 1009Sjkh * Revision 1.2 87/03/27 14:22:36 jenkins 1019Sjkh * Port to suns 1028858Srgrimes * 1039Sjkh * Revision 4.1 83/03/28 11:14:57 wft 1049Sjkh * Added handling of default branch. 1058858Srgrimes * 1069Sjkh * Revision 3.3 82/12/24 15:29:00 wft 1079Sjkh * Added call to catchsig(). 1089Sjkh * 1099Sjkh * Revision 3.2 82/12/10 21:32:02 wft 1109Sjkh * Replaced getdelta() with gettree(); improved error messages. 1119Sjkh * 1129Sjkh * Revision 3.1 82/11/28 19:27:44 wft 1139Sjkh * Initial revision. 1149Sjkh * 1159Sjkh */ 1169Sjkh#include "rcsbase.h" 1179Sjkh 1189Sjkhstatic char const co[] = CO; 1199Sjkh 12050472SpetermainProg(rcsmergeId, "rcsmerge", "$FreeBSD$") 1219Sjkh{ 1229Sjkh static char const cmdusage[] = 12311894Speter "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] -ksubst -{pq}[rev] -Vn -xsuff -zzone file"; 1249Sjkh static char const quietarg[] = "-q"; 1259Sjkh 1269Sjkh register int i; 1279Sjkh char *a, **newargv; 1289Sjkh char const *arg[3]; 12911894Speter char const *rev[3], *xrev[3]; /*revision numbers*/ 13011894Speter char const *edarg, *expandarg, *suffixarg, *versionarg, *zonearg; 1319Sjkh int tostdout; 1329Sjkh int status; 1339Sjkh RILE *workptr; 1349Sjkh struct buf commarg; 1359Sjkh struct buf numericrev; /* holds expanded revision number */ 1369Sjkh struct hshentries *gendeltas; /* deltas to be generated */ 1379Sjkh struct hshentry * target; 1389Sjkh 1399Sjkh bufautobegin(&commarg); 1409Sjkh bufautobegin(&numericrev); 14111894Speter edarg = rev[1] = rev[2] = 0; 1429Sjkh status = 0; /* Keep lint happy. */ 1439Sjkh tostdout = false; 14411894Speter expandarg = suffixarg = versionarg = zonearg = quietarg; /* no-op */ 1459Sjkh suffixes = X_DEFAULT; 1469Sjkh 1479Sjkh argc = getRCSINIT(argc, argv, &newargv); 1489Sjkh argv = newargv; 1499Sjkh while (a = *++argv, 0<--argc && *a++=='-') { 1509Sjkh switch (*a++) { 1519Sjkh case 'p': 1529Sjkh tostdout=true; 1539Sjkh goto revno; 1549Sjkh 1559Sjkh case 'q': 1569Sjkh quietflag = true; 1579Sjkh revno: 1589Sjkh if (!*a) 1599Sjkh break; 1609Sjkh /* falls into -r */ 1619Sjkh case 'r': 16211894Speter if (!rev[1]) 1639Sjkh rev[1] = a; 16411894Speter else if (!rev[2]) 16511894Speter rev[2] = a; 1669Sjkh else 16711894Speter error("too many revision numbers"); 1689Sjkh break; 16911894Speter 17011894Speter case 'A': case 'E': case 'e': 17111894Speter if (*a) 17211894Speter goto unknown; 17311894Speter edarg = *argv; 17411894Speter break; 17511894Speter 1769Sjkh case 'x': 17711894Speter suffixarg = *argv; 1789Sjkh suffixes = a; 1799Sjkh break; 18011894Speter case 'z': 18111894Speter zonearg = *argv; 18211894Speter zone_set(a); 18311894Speter break; 18411894Speter case 'T': 18511894Speter /* Ignore -T, so that RCSINIT can contain -T. */ 18611894Speter if (*a) 18711894Speter goto unknown; 18811894Speter break; 1899Sjkh case 'V': 1909Sjkh versionarg = *argv; 1919Sjkh setRCSversion(versionarg); 1929Sjkh break; 1939Sjkh 1949Sjkh case 'k': 1959Sjkh expandarg = *argv; 1969Sjkh if (0 <= str2expmode(expandarg+2)) 1979Sjkh break; 1989Sjkh /* fall into */ 1999Sjkh default: 20011894Speter unknown: 20111894Speter error("unknown option: %s%s", *argv, cmdusage); 2029Sjkh }; 2039Sjkh } /* end of option processing */ 2049Sjkh 20511894Speter if (!rev[1]) faterror("no base revision number given"); 2069Sjkh 20711894Speter /* Now handle all pathnames. */ 2089Sjkh 20911894Speter if (!nerror) { 21011894Speter if (argc < 1) 21111894Speter faterror("no input file%s", cmdusage); 21211894Speter if (0 < pairnames(argc, argv, rcsreadopen, true, false)) { 2139Sjkh 21411894Speter if (argc>2 || (argc==2 && argv[1])) 21511894Speter warn("excess arguments ignored"); 21611894Speter if (Expand == BINARY_EXPAND) 21711894Speter workerror("merging binary files"); 21811894Speter diagnose("RCS file: %s\n", RCSname); 21911894Speter if (!(workptr = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) 22011894Speter efaterror(workname); 2219Sjkh 2229Sjkh gettree(); /* reads in the delta tree */ 2239Sjkh 22411894Speter if (!Head) rcsfaterror("no revisions present"); 2259Sjkh 22611894Speter if (!*rev[1]) 2279Sjkh rev[1] = Dbranch ? Dbranch : Head->num; 22811894Speter if (fexpandsym(rev[1], &numericrev, workptr) 22911894Speter && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char*)0, &gendeltas)) 23011894Speter ) { 23111894Speter xrev[1] = target->num; 23211894Speter if (!rev[2] || !*rev[2]) 23311894Speter rev[2] = Dbranch ? Dbranch : Head->num; 23411894Speter if (fexpandsym(rev[2], &numericrev, workptr) 23511894Speter && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char *)0, &gendeltas)) 23611894Speter ) { 23711894Speter xrev[2] = target->num; 2389Sjkh 23911894Speter if (strcmp(xrev[1],xrev[2]) == 0) { 24011894Speter if (tostdout) { 24111894Speter fastcopy(workptr, stdout); 24211894Speter Ofclose(stdout); 24311894Speter } 24411894Speter } else { 24511894Speter Izclose(&workptr); 2469Sjkh 24711894Speter for (i=1; i<=2; i++) { 24811894Speter diagnose("retrieving revision %s\n", xrev[i]); 2499Sjkh bufscpy(&commarg, "-p"); 25011894Speter bufscat(&commarg, rev[i]); /* not xrev[i], for $Name's sake */ 2519Sjkh if (run( 25211894Speter -1, 2539Sjkh /* Do not collide with merger.c maketemp(). */ 25411894Speter arg[i] = maketemp(i+2), 25511894Speter co, quietarg, commarg.string, 25611894Speter expandarg, suffixarg, versionarg, zonearg, 25711894Speter RCSname, (char*)0 2589Sjkh )) 25911894Speter rcsfaterror("co failed"); 26011894Speter } 26111894Speter diagnose("Merging differences between %s and %s into %s%s\n", 26211894Speter xrev[1], xrev[2], workname, 26311894Speter tostdout?"; result to stdout":""); 26411894Speter 26511894Speter arg[0] = xrev[0] = workname; 26611894Speter status = merge(tostdout, edarg, xrev, arg); 26711894Speter } 26811894Speter } 2699Sjkh } 2709Sjkh 27111894Speter Izclose(&workptr); 27211894Speter } 2739Sjkh } 2749Sjkh tempunlink(); 2759Sjkh exitmain(nerror ? DIFF_TROUBLE : status); 2769Sjkh} 2779Sjkh 27811894Speter#if RCS_lint 2799Sjkh# define exiterr rmergeExit 2809Sjkh#endif 28111894Speter void 2829Sjkhexiterr() 2839Sjkh{ 2849Sjkh tempunlink(); 2859Sjkh _exit(DIFF_TROUBLE); 2869Sjkh} 287