rcsmerge.c revision 10
1/* 2 * rcsmerge operation 3 */ 4/***************************************************************************** 5 * join 2 revisions with respect to a third 6 ***************************************************************************** 7 */ 8 9/* Copyright (C) 1982, 1988, 1989 Walter Tichy 10 Copyright 1990, 1991 by Paul Eggert 11 Distributed under license by the Free Software Foundation, Inc. 12 13This file is part of RCS. 14 15RCS is free software; you can redistribute it and/or modify 16it under the terms of the GNU General Public License as published by 17the Free Software Foundation; either version 2, or (at your option) 18any later version. 19 20RCS is distributed in the hope that it will be useful, 21but WITHOUT ANY WARRANTY; without even the implied warranty of 22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23GNU General Public License for more details. 24 25You should have received a copy of the GNU General Public License 26along with RCS; see the file COPYING. If not, write to 27the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 28 29Report problems and direct all questions to: 30 31 rcs-bugs@cs.purdue.edu 32 33*/ 34 35 36 37/* $Log: rcsmerge.c,v $ 38 * Revision 5.7 1991/11/20 17:58:09 eggert 39 * Don't Iopen(f, "r+"); it's not portable. 40 * 41 * Revision 5.6 1991/08/19 03:13:55 eggert 42 * Add -r$. Tune. 43 * 44 * Revision 5.5 1991/04/21 11:58:27 eggert 45 * Add -x, RCSINIT, MS-DOS support. 46 * 47 * Revision 5.4 1991/02/25 07:12:43 eggert 48 * Merging a revision to itself is no longer an error. 49 * 50 * Revision 5.3 1990/11/01 05:03:50 eggert 51 * Remove unneeded setid check. 52 * 53 * Revision 5.2 1990/09/04 08:02:28 eggert 54 * Check for I/O error when reading working file. 55 * 56 * Revision 5.1 1990/08/29 07:14:04 eggert 57 * Add -q. Pass -L options to merge. 58 * 59 * Revision 5.0 1990/08/22 08:13:41 eggert 60 * Propagate merge's exit status. 61 * Remove compile-time limits; use malloc instead. 62 * Make lock and temp files faster and safer. Ansify and Posixate. Add -V. 63 * Don't use access(). Tune. 64 * 65 * Revision 4.5 89/05/01 15:13:16 narten 66 * changed copyright header to reflect current distribution rules 67 * 68 * Revision 4.4 88/08/09 19:13:13 eggert 69 * Beware merging into a readonly file. 70 * Beware merging a revision to itself (no change). 71 * Use execv(), not system(); yield exit status like diff(1)'s. 72 * 73 * Revision 4.3 87/10/18 10:38:02 narten 74 * Updating version numbers. Changes relative to version 1.1 75 * actually relative to 4.1 76 * 77 * Revision 1.3 87/09/24 14:00:31 narten 78 * Sources now pass through lint (if you ignore printf/sprintf/fprintf 79 * warnings) 80 * 81 * Revision 1.2 87/03/27 14:22:36 jenkins 82 * Port to suns 83 * 84 * Revision 4.1 83/03/28 11:14:57 wft 85 * Added handling of default branch. 86 * 87 * Revision 3.3 82/12/24 15:29:00 wft 88 * Added call to catchsig(). 89 * 90 * Revision 3.2 82/12/10 21:32:02 wft 91 * Replaced getdelta() with gettree(); improved error messages. 92 * 93 * Revision 3.1 82/11/28 19:27:44 wft 94 * Initial revision. 95 * 96 */ 97#include "rcsbase.h" 98 99static char const co[] = CO; 100 101mainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.7 1991/11/20 17:58:09 eggert Exp $") 102{ 103 static char const cmdusage[] = 104 "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file"; 105 static char const quietarg[] = "-q"; 106 107 register int i; 108 char *a, **newargv; 109 char const *arg[3]; 110 char const *rev[2]; /*revision numbers*/ 111 char const *expandarg, *versionarg; 112 int tostdout; 113 int status; 114 RILE *workptr; 115 struct buf commarg; 116 struct buf numericrev; /* holds expanded revision number */ 117 struct hshentries *gendeltas; /* deltas to be generated */ 118 struct hshentry * target; 119 120 bufautobegin(&commarg); 121 bufautobegin(&numericrev); 122 rev[0] = rev[1] = nil; 123 status = 0; /* Keep lint happy. */ 124 tostdout = false; 125 expandarg = versionarg = quietarg; /* i.e. a no-op */ 126 suffixes = X_DEFAULT; 127 128 argc = getRCSINIT(argc, argv, &newargv); 129 argv = newargv; 130 while (a = *++argv, 0<--argc && *a++=='-') { 131 switch (*a++) { 132 case 'p': 133 tostdout=true; 134 goto revno; 135 136 case 'q': 137 quietflag = true; 138 revno: 139 if (!*a) 140 break; 141 /* falls into -r */ 142 case 'r': 143 if (!rev[0]) 144 rev[0] = a; 145 else if (!rev[1]) 146 rev[1] = a; 147 else 148 faterror("too many revision numbers"); 149 break; 150 case 'x': 151 suffixes = a; 152 break; 153 case 'V': 154 versionarg = *argv; 155 setRCSversion(versionarg); 156 break; 157 158 case 'k': 159 expandarg = *argv; 160 if (0 <= str2expmode(expandarg+2)) 161 break; 162 /* fall into */ 163 default: 164 faterror("unknown option: %s%s", *argv, cmdusage); 165 }; 166 } /* end of option processing */ 167 168 if (argc<1) faterror("no input file%s", cmdusage); 169 if (!rev[0]) faterror("no base revision number given"); 170 171 /* now handle all filenames */ 172 173 if (0 < pairfilenames(argc, argv, rcsreadopen, true, false)) { 174 175 if (argc>2 || (argc==2&&argv[1]!=nil)) 176 warn("too many arguments"); 177 diagnose("RCS file: %s\n", RCSfilename); 178 if (!(workptr = Iopen(workfilename, 179 FOPEN_R_WORK, 180 (struct stat*)0 181 ))) 182 efaterror(workfilename); 183 184 gettree(); /* reads in the delta tree */ 185 186 if (Head==nil) faterror("no revisions present"); 187 188 if (!*rev[0]) 189 rev[0] = Dbranch ? Dbranch : Head->num; 190 if (!fexpandsym(rev[0], &numericrev, workptr)) 191 goto end; 192 if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end; 193 rev[0] = target->num; 194 if (!rev[1] || !*rev[1]) 195 rev[1] = Dbranch ? Dbranch : Head->num; 196 if (!fexpandsym(rev[1], &numericrev, workptr)) 197 goto end; 198 if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end; 199 rev[1] = target->num; 200 201 if (strcmp(rev[0],rev[1]) == 0) { 202 if (tostdout) { 203 FILE *o; 204# if text_equals_binary_stdio || text_work_stdio 205 o = stdout; 206# else 207 if (!(o=fdopen(STDOUT_FILENO,FOPEN_W_WORK))) 208 efaterror("stdout"); 209# endif 210 fastcopy(workptr,o); 211 Ofclose(o); 212 } 213 goto end; 214 } 215 Izclose(&workptr); 216 217 for (i=0; i<2; i++) { 218 diagnose("retrieving revision %s\n", rev[i]); 219 bufscpy(&commarg, "-p"); 220 bufscat(&commarg, rev[i]); 221 if (run( 222 (char*)0, 223 /* Do not collide with merger.c maketemp(). */ 224 arg[i+1] = maketemp(i+3), 225 co, quietarg, commarg.string, expandarg, 226 versionarg, RCSfilename, (char*)0 227 )) 228 faterror("co failed"); 229 } 230 diagnose("Merging differences between %s and %s into %s%s\n", 231 rev[0], rev[1], workfilename, 232 tostdout?"; result to stdout":""); 233 234 arg[0] = rev[0] = workfilename; 235 status = merge(tostdout, rev, arg); 236 } 237 238end: 239 Izclose(&workptr); 240 tempunlink(); 241 exitmain(nerror ? DIFF_TROUBLE : status); 242} 243 244#if lint 245# define exiterr rmergeExit 246#endif 247 exiting void 248exiterr() 249{ 250 tempunlink(); 251 _exit(DIFF_TROUBLE); 252} 253