xref: /dflybsd-src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Compare 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/rcsdiff/rcsdiff.c,v 1.8 1999/08/27 23:36:55 peter Exp $
3286d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c,v 1.2 2003/06/17 04:25:48 dillon Exp $
3386d7f5d3SJohn Marino  *
3486d7f5d3SJohn Marino  * Revision 5.19  1995/06/16 06:19:24  eggert
3586d7f5d3SJohn Marino  * Update FSF address.
3686d7f5d3SJohn Marino  *
3786d7f5d3SJohn Marino  * Revision 5.18  1995/06/01 16:23:43  eggert
3886d7f5d3SJohn Marino  * (main): Pass "--binary" if -kb and if --binary makes a difference.
3986d7f5d3SJohn Marino  * Don't treat + options specially.
4086d7f5d3SJohn Marino  *
4186d7f5d3SJohn Marino  * Revision 5.17  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.16  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.15  1993/11/03 17:42:27  eggert
4886d7f5d3SJohn Marino  * Add -z.  Ignore -T.  Pass -Vn to `co'.  Add Name keyword.
4986d7f5d3SJohn Marino  * Put revision numbers in -c output.  Improve quality of diagnostics.
5086d7f5d3SJohn Marino  *
5186d7f5d3SJohn Marino  * Revision 5.14  1992/07/28  16:12:44  eggert
5286d7f5d3SJohn Marino  * Add -V.  Use co -M for better dates with traditional diff -c.
5386d7f5d3SJohn Marino  *
5486d7f5d3SJohn Marino  * Revision 5.13  1992/02/17  23:02:23  eggert
5586d7f5d3SJohn Marino  * Output more readable context diff headers.
5686d7f5d3SJohn Marino  * Suppress needless checkout and comparison of identical revisions.
5786d7f5d3SJohn Marino  *
5886d7f5d3SJohn Marino  * Revision 5.12  1992/01/24  18:44:19  eggert
5986d7f5d3SJohn Marino  * Add GNU diff 1.15.2's new options.  lint -> RCS_lint
6086d7f5d3SJohn Marino  *
6186d7f5d3SJohn Marino  * Revision 5.11  1992/01/06  02:42:34  eggert
6286d7f5d3SJohn Marino  * Update usage string.
6386d7f5d3SJohn Marino  *
6486d7f5d3SJohn Marino  * Revision 5.10  1991/10/07  17:32:46  eggert
6586d7f5d3SJohn Marino  * Remove lint.
6686d7f5d3SJohn Marino  *
6786d7f5d3SJohn Marino  * Revision 5.9  1991/08/19  03:13:55  eggert
6886d7f5d3SJohn Marino  * Add RCSINIT, -r$.  Tune.
6986d7f5d3SJohn Marino  *
7086d7f5d3SJohn Marino  * Revision 5.8  1991/04/21  11:58:21  eggert
7186d7f5d3SJohn Marino  * Add -x, RCSINIT, MS-DOS support.
7286d7f5d3SJohn Marino  *
7386d7f5d3SJohn Marino  * Revision 5.7  1990/12/13  06:54:07  eggert
7486d7f5d3SJohn Marino  * GNU diff 1.15 has -u.
7586d7f5d3SJohn Marino  *
7686d7f5d3SJohn Marino  * Revision 5.6  1990/11/01  05:03:39  eggert
7786d7f5d3SJohn Marino  * Remove unneeded setid check.
7886d7f5d3SJohn Marino  *
7986d7f5d3SJohn Marino  * Revision 5.5  1990/10/04  06:30:19  eggert
8086d7f5d3SJohn Marino  * Accumulate exit status across files.
8186d7f5d3SJohn Marino  *
8286d7f5d3SJohn Marino  * Revision 5.4  1990/09/27  01:31:43  eggert
8386d7f5d3SJohn Marino  * Yield 1, not EXIT_FAILURE, when diffs are found.
8486d7f5d3SJohn Marino  *
8586d7f5d3SJohn Marino  * Revision 5.3  1990/09/11  02:41:11  eggert
8686d7f5d3SJohn Marino  * Simplify -kkvl test.
8786d7f5d3SJohn Marino  *
8886d7f5d3SJohn Marino  * Revision 5.2  1990/09/04  17:07:19  eggert
8986d7f5d3SJohn Marino  * Diff's argv was too small by 1.
9086d7f5d3SJohn Marino  *
9186d7f5d3SJohn Marino  * Revision 5.1  1990/08/29  07:13:55  eggert
9286d7f5d3SJohn Marino  * Add -kkvl.
9386d7f5d3SJohn Marino  *
9486d7f5d3SJohn Marino  * Revision 5.0  1990/08/22  08:12:46  eggert
9586d7f5d3SJohn Marino  * Add -k, -V.  Don't use access().  Add setuid support.
9686d7f5d3SJohn Marino  * Remove compile-time limits; use malloc instead.
9786d7f5d3SJohn Marino  * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
9886d7f5d3SJohn Marino  * Add GNU diff's flags.  Make lock and temp files faster and safer.
9986d7f5d3SJohn Marino  * Ansify and Posixate.
10086d7f5d3SJohn Marino  *
10186d7f5d3SJohn Marino  * Revision 4.6  89/05/01  15:12:27  narten
10286d7f5d3SJohn Marino  * changed copyright header to reflect current distribution rules
10386d7f5d3SJohn Marino  *
10486d7f5d3SJohn Marino  * Revision 4.5  88/08/09  19:12:41  eggert
10586d7f5d3SJohn Marino  * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
10686d7f5d3SJohn Marino  *
10786d7f5d3SJohn Marino  * Revision 4.4  87/12/18  11:37:46  narten
10886d7f5d3SJohn Marino  * changes Jay Lepreau made in the 4.3 BSD version, to add support for
10986d7f5d3SJohn Marino  * "-i", "-w", and "-t" flags and to permit flags to be bundled together,
11086d7f5d3SJohn Marino  * merged in.
11186d7f5d3SJohn Marino  *
11286d7f5d3SJohn Marino  * Revision 4.3  87/10/18  10:31:42  narten
11386d7f5d3SJohn Marino  * Updating version numbers. Changes relative to 1.1 actually
11486d7f5d3SJohn Marino  * relative to 4.1
11586d7f5d3SJohn Marino  *
11686d7f5d3SJohn Marino  * Revision 1.3  87/09/24  13:59:21  narten
11786d7f5d3SJohn Marino  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
11886d7f5d3SJohn Marino  * warnings)
11986d7f5d3SJohn Marino  *
12086d7f5d3SJohn Marino  * Revision 1.2  87/03/27  14:22:15  jenkins
12186d7f5d3SJohn Marino  * Port to suns
12286d7f5d3SJohn Marino  *
12386d7f5d3SJohn Marino  * Revision 4.1  83/05/03  22:13:19  wft
12486d7f5d3SJohn Marino  * Added default branch, option -q, exit status like diff.
12586d7f5d3SJohn Marino  * Added fterror() to replace faterror().
12686d7f5d3SJohn Marino  *
12786d7f5d3SJohn Marino  * Revision 3.6  83/01/15  17:52:40  wft
12886d7f5d3SJohn Marino  * Expanded mainprogram to handle multiple RCS files.
12986d7f5d3SJohn Marino  *
13086d7f5d3SJohn Marino  * Revision 3.5  83/01/06  09:33:45  wft
13186d7f5d3SJohn Marino  * Fixed passing of -c (context) option to diff.
13286d7f5d3SJohn Marino  *
13386d7f5d3SJohn Marino  * Revision 3.4  82/12/24  15:28:38  wft
13486d7f5d3SJohn Marino  * Added call to catchsig().
13586d7f5d3SJohn Marino  *
13686d7f5d3SJohn Marino  * Revision 3.3  82/12/10  16:08:17  wft
13786d7f5d3SJohn Marino  * Corrected checking of return code from diff; improved error msgs.
13886d7f5d3SJohn Marino  *
13986d7f5d3SJohn Marino  * Revision 3.2  82/12/04  13:20:09  wft
14086d7f5d3SJohn Marino  * replaced getdelta() with gettree(). Changed diagnostics.
14186d7f5d3SJohn Marino  *
14286d7f5d3SJohn Marino  * Revision 3.1  82/11/28  19:25:04  wft
14386d7f5d3SJohn Marino  * Initial revision.
14486d7f5d3SJohn Marino  *
14586d7f5d3SJohn Marino  */
14686d7f5d3SJohn Marino #include "rcsbase.h"
14786d7f5d3SJohn Marino 
14886d7f5d3SJohn Marino #if DIFF_L
14986d7f5d3SJohn Marino static char const *setup_label P((struct buf*,char const*,char const[datesize]));
15086d7f5d3SJohn Marino #endif
15186d7f5d3SJohn Marino static void cleanup P((void));
15286d7f5d3SJohn Marino 
15386d7f5d3SJohn Marino static int exitstatus;
15486d7f5d3SJohn Marino static RILE *workptr;
15586d7f5d3SJohn Marino static struct stat workstat;
15686d7f5d3SJohn Marino 
15786d7f5d3SJohn Marino mainProg(rcsdiffId, "rcsdiff", "$DragonFly: src/gnu/usr.bin/rcs/rcsdiff/rcsdiff.c,v 1.2 2003/06/17 04:25:48 dillon Exp $")
15886d7f5d3SJohn Marino {
15986d7f5d3SJohn Marino     static char const cmdusage[] =
16086d7f5d3SJohn Marino 	    "\nrcsdiff usage: rcsdiff -ksubst -q -rrev1 [-rrev2] -Vn -xsuff -zzone [diff options] file ...";
16186d7f5d3SJohn Marino 
16286d7f5d3SJohn Marino     int  revnums;                 /* counter for revision numbers given */
16386d7f5d3SJohn Marino     char const *rev1, *rev2;	/* revision numbers from command line */
16486d7f5d3SJohn Marino     char const *xrev1, *xrev2;	/* expanded revision numbers */
16586d7f5d3SJohn Marino     char const *expandarg, *lexpandarg, *suffixarg, *versionarg, *zonearg;
16686d7f5d3SJohn Marino #if DIFF_L
16786d7f5d3SJohn Marino     static struct buf labelbuf[2];
16886d7f5d3SJohn Marino     int file_labels;
16986d7f5d3SJohn Marino     char const **diff_label1, **diff_label2;
17086d7f5d3SJohn Marino     char date2[datesize];
17186d7f5d3SJohn Marino #endif
17286d7f5d3SJohn Marino     char const *cov[10 + !DIFF_L];
17386d7f5d3SJohn Marino     char const **diffv, **diffp, **diffpend;	/* argv for subsidiary diff */
17486d7f5d3SJohn Marino     char const **pp, *p, *diffvstr;
17586d7f5d3SJohn Marino     struct buf commarg;
17686d7f5d3SJohn Marino     struct buf numericrev;	/* expanded revision number */
17786d7f5d3SJohn Marino     struct hshentries *gendeltas;	/* deltas to be generated */
17886d7f5d3SJohn Marino     struct hshentry * target;
17986d7f5d3SJohn Marino     char *a, *dcp, **newargv;
18086d7f5d3SJohn Marino     int no_diff_means_no_output;
18186d7f5d3SJohn Marino     register int c;
18286d7f5d3SJohn Marino 
18386d7f5d3SJohn Marino     exitstatus = DIFF_SUCCESS;
18486d7f5d3SJohn Marino 
18586d7f5d3SJohn Marino     bufautobegin(&commarg);
18686d7f5d3SJohn Marino     bufautobegin(&numericrev);
18786d7f5d3SJohn Marino     revnums = 0;
18886d7f5d3SJohn Marino     rev1 = rev2 = xrev2 = 0;
18986d7f5d3SJohn Marino #if DIFF_L
19086d7f5d3SJohn Marino     file_labels = 0;
19186d7f5d3SJohn Marino #endif
19286d7f5d3SJohn Marino     expandarg = suffixarg = versionarg = zonearg = 0;
19386d7f5d3SJohn Marino     no_diff_means_no_output = true;
19486d7f5d3SJohn Marino     suffixes = X_DEFAULT;
19586d7f5d3SJohn Marino 
19686d7f5d3SJohn Marino     /*
19786d7f5d3SJohn Marino     * Room for runv extra + args [+ --binary] [+ 2 labels]
19886d7f5d3SJohn Marino     * + 1 file + 1 trailing null.
19986d7f5d3SJohn Marino     */
20086d7f5d3SJohn Marino     diffv = tnalloc(char const*, 1 + argc + !!OPEN_O_BINARY + 2*DIFF_L + 2);
20186d7f5d3SJohn Marino     diffp = diffv + 1;
20286d7f5d3SJohn Marino     *diffp++ = DIFF;
20386d7f5d3SJohn Marino 
20486d7f5d3SJohn Marino     argc = getRCSINIT(argc, argv, &newargv);
20586d7f5d3SJohn Marino     argv = newargv;
20686d7f5d3SJohn Marino     while (a = *++argv,  0<--argc && *a++=='-') {
20786d7f5d3SJohn Marino 	dcp = a;
20886d7f5d3SJohn Marino 	while ((c = *a++)) switch (c) {
20986d7f5d3SJohn Marino 	    case 'r':
21086d7f5d3SJohn Marino 		    switch (++revnums) {
21186d7f5d3SJohn Marino 			case 1: rev1=a; break;
21286d7f5d3SJohn Marino 			case 2: rev2=a; break;
21386d7f5d3SJohn Marino 			default: error("too many revision numbers");
21486d7f5d3SJohn Marino 		    }
21586d7f5d3SJohn Marino 		    goto option_handled;
21686d7f5d3SJohn Marino 	    case '-': case 'D':
21786d7f5d3SJohn Marino 		    no_diff_means_no_output = false;
21886d7f5d3SJohn Marino 		    /* fall into */
21986d7f5d3SJohn Marino 	    case 'C': case 'F': case 'I': case 'L': case 'W':
22086d7f5d3SJohn Marino #if DIFF_L
22186d7f5d3SJohn Marino 		    if (c == 'L'  &&  file_labels++ == 2)
22286d7f5d3SJohn Marino 			faterror("too many -L options");
22386d7f5d3SJohn Marino #endif
22486d7f5d3SJohn Marino 		    *dcp++ = c;
22586d7f5d3SJohn Marino 		    if (*a)
22686d7f5d3SJohn Marino 			do *dcp++ = *a++;
22786d7f5d3SJohn Marino 			while (*a);
22886d7f5d3SJohn Marino 		    else {
22986d7f5d3SJohn Marino 			if (!--argc)
23086d7f5d3SJohn Marino 			    faterror("-%c needs following argument%s",
23186d7f5d3SJohn Marino 				    c, cmdusage
23286d7f5d3SJohn Marino 			    );
23386d7f5d3SJohn Marino 			*diffp++ = *argv++;
23486d7f5d3SJohn Marino 		    }
23586d7f5d3SJohn Marino 		    break;
23686d7f5d3SJohn Marino 	    case 'y':
23786d7f5d3SJohn Marino 		    no_diff_means_no_output = false;
23886d7f5d3SJohn Marino 		    /* fall into */
23986d7f5d3SJohn Marino 	    case 'B': case 'H':
24086d7f5d3SJohn Marino 	    case '0': case '1': case '2': case '3': case '4':
24186d7f5d3SJohn Marino 	    case '5': case '6': case '7': case '8': case '9':
24286d7f5d3SJohn Marino 	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
24386d7f5d3SJohn Marino 	    case 'h': case 'i': case 'n': case 'p':
24486d7f5d3SJohn Marino 	    case 't': case 'u': case 'w':
24586d7f5d3SJohn Marino 		    *dcp++ = c;
24686d7f5d3SJohn Marino 		    break;
24786d7f5d3SJohn Marino 	    case 'q':
24886d7f5d3SJohn Marino 		    quietflag=true;
24986d7f5d3SJohn Marino 		    break;
25086d7f5d3SJohn Marino 	    case 'x':
25186d7f5d3SJohn Marino 		    suffixarg = *argv;
25286d7f5d3SJohn Marino 		    suffixes = *argv + 2;
25386d7f5d3SJohn Marino 		    goto option_handled;
25486d7f5d3SJohn Marino 	    case 'z':
25586d7f5d3SJohn Marino 		    zonearg = *argv;
25686d7f5d3SJohn Marino 		    zone_set(*argv + 2);
25786d7f5d3SJohn Marino 		    goto option_handled;
25886d7f5d3SJohn Marino 	    case 'T':
25986d7f5d3SJohn Marino 		    /* Ignore -T, so that RCSINIT can contain -T.  */
26086d7f5d3SJohn Marino 		    if (*a)
26186d7f5d3SJohn Marino 			    goto unknown;
26286d7f5d3SJohn Marino 		    break;
26386d7f5d3SJohn Marino 	    case 'V':
26486d7f5d3SJohn Marino 		    versionarg = *argv;
26586d7f5d3SJohn Marino 		    setRCSversion(versionarg);
26686d7f5d3SJohn Marino 		    goto option_handled;
26786d7f5d3SJohn Marino 	    case 'k':
26886d7f5d3SJohn Marino 		    expandarg = *argv;
26986d7f5d3SJohn Marino 		    if (0 <= str2expmode(expandarg+2))
27086d7f5d3SJohn Marino 			goto option_handled;
27186d7f5d3SJohn Marino 		    /* fall into */
27286d7f5d3SJohn Marino 	    default:
27386d7f5d3SJohn Marino 	    unknown:
27486d7f5d3SJohn Marino 		    error("unknown option: %s%s", *argv, cmdusage);
27586d7f5d3SJohn Marino 	    };
27686d7f5d3SJohn Marino       option_handled:
27786d7f5d3SJohn Marino 	if (dcp != *argv+1) {
27886d7f5d3SJohn Marino 	    *dcp = 0;
27986d7f5d3SJohn Marino 	    *diffp++ = *argv;
28086d7f5d3SJohn Marino 	}
28186d7f5d3SJohn Marino     } /* end of option processing */
28286d7f5d3SJohn Marino 
28386d7f5d3SJohn Marino     for (pp = diffv+2, c = 0;  pp<diffp;  )
28486d7f5d3SJohn Marino 	    c += strlen(*pp++) + 1;
28586d7f5d3SJohn Marino     diffvstr = a = tnalloc(char, c + 1);
28686d7f5d3SJohn Marino     for (pp = diffv+2;  pp<diffp;  ) {
28786d7f5d3SJohn Marino 	    p = *pp++;
28886d7f5d3SJohn Marino 	    *a++ = ' ';
28986d7f5d3SJohn Marino 	    while ((*a = *p++))
29086d7f5d3SJohn Marino 		    a++;
29186d7f5d3SJohn Marino     }
29286d7f5d3SJohn Marino     *a = 0;
29386d7f5d3SJohn Marino 
29486d7f5d3SJohn Marino #if DIFF_L
29586d7f5d3SJohn Marino     diff_label1 = diff_label2 = 0;
29686d7f5d3SJohn Marino     if (file_labels < 2) {
29786d7f5d3SJohn Marino 	    if (!file_labels)
29886d7f5d3SJohn Marino 		    diff_label1 = diffp++;
29986d7f5d3SJohn Marino 	    diff_label2 = diffp++;
30086d7f5d3SJohn Marino     }
30186d7f5d3SJohn Marino #endif
30286d7f5d3SJohn Marino     diffpend = diffp;
30386d7f5d3SJohn Marino 
30486d7f5d3SJohn Marino     cov[1] = CO;
30586d7f5d3SJohn Marino     cov[2] = "-q";
30686d7f5d3SJohn Marino #   if !DIFF_L
30786d7f5d3SJohn Marino 	cov[3] = "-M";
30886d7f5d3SJohn Marino #   endif
30986d7f5d3SJohn Marino 
31086d7f5d3SJohn Marino     /* Now handle all pathnames.  */
31186d7f5d3SJohn Marino     if (nerror)
31286d7f5d3SJohn Marino 	cleanup();
31386d7f5d3SJohn Marino     else if (argc < 1)
31486d7f5d3SJohn Marino 	faterror("no input file%s", cmdusage);
31586d7f5d3SJohn Marino     else
31686d7f5d3SJohn Marino 	for (;  0 < argc;  cleanup(), ++argv, --argc) {
31786d7f5d3SJohn Marino 	    ffree();
31886d7f5d3SJohn Marino 
31986d7f5d3SJohn Marino 	    if (pairnames(argc, argv, rcsreadopen, true, false)  <=  0)
32086d7f5d3SJohn Marino 		    continue;
32186d7f5d3SJohn Marino 	    diagnose("===================================================================\nRCS file: %s\n",RCSname);
32286d7f5d3SJohn Marino 	    if (!rev2) {
32386d7f5d3SJohn Marino 		/* Make sure work file is readable, and get its status.  */
32486d7f5d3SJohn Marino 		if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
32586d7f5d3SJohn Marino 		    eerror(workname);
32686d7f5d3SJohn Marino 		    continue;
32786d7f5d3SJohn Marino 		}
32886d7f5d3SJohn Marino 	    }
32986d7f5d3SJohn Marino 
33086d7f5d3SJohn Marino 
33186d7f5d3SJohn Marino 	    gettree(); /* reads in the delta tree */
33286d7f5d3SJohn Marino 
33386d7f5d3SJohn Marino 	    if (!Head) {
33486d7f5d3SJohn Marino 		    rcserror("no revisions present");
33586d7f5d3SJohn Marino 		    continue;
33686d7f5d3SJohn Marino 	    }
33786d7f5d3SJohn Marino 	    if (revnums==0  ||  !*rev1)
33886d7f5d3SJohn Marino 		    rev1  =  Dbranch ? Dbranch : Head->num;
33986d7f5d3SJohn Marino 
34086d7f5d3SJohn Marino 	    if (!fexpandsym(rev1, &numericrev, workptr)) continue;
34186d7f5d3SJohn Marino 	    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
34286d7f5d3SJohn Marino 	    xrev1=target->num;
34386d7f5d3SJohn Marino #if DIFF_L
34486d7f5d3SJohn Marino 	    if (diff_label1)
34586d7f5d3SJohn Marino 		*diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
34686d7f5d3SJohn Marino #endif
34786d7f5d3SJohn Marino 
34886d7f5d3SJohn Marino 	    lexpandarg = expandarg;
34986d7f5d3SJohn Marino 	    if (revnums==2) {
35086d7f5d3SJohn Marino 		    if (!fexpandsym(
35186d7f5d3SJohn Marino 			    *rev2 ? rev2  : Dbranch ? Dbranch  : Head->num,
35286d7f5d3SJohn Marino 			    &numericrev,
35386d7f5d3SJohn Marino 			    workptr
35486d7f5d3SJohn Marino 		    ))
35586d7f5d3SJohn Marino 			continue;
35686d7f5d3SJohn Marino 		    if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue;
35786d7f5d3SJohn Marino 		    xrev2=target->num;
35886d7f5d3SJohn Marino 		    if (no_diff_means_no_output  &&  xrev1 == xrev2)
35986d7f5d3SJohn Marino 			continue;
36086d7f5d3SJohn Marino 	    } else if (
36186d7f5d3SJohn Marino 			target->lockedby
36286d7f5d3SJohn Marino 		&&	!lexpandarg
36386d7f5d3SJohn Marino 		&&	Expand == KEYVAL_EXPAND
36486d7f5d3SJohn Marino 		&&	WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
36586d7f5d3SJohn Marino 	    )
36686d7f5d3SJohn Marino 		    lexpandarg = "-kkvl";
36786d7f5d3SJohn Marino 	    Izclose(&workptr);
36886d7f5d3SJohn Marino #if DIFF_L
36986d7f5d3SJohn Marino 	    if (diff_label2) {
37086d7f5d3SJohn Marino 		if (revnums == 2)
37186d7f5d3SJohn Marino 		    *diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
37286d7f5d3SJohn Marino 		else {
37386d7f5d3SJohn Marino 		    time2date(workstat.st_mtime, date2);
37486d7f5d3SJohn Marino 		    *diff_label2 = setup_label(&labelbuf[1], (char*)0, date2);
37586d7f5d3SJohn Marino 		}
37686d7f5d3SJohn Marino 	    }
37786d7f5d3SJohn Marino #endif
37886d7f5d3SJohn Marino 
37986d7f5d3SJohn Marino 	    diagnose("retrieving revision %s\n", xrev1);
38086d7f5d3SJohn Marino 	    bufscpy(&commarg, "-p");
38186d7f5d3SJohn Marino 	    bufscat(&commarg, rev1); /* not xrev1, for $Name's sake */
38286d7f5d3SJohn Marino 
38386d7f5d3SJohn Marino 	    pp = &cov[3 + !DIFF_L];
38486d7f5d3SJohn Marino 	    *pp++ = commarg.string;
38586d7f5d3SJohn Marino 	    if (lexpandarg) *pp++ = lexpandarg;
38686d7f5d3SJohn Marino 	    if (suffixarg) *pp++ = suffixarg;
38786d7f5d3SJohn Marino 	    if (versionarg) *pp++ = versionarg;
38886d7f5d3SJohn Marino 	    if (zonearg) *pp++ = zonearg;
38986d7f5d3SJohn Marino 	    *pp++ = RCSname;
39086d7f5d3SJohn Marino 	    *pp = 0;
39186d7f5d3SJohn Marino 
39286d7f5d3SJohn Marino 	    diffp = diffpend;
39386d7f5d3SJohn Marino #	    if OPEN_O_BINARY
39486d7f5d3SJohn Marino 		    if (Expand == BINARY_EXPAND)
39586d7f5d3SJohn Marino 			    *diffp++ = "--binary";
39686d7f5d3SJohn Marino #	    endif
39786d7f5d3SJohn Marino 	    diffp[0] = maketemp(0);
39886d7f5d3SJohn Marino 	    if (runv(-1, diffp[0], cov)) {
39986d7f5d3SJohn Marino 		    rcserror("co failed");
40086d7f5d3SJohn Marino 		    continue;
40186d7f5d3SJohn Marino 	    }
40286d7f5d3SJohn Marino 	    if (!rev2) {
40386d7f5d3SJohn Marino 		    diffp[1] = workname;
40486d7f5d3SJohn Marino 		    if (*workname == '-') {
40586d7f5d3SJohn Marino 			char *dp = ftnalloc(char, strlen(workname)+3);
40686d7f5d3SJohn Marino 			diffp[1] = dp;
40786d7f5d3SJohn Marino 			*dp++ = '.';
40886d7f5d3SJohn Marino 			*dp++ = SLASH;
40986d7f5d3SJohn Marino 			VOID strcpy(dp, workname);
41086d7f5d3SJohn Marino 		    }
41186d7f5d3SJohn Marino 	    } else {
41286d7f5d3SJohn Marino 		    diagnose("retrieving revision %s\n",xrev2);
41386d7f5d3SJohn Marino 		    bufscpy(&commarg, "-p");
41486d7f5d3SJohn Marino 		    bufscat(&commarg, rev2); /* not xrev2, for $Name's sake */
41586d7f5d3SJohn Marino 		    cov[3 + !DIFF_L] = commarg.string;
41686d7f5d3SJohn Marino 		    diffp[1] = maketemp(1);
41786d7f5d3SJohn Marino 		    if (runv(-1, diffp[1], cov)) {
41886d7f5d3SJohn Marino 			    rcserror("co failed");
41986d7f5d3SJohn Marino 			    continue;
42086d7f5d3SJohn Marino 		    }
42186d7f5d3SJohn Marino 	    }
42286d7f5d3SJohn Marino 	    if (!rev2)
42386d7f5d3SJohn Marino 		    diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workname);
42486d7f5d3SJohn Marino 	    else
42586d7f5d3SJohn Marino 		    diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
42686d7f5d3SJohn Marino 
42786d7f5d3SJohn Marino 	    diffp[2] = 0;
42886d7f5d3SJohn Marino 	    switch (runv(-1, (char*)0, diffv)) {
42986d7f5d3SJohn Marino 		    case DIFF_SUCCESS:
43086d7f5d3SJohn Marino 			    break;
43186d7f5d3SJohn Marino 		    case DIFF_FAILURE:
43286d7f5d3SJohn Marino 			    if (exitstatus == DIFF_SUCCESS)
43386d7f5d3SJohn Marino 				    exitstatus = DIFF_FAILURE;
43486d7f5d3SJohn Marino 			    break;
43586d7f5d3SJohn Marino 		    default:
43686d7f5d3SJohn Marino 			    workerror("diff failed");
43786d7f5d3SJohn Marino 	    }
43886d7f5d3SJohn Marino 	}
43986d7f5d3SJohn Marino 
44086d7f5d3SJohn Marino     tempunlink();
44186d7f5d3SJohn Marino     exitmain(exitstatus);
44286d7f5d3SJohn Marino }
44386d7f5d3SJohn Marino 
44486d7f5d3SJohn Marino     static void
cleanup()44586d7f5d3SJohn Marino cleanup()
44686d7f5d3SJohn Marino {
44786d7f5d3SJohn Marino     if (nerror) exitstatus = DIFF_TROUBLE;
44886d7f5d3SJohn Marino     Izclose(&finptr);
44986d7f5d3SJohn Marino     Izclose(&workptr);
45086d7f5d3SJohn Marino }
45186d7f5d3SJohn Marino 
45286d7f5d3SJohn Marino #if RCS_lint
45386d7f5d3SJohn Marino #	define exiterr rdiffExit
45486d7f5d3SJohn Marino #endif
45586d7f5d3SJohn Marino     void
exiterr()45686d7f5d3SJohn Marino exiterr()
45786d7f5d3SJohn Marino {
45886d7f5d3SJohn Marino     tempunlink();
45986d7f5d3SJohn Marino     _exit(DIFF_TROUBLE);
46086d7f5d3SJohn Marino }
46186d7f5d3SJohn Marino 
46286d7f5d3SJohn Marino #if DIFF_L
46386d7f5d3SJohn Marino 	static char const *
setup_label(b,num,date)46486d7f5d3SJohn Marino setup_label(b, num, date)
46586d7f5d3SJohn Marino 	struct buf *b;
46686d7f5d3SJohn Marino 	char const *num;
46786d7f5d3SJohn Marino 	char const date[datesize];
46886d7f5d3SJohn Marino {
46986d7f5d3SJohn Marino 	char *p;
47086d7f5d3SJohn Marino 	char datestr[datesize + zonelenmax];
47186d7f5d3SJohn Marino 	VOID date2str(date, datestr);
47286d7f5d3SJohn Marino 	bufalloc(b,
47386d7f5d3SJohn Marino 		strlen(workname)
47486d7f5d3SJohn Marino 		+ sizeof datestr + 4
47586d7f5d3SJohn Marino 		+ (num ? strlen(num) : 0)
47686d7f5d3SJohn Marino 	);
47786d7f5d3SJohn Marino 	p = b->string;
47886d7f5d3SJohn Marino 	if (num)
47986d7f5d3SJohn Marino 		VOID sprintf(p, "-L%s\t%s\t%s", workname, datestr, num);
48086d7f5d3SJohn Marino 	else
48186d7f5d3SJohn Marino 		VOID sprintf(p, "-L%s\t%s", workname, datestr);
48286d7f5d3SJohn Marino 	return p;
48386d7f5d3SJohn Marino }
48486d7f5d3SJohn Marino #endif
485