xref: /dragonfly/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /* Compare RCS revisions.  */
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
4*86d7f5d3SJohn Marino    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5*86d7f5d3SJohn Marino    Distributed under license by the Free Software Foundation, Inc.
6*86d7f5d3SJohn Marino 
7*86d7f5d3SJohn Marino This file is part of RCS.
8*86d7f5d3SJohn Marino 
9*86d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
10*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
11*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
12*86d7f5d3SJohn Marino any later version.
13*86d7f5d3SJohn Marino 
14*86d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
15*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
16*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*86d7f5d3SJohn Marino GNU General Public License for more details.
18*86d7f5d3SJohn Marino 
19*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
20*86d7f5d3SJohn Marino along with RCS; see the file COPYING.
21*86d7f5d3SJohn Marino If not, write to the Free Software Foundation,
22*86d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*86d7f5d3SJohn Marino 
24*86d7f5d3SJohn Marino Report problems and direct all questions to:
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino     rcs-bugs@cs.purdue.edu
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino */
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino /*
31*86d7f5d3SJohn Marino  * $FreeBSD: src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c,v 1.8 1999/08/27 23:36:55 peter Exp $
32*86d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c,v 1.2 2003/06/17 04:25:48 dillon Exp $
33*86d7f5d3SJohn Marino  *
34*86d7f5d3SJohn Marino  * Revision 5.19  1995/06/16 06:19:24  eggert
35*86d7f5d3SJohn Marino  * Update FSF address.
36*86d7f5d3SJohn Marino  *
37*86d7f5d3SJohn Marino  * Revision 5.18  1995/06/01 16:23:43  eggert
38*86d7f5d3SJohn Marino  * (main): Pass "--binary" if -kb and if --binary makes a difference.
39*86d7f5d3SJohn Marino  * Don't treat + options specially.
40*86d7f5d3SJohn Marino  *
41*86d7f5d3SJohn Marino  * Revision 5.17  1994/03/17 14:05:48  eggert
42*86d7f5d3SJohn Marino  * Specify subprocess input via file descriptor, not file name.  Remove lint.
43*86d7f5d3SJohn Marino  *
44*86d7f5d3SJohn Marino  * Revision 5.16  1993/11/09 17:40:15  eggert
45*86d7f5d3SJohn Marino  * -V now prints version on stdout and exits.  Don't print usage twice.
46*86d7f5d3SJohn Marino  *
47*86d7f5d3SJohn Marino  * Revision 5.15  1993/11/03 17:42:27  eggert
48*86d7f5d3SJohn Marino  * Add -z.  Ignore -T.  Pass -Vn to `co'.  Add Name keyword.
49*86d7f5d3SJohn Marino  * Put revision numbers in -c output.  Improve quality of diagnostics.
50*86d7f5d3SJohn Marino  *
51*86d7f5d3SJohn Marino  * Revision 5.14  1992/07/28  16:12:44  eggert
52*86d7f5d3SJohn Marino  * Add -V.  Use co -M for better dates with traditional diff -c.
53*86d7f5d3SJohn Marino  *
54*86d7f5d3SJohn Marino  * Revision 5.13  1992/02/17  23:02:23  eggert
55*86d7f5d3SJohn Marino  * Output more readable context diff headers.
56*86d7f5d3SJohn Marino  * Suppress needless checkout and comparison of identical revisions.
57*86d7f5d3SJohn Marino  *
58*86d7f5d3SJohn Marino  * Revision 5.12  1992/01/24  18:44:19  eggert
59*86d7f5d3SJohn Marino  * Add GNU diff 1.15.2's new options.  lint -> RCS_lint
60*86d7f5d3SJohn Marino  *
61*86d7f5d3SJohn Marino  * Revision 5.11  1992/01/06  02:42:34  eggert
62*86d7f5d3SJohn Marino  * Update usage string.
63*86d7f5d3SJohn Marino  *
64*86d7f5d3SJohn Marino  * Revision 5.10  1991/10/07  17:32:46  eggert
65*86d7f5d3SJohn Marino  * Remove lint.
66*86d7f5d3SJohn Marino  *
67*86d7f5d3SJohn Marino  * Revision 5.9  1991/08/19  03:13:55  eggert
68*86d7f5d3SJohn Marino  * Add RCSINIT, -r$.  Tune.
69*86d7f5d3SJohn Marino  *
70*86d7f5d3SJohn Marino  * Revision 5.8  1991/04/21  11:58:21  eggert
71*86d7f5d3SJohn Marino  * Add -x, RCSINIT, MS-DOS support.
72*86d7f5d3SJohn Marino  *
73*86d7f5d3SJohn Marino  * Revision 5.7  1990/12/13  06:54:07  eggert
74*86d7f5d3SJohn Marino  * GNU diff 1.15 has -u.
75*86d7f5d3SJohn Marino  *
76*86d7f5d3SJohn Marino  * Revision 5.6  1990/11/01  05:03:39  eggert
77*86d7f5d3SJohn Marino  * Remove unneeded setid check.
78*86d7f5d3SJohn Marino  *
79*86d7f5d3SJohn Marino  * Revision 5.5  1990/10/04  06:30:19  eggert
80*86d7f5d3SJohn Marino  * Accumulate exit status across files.
81*86d7f5d3SJohn Marino  *
82*86d7f5d3SJohn Marino  * Revision 5.4  1990/09/27  01:31:43  eggert
83*86d7f5d3SJohn Marino  * Yield 1, not EXIT_FAILURE, when diffs are found.
84*86d7f5d3SJohn Marino  *
85*86d7f5d3SJohn Marino  * Revision 5.3  1990/09/11  02:41:11  eggert
86*86d7f5d3SJohn Marino  * Simplify -kkvl test.
87*86d7f5d3SJohn Marino  *
88*86d7f5d3SJohn Marino  * Revision 5.2  1990/09/04  17:07:19  eggert
89*86d7f5d3SJohn Marino  * Diff's argv was too small by 1.
90*86d7f5d3SJohn Marino  *
91*86d7f5d3SJohn Marino  * Revision 5.1  1990/08/29  07:13:55  eggert
92*86d7f5d3SJohn Marino  * Add -kkvl.
93*86d7f5d3SJohn Marino  *
94*86d7f5d3SJohn Marino  * Revision 5.0  1990/08/22  08:12:46  eggert
95*86d7f5d3SJohn Marino  * Add -k, -V.  Don't use access().  Add setuid support.
96*86d7f5d3SJohn Marino  * Remove compile-time limits; use malloc instead.
97*86d7f5d3SJohn Marino  * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
98*86d7f5d3SJohn Marino  * Add GNU diff's flags.  Make lock and temp files faster and safer.
99*86d7f5d3SJohn Marino  * Ansify and Posixate.
100*86d7f5d3SJohn Marino  *
101*86d7f5d3SJohn Marino  * Revision 4.6  89/05/01  15:12:27  narten
102*86d7f5d3SJohn Marino  * changed copyright header to reflect current distribution rules
103*86d7f5d3SJohn Marino  *
104*86d7f5d3SJohn Marino  * Revision 4.5  88/08/09  19:12:41  eggert
105*86d7f5d3SJohn Marino  * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
106*86d7f5d3SJohn Marino  *
107*86d7f5d3SJohn Marino  * Revision 4.4  87/12/18  11:37:46  narten
108*86d7f5d3SJohn Marino  * changes Jay Lepreau made in the 4.3 BSD version, to add support for
109*86d7f5d3SJohn Marino  * "-i", "-w", and "-t" flags and to permit flags to be bundled together,
110*86d7f5d3SJohn Marino  * merged in.
111*86d7f5d3SJohn Marino  *
112*86d7f5d3SJohn Marino  * Revision 4.3  87/10/18  10:31:42  narten
113*86d7f5d3SJohn Marino  * Updating version numbers. Changes relative to 1.1 actually
114*86d7f5d3SJohn Marino  * relative to 4.1
115*86d7f5d3SJohn Marino  *
116*86d7f5d3SJohn Marino  * Revision 1.3  87/09/24  13:59:21  narten
117*86d7f5d3SJohn Marino  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
118*86d7f5d3SJohn Marino  * warnings)
119*86d7f5d3SJohn Marino  *
120*86d7f5d3SJohn Marino  * Revision 1.2  87/03/27  14:22:15  jenkins
121*86d7f5d3SJohn Marino  * Port to suns
122*86d7f5d3SJohn Marino  *
123*86d7f5d3SJohn Marino  * Revision 4.1  83/05/03  22:13:19  wft
124*86d7f5d3SJohn Marino  * Added default branch, option -q, exit status like diff.
125*86d7f5d3SJohn Marino  * Added fterror() to replace faterror().
126*86d7f5d3SJohn Marino  *
127*86d7f5d3SJohn Marino  * Revision 3.6  83/01/15  17:52:40  wft
128*86d7f5d3SJohn Marino  * Expanded mainprogram to handle multiple RCS files.
129*86d7f5d3SJohn Marino  *
130*86d7f5d3SJohn Marino  * Revision 3.5  83/01/06  09:33:45  wft
131*86d7f5d3SJohn Marino  * Fixed passing of -c (context) option to diff.
132*86d7f5d3SJohn Marino  *
133*86d7f5d3SJohn Marino  * Revision 3.4  82/12/24  15:28:38  wft
134*86d7f5d3SJohn Marino  * Added call to catchsig().
135*86d7f5d3SJohn Marino  *
136*86d7f5d3SJohn Marino  * Revision 3.3  82/12/10  16:08:17  wft
137*86d7f5d3SJohn Marino  * Corrected checking of return code from diff; improved error msgs.
138*86d7f5d3SJohn Marino  *
139*86d7f5d3SJohn Marino  * Revision 3.2  82/12/04  13:20:09  wft
140*86d7f5d3SJohn Marino  * replaced getdelta() with gettree(). Changed diagnostics.
141*86d7f5d3SJohn Marino  *
142*86d7f5d3SJohn Marino  * Revision 3.1  82/11/28  19:25:04  wft
143*86d7f5d3SJohn Marino  * Initial revision.
144*86d7f5d3SJohn Marino  *
145*86d7f5d3SJohn Marino  */
146*86d7f5d3SJohn Marino #include "rcsbase.h"
147*86d7f5d3SJohn Marino 
148*86d7f5d3SJohn Marino #if DIFF_L
149*86d7f5d3SJohn Marino static char const *setup_label P((struct buf*,char const*,char const[datesize]));
150*86d7f5d3SJohn Marino #endif
151*86d7f5d3SJohn Marino static void cleanup P((void));
152*86d7f5d3SJohn Marino 
153*86d7f5d3SJohn Marino static int exitstatus;
154*86d7f5d3SJohn Marino static RILE *workptr;
155*86d7f5d3SJohn Marino static struct stat workstat;
156*86d7f5d3SJohn Marino 
157*86d7f5d3SJohn Marino mainProg(rcsdiffId, "rcsdiff", "$DragonFly: src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c,v 1.2 2003/06/17 04:25:48 dillon Exp $")
158*86d7f5d3SJohn Marino {
159*86d7f5d3SJohn Marino     static char const cmdusage[] =
160*86d7f5d3SJohn Marino 	    "\nrcsdiff usage: rcsdiff -ksubst -q -rrev1 [-rrev2] -Vn -xsuff -zzone [diff options] file ...";
161*86d7f5d3SJohn Marino 
162*86d7f5d3SJohn Marino     int  revnums;                 /* counter for revision numbers given */
163*86d7f5d3SJohn Marino     char const *rev1, *rev2;	/* revision numbers from command line */
164*86d7f5d3SJohn Marino     char const *xrev1, *xrev2;	/* expanded revision numbers */
165*86d7f5d3SJohn Marino     char const *expandarg, *lexpandarg, *suffixarg, *versionarg, *zonearg;
166*86d7f5d3SJohn Marino #if DIFF_L
167*86d7f5d3SJohn Marino     static struct buf labelbuf[2];
168*86d7f5d3SJohn Marino     int file_labels;
169*86d7f5d3SJohn Marino     char const **diff_label1, **diff_label2;
170*86d7f5d3SJohn Marino     char date2[datesize];
171*86d7f5d3SJohn Marino #endif
172*86d7f5d3SJohn Marino     char const *cov[10 + !DIFF_L];
173*86d7f5d3SJohn Marino     char const **diffv, **diffp, **diffpend;	/* argv for subsidiary diff */
174*86d7f5d3SJohn Marino     char const **pp, *p, *diffvstr;
175*86d7f5d3SJohn Marino     struct buf commarg;
176*86d7f5d3SJohn Marino     struct buf numericrev;	/* expanded revision number */
177*86d7f5d3SJohn Marino     struct hshentries *gendeltas;	/* deltas to be generated */
178*86d7f5d3SJohn Marino     struct hshentry * target;
179*86d7f5d3SJohn Marino     char *a, *dcp, **newargv;
180*86d7f5d3SJohn Marino     int no_diff_means_no_output;
181*86d7f5d3SJohn Marino     register int c;
182*86d7f5d3SJohn Marino 
183*86d7f5d3SJohn Marino     exitstatus = DIFF_SUCCESS;
184*86d7f5d3SJohn Marino 
185*86d7f5d3SJohn Marino     bufautobegin(&commarg);
186*86d7f5d3SJohn Marino     bufautobegin(&numericrev);
187*86d7f5d3SJohn Marino     revnums = 0;
188*86d7f5d3SJohn Marino     rev1 = rev2 = xrev2 = 0;
189*86d7f5d3SJohn Marino #if DIFF_L
190*86d7f5d3SJohn Marino     file_labels = 0;
191*86d7f5d3SJohn Marino #endif
192*86d7f5d3SJohn Marino     expandarg = suffixarg = versionarg = zonearg = 0;
193*86d7f5d3SJohn Marino     no_diff_means_no_output = true;
194*86d7f5d3SJohn Marino     suffixes = X_DEFAULT;
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino     /*
197*86d7f5d3SJohn Marino     * Room for runv extra + args [+ --binary] [+ 2 labels]
198*86d7f5d3SJohn Marino     * + 1 file + 1 trailing null.
199*86d7f5d3SJohn Marino     */
200*86d7f5d3SJohn Marino     diffv = tnalloc(char const*, 1 + argc + !!OPEN_O_BINARY + 2*DIFF_L + 2);
201*86d7f5d3SJohn Marino     diffp = diffv + 1;
202*86d7f5d3SJohn Marino     *diffp++ = DIFF;
203*86d7f5d3SJohn Marino 
204*86d7f5d3SJohn Marino     argc = getRCSINIT(argc, argv, &newargv);
205*86d7f5d3SJohn Marino     argv = newargv;
206*86d7f5d3SJohn Marino     while (a = *++argv,  0<--argc && *a++=='-') {
207*86d7f5d3SJohn Marino 	dcp = a;
208*86d7f5d3SJohn Marino 	while ((c = *a++)) switch (c) {
209*86d7f5d3SJohn Marino 	    case 'r':
210*86d7f5d3SJohn Marino 		    switch (++revnums) {
211*86d7f5d3SJohn Marino 			case 1: rev1=a; break;
212*86d7f5d3SJohn Marino 			case 2: rev2=a; break;
213*86d7f5d3SJohn Marino 			default: error("too many revision numbers");
214*86d7f5d3SJohn Marino 		    }
215*86d7f5d3SJohn Marino 		    goto option_handled;
216*86d7f5d3SJohn Marino 	    case '-': case 'D':
217*86d7f5d3SJohn Marino 		    no_diff_means_no_output = false;
218*86d7f5d3SJohn Marino 		    /* fall into */
219*86d7f5d3SJohn Marino 	    case 'C': case 'F': case 'I': case 'L': case 'W':
220*86d7f5d3SJohn Marino #if DIFF_L
221*86d7f5d3SJohn Marino 		    if (c == 'L'  &&  file_labels++ == 2)
222*86d7f5d3SJohn Marino 			faterror("too many -L options");
223*86d7f5d3SJohn Marino #endif
224*86d7f5d3SJohn Marino 		    *dcp++ = c;
225*86d7f5d3SJohn Marino 		    if (*a)
226*86d7f5d3SJohn Marino 			do *dcp++ = *a++;
227*86d7f5d3SJohn Marino 			while (*a);
228*86d7f5d3SJohn Marino 		    else {
229*86d7f5d3SJohn Marino 			if (!--argc)
230*86d7f5d3SJohn Marino 			    faterror("-%c needs following argument%s",
231*86d7f5d3SJohn Marino 				    c, cmdusage
232*86d7f5d3SJohn Marino 			    );
233*86d7f5d3SJohn Marino 			*diffp++ = *argv++;
234*86d7f5d3SJohn Marino 		    }
235*86d7f5d3SJohn Marino 		    break;
236*86d7f5d3SJohn Marino 	    case 'y':
237*86d7f5d3SJohn Marino 		    no_diff_means_no_output = false;
238*86d7f5d3SJohn Marino 		    /* fall into */
239*86d7f5d3SJohn Marino 	    case 'B': case 'H':
240*86d7f5d3SJohn Marino 	    case '0': case '1': case '2': case '3': case '4':
241*86d7f5d3SJohn Marino 	    case '5': case '6': case '7': case '8': case '9':
242*86d7f5d3SJohn Marino 	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
243*86d7f5d3SJohn Marino 	    case 'h': case 'i': case 'n': case 'p':
244*86d7f5d3SJohn Marino 	    case 't': case 'u': case 'w':
245*86d7f5d3SJohn Marino 		    *dcp++ = c;
246*86d7f5d3SJohn Marino 		    break;
247*86d7f5d3SJohn Marino 	    case 'q':
248*86d7f5d3SJohn Marino 		    quietflag=true;
249*86d7f5d3SJohn Marino 		    break;
250*86d7f5d3SJohn Marino 	    case 'x':
251*86d7f5d3SJohn Marino 		    suffixarg = *argv;
252*86d7f5d3SJohn Marino 		    suffixes = *argv + 2;
253*86d7f5d3SJohn Marino 		    goto option_handled;
254*86d7f5d3SJohn Marino 	    case 'z':
255*86d7f5d3SJohn Marino 		    zonearg = *argv;
256*86d7f5d3SJohn Marino 		    zone_set(*argv + 2);
257*86d7f5d3SJohn Marino 		    goto option_handled;
258*86d7f5d3SJohn Marino 	    case 'T':
259*86d7f5d3SJohn Marino 		    /* Ignore -T, so that RCSINIT can contain -T.  */
260*86d7f5d3SJohn Marino 		    if (*a)
261*86d7f5d3SJohn Marino 			    goto unknown;
262*86d7f5d3SJohn Marino 		    break;
263*86d7f5d3SJohn Marino 	    case 'V':
264*86d7f5d3SJohn Marino 		    versionarg = *argv;
265*86d7f5d3SJohn Marino 		    setRCSversion(versionarg);
266*86d7f5d3SJohn Marino 		    goto option_handled;
267*86d7f5d3SJohn Marino 	    case 'k':
268*86d7f5d3SJohn Marino 		    expandarg = *argv;
269*86d7f5d3SJohn Marino 		    if (0 <= str2expmode(expandarg+2))
270*86d7f5d3SJohn Marino 			goto option_handled;
271*86d7f5d3SJohn Marino 		    /* fall into */
272*86d7f5d3SJohn Marino 	    default:
273*86d7f5d3SJohn Marino 	    unknown:
274*86d7f5d3SJohn Marino 		    error("unknown option: %s%s", *argv, cmdusage);
275*86d7f5d3SJohn Marino 	    };
276*86d7f5d3SJohn Marino       option_handled:
277*86d7f5d3SJohn Marino 	if (dcp != *argv+1) {
278*86d7f5d3SJohn Marino 	    *dcp = 0;
279*86d7f5d3SJohn Marino 	    *diffp++ = *argv;
280*86d7f5d3SJohn Marino 	}
281*86d7f5d3SJohn Marino     } /* end of option processing */
282*86d7f5d3SJohn Marino 
283*86d7f5d3SJohn Marino     for (pp = diffv+2, c = 0;  pp<diffp;  )
284*86d7f5d3SJohn Marino 	    c += strlen(*pp++) + 1;
285*86d7f5d3SJohn Marino     diffvstr = a = tnalloc(char, c + 1);
286*86d7f5d3SJohn Marino     for (pp = diffv+2;  pp<diffp;  ) {
287*86d7f5d3SJohn Marino 	    p = *pp++;
288*86d7f5d3SJohn Marino 	    *a++ = ' ';
289*86d7f5d3SJohn Marino 	    while ((*a = *p++))
290*86d7f5d3SJohn Marino 		    a++;
291*86d7f5d3SJohn Marino     }
292*86d7f5d3SJohn Marino     *a = 0;
293*86d7f5d3SJohn Marino 
294*86d7f5d3SJohn Marino #if DIFF_L
295*86d7f5d3SJohn Marino     diff_label1 = diff_label2 = 0;
296*86d7f5d3SJohn Marino     if (file_labels < 2) {
297*86d7f5d3SJohn Marino 	    if (!file_labels)
298*86d7f5d3SJohn Marino 		    diff_label1 = diffp++;
299*86d7f5d3SJohn Marino 	    diff_label2 = diffp++;
300*86d7f5d3SJohn Marino     }
301*86d7f5d3SJohn Marino #endif
302*86d7f5d3SJohn Marino     diffpend = diffp;
303*86d7f5d3SJohn Marino 
304*86d7f5d3SJohn Marino     cov[1] = CO;
305*86d7f5d3SJohn Marino     cov[2] = "-q";
306*86d7f5d3SJohn Marino #   if !DIFF_L
307*86d7f5d3SJohn Marino 	cov[3] = "-M";
308*86d7f5d3SJohn Marino #   endif
309*86d7f5d3SJohn Marino 
310*86d7f5d3SJohn Marino     /* Now handle all pathnames.  */
311*86d7f5d3SJohn Marino     if (nerror)
312*86d7f5d3SJohn Marino 	cleanup();
313*86d7f5d3SJohn Marino     else if (argc < 1)
314*86d7f5d3SJohn Marino 	faterror("no input file%s", cmdusage);
315*86d7f5d3SJohn Marino     else
316*86d7f5d3SJohn Marino 	for (;  0 < argc;  cleanup(), ++argv, --argc) {
317*86d7f5d3SJohn Marino 	    ffree();
318*86d7f5d3SJohn Marino 
319*86d7f5d3SJohn Marino 	    if (pairnames(argc, argv, rcsreadopen, true, false)  <=  0)
320*86d7f5d3SJohn Marino 		    continue;
321*86d7f5d3SJohn Marino 	    diagnose("===================================================================\nRCS file: %s\n",RCSname);
322*86d7f5d3SJohn Marino 	    if (!rev2) {
323*86d7f5d3SJohn Marino 		/* Make sure work file is readable, and get its status.  */
324*86d7f5d3SJohn Marino 		if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
325*86d7f5d3SJohn Marino 		    eerror(workname);
326*86d7f5d3SJohn Marino 		    continue;
327*86d7f5d3SJohn Marino 		}
328*86d7f5d3SJohn Marino 	    }
329*86d7f5d3SJohn Marino 
330*86d7f5d3SJohn Marino 
331*86d7f5d3SJohn Marino 	    gettree(); /* reads in the delta tree */
332*86d7f5d3SJohn Marino 
333*86d7f5d3SJohn Marino 	    if (!Head) {
334*86d7f5d3SJohn Marino 		    rcserror("no revisions present");
335*86d7f5d3SJohn Marino 		    continue;
336*86d7f5d3SJohn Marino 	    }
337*86d7f5d3SJohn Marino 	    if (revnums==0  ||  !*rev1)
338*86d7f5d3SJohn Marino 		    rev1  =  Dbranch ? Dbranch : Head->num;
339*86d7f5d3SJohn Marino 
340*86d7f5d3SJohn Marino 	    if (!fexpandsym(rev1, &numericrev, workptr)) continue;
341*86d7f5d3SJohn Marino 	    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
342*86d7f5d3SJohn Marino 	    xrev1=target->num;
343*86d7f5d3SJohn Marino #if DIFF_L
344*86d7f5d3SJohn Marino 	    if (diff_label1)
345*86d7f5d3SJohn Marino 		*diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
346*86d7f5d3SJohn Marino #endif
347*86d7f5d3SJohn Marino 
348*86d7f5d3SJohn Marino 	    lexpandarg = expandarg;
349*86d7f5d3SJohn Marino 	    if (revnums==2) {
350*86d7f5d3SJohn Marino 		    if (!fexpandsym(
351*86d7f5d3SJohn Marino 			    *rev2 ? rev2  : Dbranch ? Dbranch  : Head->num,
352*86d7f5d3SJohn Marino 			    &numericrev,
353*86d7f5d3SJohn Marino 			    workptr
354*86d7f5d3SJohn Marino 		    ))
355*86d7f5d3SJohn Marino 			continue;
356*86d7f5d3SJohn Marino 		    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
357*86d7f5d3SJohn Marino 		    xrev2=target->num;
358*86d7f5d3SJohn Marino 		    if (no_diff_means_no_output  &&  xrev1 == xrev2)
359*86d7f5d3SJohn Marino 			continue;
360*86d7f5d3SJohn Marino 	    } else if (
361*86d7f5d3SJohn Marino 			target->lockedby
362*86d7f5d3SJohn Marino 		&&	!lexpandarg
363*86d7f5d3SJohn Marino 		&&	Expand == KEYVAL_EXPAND
364*86d7f5d3SJohn Marino 		&&	WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
365*86d7f5d3SJohn Marino 	    )
366*86d7f5d3SJohn Marino 		    lexpandarg = "-kkvl";
367*86d7f5d3SJohn Marino 	    Izclose(&workptr);
368*86d7f5d3SJohn Marino #if DIFF_L
369*86d7f5d3SJohn Marino 	    if (diff_label2) {
370*86d7f5d3SJohn Marino 		if (revnums == 2)
371*86d7f5d3SJohn Marino 		    *diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
372*86d7f5d3SJohn Marino 		else {
373*86d7f5d3SJohn Marino 		    time2date(workstat.st_mtime, date2);
374*86d7f5d3SJohn Marino 		    *diff_label2 = setup_label(&labelbuf[1], (char*)0, date2);
375*86d7f5d3SJohn Marino 		}
376*86d7f5d3SJohn Marino 	    }
377*86d7f5d3SJohn Marino #endif
378*86d7f5d3SJohn Marino 
379*86d7f5d3SJohn Marino 	    diagnose("retrieving revision %s\n", xrev1);
380*86d7f5d3SJohn Marino 	    bufscpy(&commarg, "-p");
381*86d7f5d3SJohn Marino 	    bufscat(&commarg, rev1); /* not xrev1, for $Name's sake */
382*86d7f5d3SJohn Marino 
383*86d7f5d3SJohn Marino 	    pp = &cov[3 + !DIFF_L];
384*86d7f5d3SJohn Marino 	    *pp++ = commarg.string;
385*86d7f5d3SJohn Marino 	    if (lexpandarg) *pp++ = lexpandarg;
386*86d7f5d3SJohn Marino 	    if (suffixarg) *pp++ = suffixarg;
387*86d7f5d3SJohn Marino 	    if (versionarg) *pp++ = versionarg;
388*86d7f5d3SJohn Marino 	    if (zonearg) *pp++ = zonearg;
389*86d7f5d3SJohn Marino 	    *pp++ = RCSname;
390*86d7f5d3SJohn Marino 	    *pp = 0;
391*86d7f5d3SJohn Marino 
392*86d7f5d3SJohn Marino 	    diffp = diffpend;
393*86d7f5d3SJohn Marino #	    if OPEN_O_BINARY
394*86d7f5d3SJohn Marino 		    if (Expand == BINARY_EXPAND)
395*86d7f5d3SJohn Marino 			    *diffp++ = "--binary";
396*86d7f5d3SJohn Marino #	    endif
397*86d7f5d3SJohn Marino 	    diffp[0] = maketemp(0);
398*86d7f5d3SJohn Marino 	    if (runv(-1, diffp[0], cov)) {
399*86d7f5d3SJohn Marino 		    rcserror("co failed");
400*86d7f5d3SJohn Marino 		    continue;
401*86d7f5d3SJohn Marino 	    }
402*86d7f5d3SJohn Marino 	    if (!rev2) {
403*86d7f5d3SJohn Marino 		    diffp[1] = workname;
404*86d7f5d3SJohn Marino 		    if (*workname == '-') {
405*86d7f5d3SJohn Marino 			char *dp = ftnalloc(char, strlen(workname)+3);
406*86d7f5d3SJohn Marino 			diffp[1] = dp;
407*86d7f5d3SJohn Marino 			*dp++ = '.';
408*86d7f5d3SJohn Marino 			*dp++ = SLASH;
409*86d7f5d3SJohn Marino 			VOID strcpy(dp, workname);
410*86d7f5d3SJohn Marino 		    }
411*86d7f5d3SJohn Marino 	    } else {
412*86d7f5d3SJohn Marino 		    diagnose("retrieving revision %s\n",xrev2);
413*86d7f5d3SJohn Marino 		    bufscpy(&commarg, "-p");
414*86d7f5d3SJohn Marino 		    bufscat(&commarg, rev2); /* not xrev2, for $Name's sake */
415*86d7f5d3SJohn Marino 		    cov[3 + !DIFF_L] = commarg.string;
416*86d7f5d3SJohn Marino 		    diffp[1] = maketemp(1);
417*86d7f5d3SJohn Marino 		    if (runv(-1, diffp[1], cov)) {
418*86d7f5d3SJohn Marino 			    rcserror("co failed");
419*86d7f5d3SJohn Marino 			    continue;
420*86d7f5d3SJohn Marino 		    }
421*86d7f5d3SJohn Marino 	    }
422*86d7f5d3SJohn Marino 	    if (!rev2)
423*86d7f5d3SJohn Marino 		    diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workname);
424*86d7f5d3SJohn Marino 	    else
425*86d7f5d3SJohn Marino 		    diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
426*86d7f5d3SJohn Marino 
427*86d7f5d3SJohn Marino 	    diffp[2] = 0;
428*86d7f5d3SJohn Marino 	    switch (runv(-1, (char*)0, diffv)) {
429*86d7f5d3SJohn Marino 		    case DIFF_SUCCESS:
430*86d7f5d3SJohn Marino 			    break;
431*86d7f5d3SJohn Marino 		    case DIFF_FAILURE:
432*86d7f5d3SJohn Marino 			    if (exitstatus == DIFF_SUCCESS)
433*86d7f5d3SJohn Marino 				    exitstatus = DIFF_FAILURE;
434*86d7f5d3SJohn Marino 			    break;
435*86d7f5d3SJohn Marino 		    default:
436*86d7f5d3SJohn Marino 			    workerror("diff failed");
437*86d7f5d3SJohn Marino 	    }
438*86d7f5d3SJohn Marino 	}
439*86d7f5d3SJohn Marino 
440*86d7f5d3SJohn Marino     tempunlink();
441*86d7f5d3SJohn Marino     exitmain(exitstatus);
442*86d7f5d3SJohn Marino }
443*86d7f5d3SJohn Marino 
444*86d7f5d3SJohn Marino     static void
cleanup()445*86d7f5d3SJohn Marino cleanup()
446*86d7f5d3SJohn Marino {
447*86d7f5d3SJohn Marino     if (nerror) exitstatus = DIFF_TROUBLE;
448*86d7f5d3SJohn Marino     Izclose(&finptr);
449*86d7f5d3SJohn Marino     Izclose(&workptr);
450*86d7f5d3SJohn Marino }
451*86d7f5d3SJohn Marino 
452*86d7f5d3SJohn Marino #if RCS_lint
453*86d7f5d3SJohn Marino #	define exiterr rdiffExit
454*86d7f5d3SJohn Marino #endif
455*86d7f5d3SJohn Marino     void
exiterr()456*86d7f5d3SJohn Marino exiterr()
457*86d7f5d3SJohn Marino {
458*86d7f5d3SJohn Marino     tempunlink();
459*86d7f5d3SJohn Marino     _exit(DIFF_TROUBLE);
460*86d7f5d3SJohn Marino }
461*86d7f5d3SJohn Marino 
462*86d7f5d3SJohn Marino #if DIFF_L
463*86d7f5d3SJohn Marino 	static char const *
setup_label(b,num,date)464*86d7f5d3SJohn Marino setup_label(b, num, date)
465*86d7f5d3SJohn Marino 	struct buf *b;
466*86d7f5d3SJohn Marino 	char const *num;
467*86d7f5d3SJohn Marino 	char const date[datesize];
468*86d7f5d3SJohn Marino {
469*86d7f5d3SJohn Marino 	char *p;
470*86d7f5d3SJohn Marino 	char datestr[datesize + zonelenmax];
471*86d7f5d3SJohn Marino 	VOID date2str(date, datestr);
472*86d7f5d3SJohn Marino 	bufalloc(b,
473*86d7f5d3SJohn Marino 		strlen(workname)
474*86d7f5d3SJohn Marino 		+ sizeof datestr + 4
475*86d7f5d3SJohn Marino 		+ (num ? strlen(num) : 0)
476*86d7f5d3SJohn Marino 	);
477*86d7f5d3SJohn Marino 	p = b->string;
478*86d7f5d3SJohn Marino 	if (num)
479*86d7f5d3SJohn Marino 		VOID sprintf(p, "-L%s\t%s\t%s", workname, datestr, num);
480*86d7f5d3SJohn Marino 	else
481*86d7f5d3SJohn Marino 		VOID sprintf(p, "-L%s\t%s", workname, datestr);
482*86d7f5d3SJohn Marino 	return p;
483*86d7f5d3SJohn Marino }
484*86d7f5d3SJohn Marino #endif
485