xref: /netbsd/external/gpl2/rcs/dist/src/rcsdiff.c (revision 0d69c6cf)
1*0d69c6cfSchristos /*	$NetBSD: rcsdiff.c,v 1.2 2016/01/14 04:22:39 christos Exp $	*/
2075184b7Schristos 
3075184b7Schristos /* Compare RCS revisions.  */
4075184b7Schristos 
5075184b7Schristos /* Copyright 1982, 1988, 1989 Walter Tichy
6075184b7Schristos    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
7075184b7Schristos    Distributed under license by the Free Software Foundation, Inc.
8075184b7Schristos 
9075184b7Schristos This file is part of RCS.
10075184b7Schristos 
11075184b7Schristos RCS is free software; you can redistribute it and/or modify
12075184b7Schristos it under the terms of the GNU General Public License as published by
13075184b7Schristos the Free Software Foundation; either version 2, or (at your option)
14075184b7Schristos any later version.
15075184b7Schristos 
16075184b7Schristos RCS is distributed in the hope that it will be useful,
17075184b7Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
18075184b7Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19075184b7Schristos GNU General Public License for more details.
20075184b7Schristos 
21075184b7Schristos You should have received a copy of the GNU General Public License
22075184b7Schristos along with RCS; see the file COPYING.
23075184b7Schristos If not, write to the Free Software Foundation,
24075184b7Schristos 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25075184b7Schristos 
26075184b7Schristos Report problems and direct all questions to:
27075184b7Schristos 
28075184b7Schristos     rcs-bugs@cs.purdue.edu
29075184b7Schristos 
30075184b7Schristos */
31075184b7Schristos 
32075184b7Schristos /*
33075184b7Schristos  * Log: rcsdiff.c,v
34075184b7Schristos  * Revision 5.19  1995/06/16 06:19:24  eggert
35075184b7Schristos  * Update FSF address.
36075184b7Schristos  *
37075184b7Schristos  * Revision 5.18  1995/06/01 16:23:43  eggert
38075184b7Schristos  * (main): Pass "--binary" if -kb and if --binary makes a difference.
39075184b7Schristos  * Don't treat + options specially.
40075184b7Schristos  *
41075184b7Schristos  * Revision 5.17  1994/03/17 14:05:48  eggert
42075184b7Schristos  * Specify subprocess input via file descriptor, not file name.  Remove lint.
43075184b7Schristos  *
44075184b7Schristos  * Revision 5.16  1993/11/09 17:40:15  eggert
45075184b7Schristos  * -V now prints version on stdout and exits.  Don't print usage twice.
46075184b7Schristos  *
47075184b7Schristos  * Revision 5.15  1993/11/03 17:42:27  eggert
48075184b7Schristos  * Add -z.  Ignore -T.  Pass -Vn to `co'.  Add Name keyword.
49075184b7Schristos  * Put revision numbers in -c output.  Improve quality of diagnostics.
50075184b7Schristos  *
51075184b7Schristos  * Revision 5.14  1992/07/28  16:12:44  eggert
52075184b7Schristos  * Add -V.  Use co -M for better dates with traditional diff -c.
53075184b7Schristos  *
54075184b7Schristos  * Revision 5.13  1992/02/17  23:02:23  eggert
55075184b7Schristos  * Output more readable context diff headers.
56075184b7Schristos  * Suppress needless checkout and comparison of identical revisions.
57075184b7Schristos  *
58075184b7Schristos  * Revision 5.12  1992/01/24  18:44:19  eggert
59075184b7Schristos  * Add GNU diff 1.15.2's new options.  lint -> RCS_lint
60075184b7Schristos  *
61075184b7Schristos  * Revision 5.11  1992/01/06  02:42:34  eggert
62075184b7Schristos  * Update usage string.
63075184b7Schristos  *
64075184b7Schristos  * Revision 5.10  1991/10/07  17:32:46  eggert
65075184b7Schristos  * Remove lint.
66075184b7Schristos  *
67075184b7Schristos  * Revision 5.9  1991/08/19  03:13:55  eggert
68075184b7Schristos  * Add RCSINIT, -r$.  Tune.
69075184b7Schristos  *
70075184b7Schristos  * Revision 5.8  1991/04/21  11:58:21  eggert
71075184b7Schristos  * Add -x, RCSINIT, MS-DOS support.
72075184b7Schristos  *
73075184b7Schristos  * Revision 5.7  1990/12/13  06:54:07  eggert
74075184b7Schristos  * GNU diff 1.15 has -u.
75075184b7Schristos  *
76075184b7Schristos  * Revision 5.6  1990/11/01  05:03:39  eggert
77075184b7Schristos  * Remove unneeded setid check.
78075184b7Schristos  *
79075184b7Schristos  * Revision 5.5  1990/10/04  06:30:19  eggert
80075184b7Schristos  * Accumulate exit status across files.
81075184b7Schristos  *
82075184b7Schristos  * Revision 5.4  1990/09/27  01:31:43  eggert
83075184b7Schristos  * Yield 1, not EXIT_FAILURE, when diffs are found.
84075184b7Schristos  *
85075184b7Schristos  * Revision 5.3  1990/09/11  02:41:11  eggert
86075184b7Schristos  * Simplify -kkvl test.
87075184b7Schristos  *
88075184b7Schristos  * Revision 5.2  1990/09/04  17:07:19  eggert
89075184b7Schristos  * Diff's argv was too small by 1.
90075184b7Schristos  *
91075184b7Schristos  * Revision 5.1  1990/08/29  07:13:55  eggert
92075184b7Schristos  * Add -kkvl.
93075184b7Schristos  *
94075184b7Schristos  * Revision 5.0  1990/08/22  08:12:46  eggert
95075184b7Schristos  * Add -k, -V.  Don't use access().  Add setuid support.
96075184b7Schristos  * Remove compile-time limits; use malloc instead.
97075184b7Schristos  * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
98075184b7Schristos  * Add GNU diff's flags.  Make lock and temp files faster and safer.
99075184b7Schristos  * Ansify and Posixate.
100075184b7Schristos  *
101075184b7Schristos  * Revision 4.6  89/05/01  15:12:27  narten
102075184b7Schristos  * changed copyright header to reflect current distribution rules
103075184b7Schristos  *
104075184b7Schristos  * Revision 4.5  88/08/09  19:12:41  eggert
105075184b7Schristos  * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
106075184b7Schristos  *
107075184b7Schristos  * Revision 4.4  87/12/18  11:37:46  narten
108075184b7Schristos  * changes Jay Lepreau made in the 4.3 BSD version, to add support for
109075184b7Schristos  * "-i", "-w", and "-t" flags and to permit flags to be bundled together,
110075184b7Schristos  * merged in.
111075184b7Schristos  *
112075184b7Schristos  * Revision 4.3  87/10/18  10:31:42  narten
113075184b7Schristos  * Updating version numbers. Changes relative to 1.1 actually
114075184b7Schristos  * relative to 4.1
115075184b7Schristos  *
116075184b7Schristos  * Revision 1.3  87/09/24  13:59:21  narten
117075184b7Schristos  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
118075184b7Schristos  * warnings)
119075184b7Schristos  *
120075184b7Schristos  * Revision 1.2  87/03/27  14:22:15  jenkins
121075184b7Schristos  * Port to suns
122075184b7Schristos  *
123075184b7Schristos  * Revision 4.1  83/05/03  22:13:19  wft
124075184b7Schristos  * Added default branch, option -q, exit status like diff.
125075184b7Schristos  * Added fterror() to replace faterror().
126075184b7Schristos  *
127075184b7Schristos  * Revision 3.6  83/01/15  17:52:40  wft
128075184b7Schristos  * Expanded mainprogram to handle multiple RCS files.
129075184b7Schristos  *
130075184b7Schristos  * Revision 3.5  83/01/06  09:33:45  wft
131075184b7Schristos  * Fixed passing of -c (context) option to diff.
132075184b7Schristos  *
133075184b7Schristos  * Revision 3.4  82/12/24  15:28:38  wft
134075184b7Schristos  * Added call to catchsig().
135075184b7Schristos  *
136075184b7Schristos  * Revision 3.3  82/12/10  16:08:17  wft
137075184b7Schristos  * Corrected checking of return code from diff; improved error msgs.
138075184b7Schristos  *
139075184b7Schristos  * Revision 3.2  82/12/04  13:20:09  wft
140075184b7Schristos  * replaced getdelta() with gettree(). Changed diagnostics.
141075184b7Schristos  *
142075184b7Schristos  * Revision 3.1  82/11/28  19:25:04  wft
143075184b7Schristos  * Initial revision.
144075184b7Schristos  *
145075184b7Schristos  */
146075184b7Schristos #include "rcsbase.h"
147075184b7Schristos 
148075184b7Schristos #if DIFF_L
149075184b7Schristos static char const *setup_label P((struct buf*,char const*,char const[datesize]));
150075184b7Schristos #endif
151075184b7Schristos static void cleanup P((void));
152075184b7Schristos 
153075184b7Schristos static int exitstatus;
154075184b7Schristos static RILE *workptr;
155075184b7Schristos static struct stat workstat;
156075184b7Schristos 
157075184b7Schristos mainProg(rcsdiffId, "rcsdiff", "Id: rcsdiff.c,v 5.19 1995/06/16 06:19:24 eggert Exp ")
158075184b7Schristos {
159075184b7Schristos     static char const cmdusage[] =
160075184b7Schristos 	    "\nrcsdiff usage: rcsdiff -ksubst -q -rrev1 [-rrev2] -Vn -xsuff -zzone [diff options] file ...";
161075184b7Schristos 
162075184b7Schristos     int  revnums;                 /* counter for revision numbers given */
163075184b7Schristos     char const *rev1, *rev2;	/* revision numbers from command line */
164075184b7Schristos     char const *xrev1, *xrev2;	/* expanded revision numbers */
165075184b7Schristos     char const *expandarg, *lexpandarg, *suffixarg, *versionarg, *zonearg;
166075184b7Schristos #if DIFF_L
167075184b7Schristos     static struct buf labelbuf[2];
168075184b7Schristos     int file_labels;
169075184b7Schristos     char const **diff_label1, **diff_label2;
170075184b7Schristos     char date2[datesize];
171075184b7Schristos #endif
172075184b7Schristos     char const *cov[10 + !DIFF_L];
173075184b7Schristos     char const **diffv, **diffp, **diffpend;	/* argv for subsidiary diff */
174075184b7Schristos     char const **pp, *p, *diffvstr;
175075184b7Schristos     struct buf commarg;
176075184b7Schristos     struct buf numericrev;	/* expanded revision number */
177075184b7Schristos     struct hshentries *gendeltas;	/* deltas to be generated */
178075184b7Schristos     struct hshentry * target;
179075184b7Schristos     char *a, *dcp, **newargv;
180075184b7Schristos     int no_diff_means_no_output;
181*0d69c6cfSchristos     int c;
182075184b7Schristos 
183075184b7Schristos     exitstatus = DIFF_SUCCESS;
184075184b7Schristos 
185075184b7Schristos     bufautobegin(&commarg);
186075184b7Schristos     bufautobegin(&numericrev);
187075184b7Schristos     revnums = 0;
188075184b7Schristos     rev1 = rev2 = xrev2 = 0;
189075184b7Schristos #if DIFF_L
190075184b7Schristos     file_labels = 0;
191075184b7Schristos #endif
192075184b7Schristos     expandarg = suffixarg = versionarg = zonearg = 0;
193075184b7Schristos     no_diff_means_no_output = true;
194075184b7Schristos     suffixes = X_DEFAULT;
195075184b7Schristos 
196075184b7Schristos     /*
197075184b7Schristos     * Room for runv extra + args [+ --binary] [+ 2 labels]
198075184b7Schristos     * + 1 file + 1 trailing null.
199075184b7Schristos     */
200075184b7Schristos     diffv = tnalloc(char const*, 1 + argc + !!OPEN_O_BINARY + 2*DIFF_L + 2);
201075184b7Schristos     diffp = diffv + 1;
202075184b7Schristos     *diffp++ = DIFF;
203075184b7Schristos 
204075184b7Schristos     argc = getRCSINIT(argc, argv, &newargv);
205075184b7Schristos     argv = newargv;
206075184b7Schristos     while (a = *++argv,  0<--argc && *a++=='-') {
207075184b7Schristos 	dcp = a;
208075184b7Schristos 	while ((c = *a++)) switch (c) {
209075184b7Schristos 	    case 'r':
210075184b7Schristos 		    switch (++revnums) {
211075184b7Schristos 			case 1: rev1=a; break;
212075184b7Schristos 			case 2: rev2=a; break;
213075184b7Schristos 			default: error("too many revision numbers");
214075184b7Schristos 		    }
215075184b7Schristos 		    goto option_handled;
216075184b7Schristos 	    case '-': case 'D':
217075184b7Schristos 		    no_diff_means_no_output = false;
218075184b7Schristos 		    /* fall into */
219*0d69c6cfSchristos 	    case 'C': case 'F': case 'I': case 'L': case 'W': case 'U':
220075184b7Schristos #if DIFF_L
221*0d69c6cfSchristos 		    if (c == 'L'  &&  file_labels++ == 2)
222075184b7Schristos 			faterror("too many -L options");
223075184b7Schristos #endif
224075184b7Schristos 		    *dcp++ = c;
225075184b7Schristos 		    if (*a)
226075184b7Schristos 			do *dcp++ = *a++;
227075184b7Schristos 			while (*a);
228075184b7Schristos 		    else {
229075184b7Schristos 			if (!--argc)
230075184b7Schristos 			    faterror("-%c needs following argument%s",
231075184b7Schristos 				    c, cmdusage
232075184b7Schristos 			    );
233075184b7Schristos 			*diffp++ = *argv++;
234075184b7Schristos 		    }
235075184b7Schristos 		    break;
236075184b7Schristos 	    case 'y':
237075184b7Schristos 		    no_diff_means_no_output = false;
238075184b7Schristos 		    /* fall into */
239075184b7Schristos 	    case 'B': case 'H':
240075184b7Schristos 	    case '0': case '1': case '2': case '3': case '4':
241075184b7Schristos 	    case '5': case '6': case '7': case '8': case '9':
242075184b7Schristos 	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
243075184b7Schristos 	    case 'h': case 'i': case 'n': case 'p':
244075184b7Schristos 	    case 't': case 'u': case 'w':
245075184b7Schristos 		    *dcp++ = c;
246075184b7Schristos 		    break;
247075184b7Schristos 	    case 'q':
248075184b7Schristos 		    quietflag=true;
249075184b7Schristos 		    break;
250075184b7Schristos 	    case 'x':
251075184b7Schristos 		    suffixarg = *argv;
252075184b7Schristos 		    suffixes = *argv + 2;
253075184b7Schristos 		    goto option_handled;
254075184b7Schristos 	    case 'z':
255075184b7Schristos 		    zonearg = *argv;
256075184b7Schristos 		    zone_set(*argv + 2);
257075184b7Schristos 		    goto option_handled;
258075184b7Schristos 	    case 'T':
259075184b7Schristos 		    /* Ignore -T, so that RCSINIT can contain -T.  */
260075184b7Schristos 		    if (*a)
261075184b7Schristos 			    goto unknown;
262075184b7Schristos 		    break;
263075184b7Schristos 	    case 'V':
264075184b7Schristos 		    versionarg = *argv;
265075184b7Schristos 		    setRCSversion(versionarg);
266075184b7Schristos 		    goto option_handled;
267075184b7Schristos 	    case 'k':
268075184b7Schristos 		    expandarg = *argv;
269075184b7Schristos 		    if (0 <= str2expmode(expandarg+2))
270075184b7Schristos 			goto option_handled;
271075184b7Schristos 		    /* fall into */
272075184b7Schristos 	    default:
273075184b7Schristos 	    unknown:
274075184b7Schristos 		    error("unknown option: %s%s", *argv, cmdusage);
275075184b7Schristos 	    };
276075184b7Schristos       option_handled:
277075184b7Schristos 	if (dcp != *argv+1) {
278075184b7Schristos 	    *dcp = 0;
279075184b7Schristos 	    *diffp++ = *argv;
280075184b7Schristos 	}
281075184b7Schristos     } /* end of option processing */
282075184b7Schristos 
283075184b7Schristos     for (pp = diffv+2, c = 0;  pp<diffp;  )
284075184b7Schristos 	    c += strlen(*pp++) + 1;
285075184b7Schristos     diffvstr = a = tnalloc(char, c + 1);
286075184b7Schristos     for (pp = diffv+2;  pp<diffp;  ) {
287075184b7Schristos 	    p = *pp++;
288075184b7Schristos 	    *a++ = ' ';
289075184b7Schristos 	    while ((*a = *p++))
290075184b7Schristos 		    a++;
291075184b7Schristos     }
292075184b7Schristos     *a = 0;
293075184b7Schristos 
294075184b7Schristos #if DIFF_L
295075184b7Schristos     diff_label1 = diff_label2 = 0;
296075184b7Schristos     if (file_labels < 2) {
297075184b7Schristos 	    if (!file_labels)
298075184b7Schristos 		    diff_label1 = diffp++;
299075184b7Schristos 	    diff_label2 = diffp++;
300075184b7Schristos     }
301075184b7Schristos #endif
302075184b7Schristos     diffpend = diffp;
303075184b7Schristos 
304075184b7Schristos     cov[1] = CO;
305075184b7Schristos     cov[2] = "-q";
306075184b7Schristos #   if !DIFF_L
307075184b7Schristos 	cov[3] = "-M";
308075184b7Schristos #   endif
309075184b7Schristos 
310075184b7Schristos     /* Now handle all pathnames.  */
311075184b7Schristos     if (nerror)
312075184b7Schristos 	cleanup();
313075184b7Schristos     else if (argc < 1)
314075184b7Schristos 	faterror("no input file%s", cmdusage);
315075184b7Schristos     else
316075184b7Schristos 	for (;  0 < argc;  cleanup(), ++argv, --argc) {
317075184b7Schristos 	    ffree();
318075184b7Schristos 
319075184b7Schristos 	    if (pairnames(argc, argv, rcsreadopen, true, false)  <=  0)
320075184b7Schristos 		    continue;
321075184b7Schristos 	    diagnose("===================================================================\nRCS file: %s\n",RCSname);
322075184b7Schristos 	    if (!rev2) {
323075184b7Schristos 		/* Make sure work file is readable, and get its status.  */
324075184b7Schristos 		if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
325075184b7Schristos 		    eerror(workname);
326075184b7Schristos 		    continue;
327075184b7Schristos 		}
328075184b7Schristos 	    }
329075184b7Schristos 
330075184b7Schristos 
331075184b7Schristos 	    gettree(); /* reads in the delta tree */
332075184b7Schristos 
333075184b7Schristos 	    if (!Head) {
334075184b7Schristos 		    rcserror("no revisions present");
335075184b7Schristos 		    continue;
336075184b7Schristos 	    }
337075184b7Schristos 	    if (revnums==0  ||  !*rev1)
338075184b7Schristos 		    rev1  =  Dbranch ? Dbranch : Head->num;
339075184b7Schristos 
340075184b7Schristos 	    if (!fexpandsym(rev1, &numericrev, workptr)) continue;
341075184b7Schristos 	    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
342075184b7Schristos 	    xrev1=target->num;
343075184b7Schristos #if DIFF_L
344075184b7Schristos 	    if (diff_label1)
345075184b7Schristos 		*diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
346075184b7Schristos #endif
347075184b7Schristos 
348075184b7Schristos 	    lexpandarg = expandarg;
349075184b7Schristos 	    if (revnums==2) {
350075184b7Schristos 		    if (!fexpandsym(
351075184b7Schristos 			    *rev2 ? rev2  : Dbranch ? Dbranch  : Head->num,
352075184b7Schristos 			    &numericrev,
353075184b7Schristos 			    workptr
354075184b7Schristos 		    ))
355075184b7Schristos 			continue;
356075184b7Schristos 		    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
357075184b7Schristos 		    xrev2=target->num;
358075184b7Schristos 		    if (no_diff_means_no_output  &&  xrev1 == xrev2)
359075184b7Schristos 			continue;
360075184b7Schristos 	    } else if (
361075184b7Schristos 			target->lockedby
362075184b7Schristos 		&&	!lexpandarg
363075184b7Schristos 		&&	Expand == KEYVAL_EXPAND
364075184b7Schristos 		&&	WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
365075184b7Schristos 	    )
366075184b7Schristos 		    lexpandarg = "-kkvl";
367075184b7Schristos 	    Izclose(&workptr);
368075184b7Schristos #if DIFF_L
369*0d69c6cfSchristos 	    if (diff_label2) {
370075184b7Schristos 		if (revnums == 2)
371075184b7Schristos 		    *diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
372075184b7Schristos 		else {
373075184b7Schristos 		    time2date(workstat.st_mtime, date2);
374075184b7Schristos 		    *diff_label2 = setup_label(&labelbuf[1], (char*)0, date2);
375075184b7Schristos 		}
376*0d69c6cfSchristos 	    }
377075184b7Schristos #endif
378075184b7Schristos 
379075184b7Schristos 	    diagnose("retrieving revision %s\n", xrev1);
380075184b7Schristos 	    bufscpy(&commarg, "-p");
381075184b7Schristos 	    bufscat(&commarg, rev1); /* not xrev1, for $Name's sake */
382075184b7Schristos 
383075184b7Schristos 	    pp = &cov[3 + !DIFF_L];
384075184b7Schristos 	    *pp++ = commarg.string;
385075184b7Schristos 	    if (lexpandarg) *pp++ = lexpandarg;
386075184b7Schristos 	    if (suffixarg) *pp++ = suffixarg;
387075184b7Schristos 	    if (versionarg) *pp++ = versionarg;
388075184b7Schristos 	    if (zonearg) *pp++ = zonearg;
389075184b7Schristos 	    *pp++ = RCSname;
390075184b7Schristos 	    *pp = 0;
391075184b7Schristos 
392075184b7Schristos 	    diffp = diffpend;
393075184b7Schristos #	    if OPEN_O_BINARY
394075184b7Schristos 		    if (Expand == BINARY_EXPAND)
395075184b7Schristos 			    *diffp++ = "--binary";
396075184b7Schristos #	    endif
397075184b7Schristos 	    diffp[0] = maketemp(0);
398075184b7Schristos 	    if (runv(-1, diffp[0], cov)) {
399075184b7Schristos 		    rcserror("co failed");
400075184b7Schristos 		    continue;
401075184b7Schristos 	    }
402075184b7Schristos 	    if (!rev2) {
403075184b7Schristos 		    diffp[1] = workname;
404075184b7Schristos 		    if (*workname == '-') {
405075184b7Schristos 			char *dp = ftnalloc(char, strlen(workname)+3);
406075184b7Schristos 			diffp[1] = dp;
407075184b7Schristos 			*dp++ = '.';
408075184b7Schristos 			*dp++ = SLASH;
409075184b7Schristos 			VOID strcpy(dp, workname);
410075184b7Schristos 		    }
411075184b7Schristos 	    } else {
412075184b7Schristos 		    diagnose("retrieving revision %s\n",xrev2);
413075184b7Schristos 		    bufscpy(&commarg, "-p");
414075184b7Schristos 		    bufscat(&commarg, rev2); /* not xrev2, for $Name's sake */
415075184b7Schristos 		    cov[3 + !DIFF_L] = commarg.string;
416075184b7Schristos 		    diffp[1] = maketemp(1);
417075184b7Schristos 		    if (runv(-1, diffp[1], cov)) {
418075184b7Schristos 			    rcserror("co failed");
419075184b7Schristos 			    continue;
420075184b7Schristos 		    }
421075184b7Schristos 	    }
422075184b7Schristos 	    if (!rev2)
423075184b7Schristos 		    diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workname);
424075184b7Schristos 	    else
425075184b7Schristos 		    diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
426075184b7Schristos 
427075184b7Schristos 	    diffp[2] = 0;
428075184b7Schristos 	    switch (runv(-1, (char*)0, diffv)) {
429075184b7Schristos 		    case DIFF_SUCCESS:
430075184b7Schristos 			    break;
431075184b7Schristos 		    case DIFF_FAILURE:
432075184b7Schristos 			    if (exitstatus == DIFF_SUCCESS)
433075184b7Schristos 				    exitstatus = DIFF_FAILURE;
434075184b7Schristos 			    break;
435075184b7Schristos 		    default:
436075184b7Schristos 			    workerror("diff failed");
437075184b7Schristos 	    }
438075184b7Schristos 	}
439075184b7Schristos 
440075184b7Schristos     tempunlink();
441075184b7Schristos     exitmain(exitstatus);
442075184b7Schristos }
443075184b7Schristos 
444075184b7Schristos     static void
cleanup()445075184b7Schristos cleanup()
446075184b7Schristos {
447075184b7Schristos     if (nerror) exitstatus = DIFF_TROUBLE;
448075184b7Schristos     Izclose(&finptr);
449075184b7Schristos     Izclose(&workptr);
450075184b7Schristos }
451075184b7Schristos 
452075184b7Schristos #if RCS_lint
453075184b7Schristos #	define exiterr rdiffExit
454075184b7Schristos #endif
455075184b7Schristos     void
exiterr()456075184b7Schristos exiterr()
457075184b7Schristos {
458075184b7Schristos     tempunlink();
459075184b7Schristos     _exit(DIFF_TROUBLE);
460075184b7Schristos }
461075184b7Schristos 
462075184b7Schristos #if DIFF_L
463075184b7Schristos 	static char const *
setup_label(b,num,date)464075184b7Schristos setup_label(b, num, date)
465075184b7Schristos 	struct buf *b;
466075184b7Schristos 	char const *num;
467075184b7Schristos 	char const date[datesize];
468075184b7Schristos {
469075184b7Schristos 	char *p;
470075184b7Schristos 	char datestr[datesize + zonelenmax];
471075184b7Schristos 	VOID date2str(date, datestr);
472075184b7Schristos 	bufalloc(b,
473075184b7Schristos 		strlen(workname)
474075184b7Schristos 		+ sizeof datestr + 4
475075184b7Schristos 		+ (num ? strlen(num) : 0)
476075184b7Schristos 	);
477075184b7Schristos 	p = b->string;
478075184b7Schristos 	if (num)
479075184b7Schristos 		VOID sprintf(p, "-L%s\t%s\t%s", workname, datestr, num);
480075184b7Schristos 	else
481075184b7Schristos 		VOID sprintf(p, "-L%s\t%s", workname, datestr);
482075184b7Schristos 	return p;
483075184b7Schristos }
484075184b7Schristos #endif
485