xref: /plan9/sys/src/ape/cmd/diff/sdiff.c (revision 0b459c2cb92b7c9d88818e9a2f72e678e5bc4553)
1*0b459c2cSDavid du Colombier /* SDIFF -- interactive merge front end to diff
2*0b459c2cSDavid du Colombier    Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
3*0b459c2cSDavid du Colombier 
4*0b459c2cSDavid du Colombier This file is part of GNU DIFF.
5*0b459c2cSDavid du Colombier 
6*0b459c2cSDavid du Colombier GNU DIFF is free software; you can redistribute it and/or modify
7*0b459c2cSDavid du Colombier it under the terms of the GNU General Public License as published by
8*0b459c2cSDavid du Colombier the Free Software Foundation; either version 2, or (at your option)
9*0b459c2cSDavid du Colombier any later version.
10*0b459c2cSDavid du Colombier 
11*0b459c2cSDavid du Colombier GNU DIFF is distributed in the hope that it will be useful,
12*0b459c2cSDavid du Colombier but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0b459c2cSDavid du Colombier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*0b459c2cSDavid du Colombier GNU General Public License for more details.
15*0b459c2cSDavid du Colombier 
16*0b459c2cSDavid du Colombier You should have received a copy of the GNU General Public License
17*0b459c2cSDavid du Colombier along with GNU DIFF; see the file COPYING.  If not, write to
18*0b459c2cSDavid du Colombier the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19*0b459c2cSDavid du Colombier 
20*0b459c2cSDavid du Colombier /* GNU SDIFF was written by Thomas Lord. */
21*0b459c2cSDavid du Colombier 
22*0b459c2cSDavid du Colombier #include <sys/cdefs.h>
23*0b459c2cSDavid du Colombier __FBSDID("$FreeBSD: src/contrib/diff/sdiff.c,v 1.1.1.1.12.1 2002/01/28 01:26:35 nectar Exp $");
24*0b459c2cSDavid du Colombier 
25*0b459c2cSDavid du Colombier #include "system.h"
26*0b459c2cSDavid du Colombier #include <stdio.h>
27*0b459c2cSDavid du Colombier #include <signal.h>
28*0b459c2cSDavid du Colombier #include "getopt.h"
29*0b459c2cSDavid du Colombier 
30*0b459c2cSDavid du Colombier /* Size of chunks read from files which must be parsed into lines. */
31*0b459c2cSDavid du Colombier #define SDIFF_BUFSIZE ((size_t) 65536)
32*0b459c2cSDavid du Colombier 
33*0b459c2cSDavid du Colombier /* Default name of the diff program */
34*0b459c2cSDavid du Colombier #ifndef DIFF_PROGRAM
35*0b459c2cSDavid du Colombier #define DIFF_PROGRAM "/usr/bin/diff"
36*0b459c2cSDavid du Colombier #endif
37*0b459c2cSDavid du Colombier 
38*0b459c2cSDavid du Colombier /* Users' editor of nonchoice */
39*0b459c2cSDavid du Colombier #ifndef DEFAULT_EDITOR_PROGRAM
40*0b459c2cSDavid du Colombier #define DEFAULT_EDITOR_PROGRAM "ed"
41*0b459c2cSDavid du Colombier #endif
42*0b459c2cSDavid du Colombier 
43*0b459c2cSDavid du Colombier extern char version_string[];
44*0b459c2cSDavid du Colombier static char const *program_name;
45*0b459c2cSDavid du Colombier static char const *diffbin = DIFF_PROGRAM;
46*0b459c2cSDavid du Colombier static char const *edbin = DEFAULT_EDITOR_PROGRAM;
47*0b459c2cSDavid du Colombier static char const **diffargv;
48*0b459c2cSDavid du Colombier 
49*0b459c2cSDavid du Colombier static char *tmpname;
50*0b459c2cSDavid du Colombier static int volatile tmpmade;
51*0b459c2cSDavid du Colombier 
52*0b459c2cSDavid du Colombier #if HAVE_FORK
53*0b459c2cSDavid du Colombier static pid_t volatile diffpid;
54*0b459c2cSDavid du Colombier #endif
55*0b459c2cSDavid du Colombier 
56*0b459c2cSDavid du Colombier struct line_filter;
57*0b459c2cSDavid du Colombier 
58*0b459c2cSDavid du Colombier static FILE *ck_fopen PARAMS((char const *, char const *));
59*0b459c2cSDavid du Colombier static RETSIGTYPE catchsig PARAMS((int));
60*0b459c2cSDavid du Colombier static VOID *xmalloc PARAMS((size_t));
61*0b459c2cSDavid du Colombier static char const *expand_name PARAMS((char *, int, char const *));
62*0b459c2cSDavid du Colombier static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*));
63*0b459c2cSDavid du Colombier static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*));
64*0b459c2cSDavid du Colombier static int lf_snarf PARAMS((struct line_filter *, char *, size_t));
65*0b459c2cSDavid du Colombier static int skip_white PARAMS((void));
66*0b459c2cSDavid du Colombier static size_t ck_fread PARAMS((char *, size_t, FILE *));
67*0b459c2cSDavid du Colombier static size_t lf_refill PARAMS((struct line_filter *));
68*0b459c2cSDavid du Colombier static void checksigs PARAMS((void));
69*0b459c2cSDavid du Colombier static void ck_fclose PARAMS((FILE *));
70*0b459c2cSDavid du Colombier static void ck_fflush PARAMS((FILE *));
71*0b459c2cSDavid du Colombier static void ck_fwrite PARAMS((char const *, size_t, FILE *));
72*0b459c2cSDavid du Colombier static void cleanup PARAMS((void));
73*0b459c2cSDavid du Colombier static void diffarg PARAMS((char const *));
74*0b459c2cSDavid du Colombier static void execdiff PARAMS((void));
75*0b459c2cSDavid du Colombier static void exiterr PARAMS((void));
76*0b459c2cSDavid du Colombier static void fatal PARAMS((char const *));
77*0b459c2cSDavid du Colombier static void flush_line PARAMS((void));
78*0b459c2cSDavid du Colombier static void give_help PARAMS((void));
79*0b459c2cSDavid du Colombier static void lf_copy PARAMS((struct line_filter *, int, FILE *));
80*0b459c2cSDavid du Colombier static void lf_init PARAMS((struct line_filter *, FILE *));
81*0b459c2cSDavid du Colombier static void lf_skip PARAMS((struct line_filter *, int));
82*0b459c2cSDavid du Colombier static void perror_fatal PARAMS((char const *));
83*0b459c2cSDavid du Colombier static void trapsigs PARAMS((void));
84*0b459c2cSDavid du Colombier static void try_help PARAMS((char const *));
85*0b459c2cSDavid du Colombier static void untrapsig PARAMS((int));
86*0b459c2cSDavid du Colombier static void usage PARAMS((void));
87*0b459c2cSDavid du Colombier 
88*0b459c2cSDavid du Colombier static int diraccess PARAMS((char const *));
89*0b459c2cSDavid du Colombier 
90*0b459c2cSDavid du Colombier /* Options: */
91*0b459c2cSDavid du Colombier 
92*0b459c2cSDavid du Colombier /* name of output file if -o spec'd */
93*0b459c2cSDavid du Colombier static char *out_file;
94*0b459c2cSDavid du Colombier 
95*0b459c2cSDavid du Colombier /* do not print common lines if true, set by -s option */
96*0b459c2cSDavid du Colombier static int suppress_common_flag;
97*0b459c2cSDavid du Colombier 
98*0b459c2cSDavid du Colombier static struct option const longopts[] =
99*0b459c2cSDavid du Colombier {
100*0b459c2cSDavid du Colombier   {"ignore-blank-lines", 0, 0, 'B'},
101*0b459c2cSDavid du Colombier   {"speed-large-files", 0, 0, 'H'},
102*0b459c2cSDavid du Colombier   {"ignore-matching-lines", 1, 0, 'I'},
103*0b459c2cSDavid du Colombier   {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
104*0b459c2cSDavid du Colombier   {"text", 0, 0, 'a'},
105*0b459c2cSDavid du Colombier   {"ignore-space-change", 0, 0, 'b'},
106*0b459c2cSDavid du Colombier   {"minimal", 0, 0, 'd'},
107*0b459c2cSDavid du Colombier   {"ignore-case", 0, 0, 'i'},
108*0b459c2cSDavid du Colombier   {"left-column", 0, 0, 'l'},
109*0b459c2cSDavid du Colombier   {"output", 1, 0, 'o'},
110*0b459c2cSDavid du Colombier   {"suppress-common-lines", 0, 0, 's'},
111*0b459c2cSDavid du Colombier   {"expand-tabs", 0, 0, 't'},
112*0b459c2cSDavid du Colombier   {"width", 1, 0, 'w'},
113*0b459c2cSDavid du Colombier   {"version", 0, 0, 'v'},
114*0b459c2cSDavid du Colombier   {"help", 0, 0, 129},
115*0b459c2cSDavid du Colombier   {0, 0, 0, 0}
116*0b459c2cSDavid du Colombier };
117*0b459c2cSDavid du Colombier 
118*0b459c2cSDavid du Colombier static void
try_help(reason)119*0b459c2cSDavid du Colombier try_help (reason)
120*0b459c2cSDavid du Colombier      char const *reason;
121*0b459c2cSDavid du Colombier {
122*0b459c2cSDavid du Colombier   if (reason)
123*0b459c2cSDavid du Colombier     fprintf (stderr, "%s: %s\n", program_name, reason);
124*0b459c2cSDavid du Colombier   fprintf (stderr, "%s: Try `%s --help' for more information.\n",
125*0b459c2cSDavid du Colombier 	   program_name, program_name);
126*0b459c2cSDavid du Colombier   exit (2);
127*0b459c2cSDavid du Colombier }
128*0b459c2cSDavid du Colombier 
129*0b459c2cSDavid du Colombier static void
usage()130*0b459c2cSDavid du Colombier usage ()
131*0b459c2cSDavid du Colombier {
132*0b459c2cSDavid du Colombier   printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name);
133*0b459c2cSDavid du Colombier   printf ("%s", "\
134*0b459c2cSDavid du Colombier   -o FILE  --output=FILE  Operate interactively, sending output to FILE.\n\n");
135*0b459c2cSDavid du Colombier   printf ("%s", "\
136*0b459c2cSDavid du Colombier   -i  --ignore-case  Consider upper- and lower-case to be the same.\n\
137*0b459c2cSDavid du Colombier   -W  --ignore-all-space  Ignore all white space.\n\
138*0b459c2cSDavid du Colombier   -b  --ignore-space-change  Ignore changes in the amount of white space.\n\
139*0b459c2cSDavid du Colombier   -B  --ignore-blank-lines  Ignore changes whose lines are all blank.\n\
140*0b459c2cSDavid du Colombier   -I RE  --ignore-matching-lines=RE  Ignore changes whose lines all match RE.\n\
141*0b459c2cSDavid du Colombier   -a  --text  Treat all files as text.\n\n");
142*0b459c2cSDavid du Colombier   printf ("%s", "\
143*0b459c2cSDavid du Colombier   -w NUM  --width=NUM  Output at most NUM (default 130) characters per line.\n\
144*0b459c2cSDavid du Colombier   -l  --left-column  Output only the left column of common lines.\n\
145*0b459c2cSDavid du Colombier   -s  --suppress-common-lines  Do not output common lines.\n\n");
146*0b459c2cSDavid du Colombier   printf ("\
147*0b459c2cSDavid du Colombier   -t  --expand-tabs  Expand tabs to spaces in output.\n\n");
148*0b459c2cSDavid du Colombier   printf ("%s", "\
149*0b459c2cSDavid du Colombier   -d  --minimal  Try hard to find a smaller set of changes.\n\
150*0b459c2cSDavid du Colombier   -H  --speed-large-files  Assume large files and many scattered small changes.\n\n");
151*0b459c2cSDavid du Colombier  printf ("%s", "\
152*0b459c2cSDavid du Colombier   -v  --version  Output version info.\n\
153*0b459c2cSDavid du Colombier   --help  Output this help.\n\n\
154*0b459c2cSDavid du Colombier If FILE1 or FILE2 is `-', read standard input.\n");
155*0b459c2cSDavid du Colombier }
156*0b459c2cSDavid du Colombier 
157*0b459c2cSDavid du Colombier static void
cleanup()158*0b459c2cSDavid du Colombier cleanup ()
159*0b459c2cSDavid du Colombier {
160*0b459c2cSDavid du Colombier #if HAVE_FORK
161*0b459c2cSDavid du Colombier   if (0 < diffpid)
162*0b459c2cSDavid du Colombier     kill (diffpid, SIGPIPE);
163*0b459c2cSDavid du Colombier #endif
164*0b459c2cSDavid du Colombier   if (tmpmade)
165*0b459c2cSDavid du Colombier     unlink (tmpname);
166*0b459c2cSDavid du Colombier }
167*0b459c2cSDavid du Colombier 
168*0b459c2cSDavid du Colombier static void
exiterr()169*0b459c2cSDavid du Colombier exiterr ()
170*0b459c2cSDavid du Colombier {
171*0b459c2cSDavid du Colombier   cleanup ();
172*0b459c2cSDavid du Colombier   untrapsig (0);
173*0b459c2cSDavid du Colombier   checksigs ();
174*0b459c2cSDavid du Colombier   exit (2);
175*0b459c2cSDavid du Colombier }
176*0b459c2cSDavid du Colombier 
177*0b459c2cSDavid du Colombier static void
fatal(msg)178*0b459c2cSDavid du Colombier fatal (msg)
179*0b459c2cSDavid du Colombier      char const *msg;
180*0b459c2cSDavid du Colombier {
181*0b459c2cSDavid du Colombier   fprintf (stderr, "%s: %s\n", program_name, msg);
182*0b459c2cSDavid du Colombier   exiterr ();
183*0b459c2cSDavid du Colombier }
184*0b459c2cSDavid du Colombier 
185*0b459c2cSDavid du Colombier static void
perror_fatal(msg)186*0b459c2cSDavid du Colombier perror_fatal (msg)
187*0b459c2cSDavid du Colombier      char const *msg;
188*0b459c2cSDavid du Colombier {
189*0b459c2cSDavid du Colombier   int e = errno;
190*0b459c2cSDavid du Colombier   checksigs ();
191*0b459c2cSDavid du Colombier   fprintf (stderr, "%s: ", program_name);
192*0b459c2cSDavid du Colombier   errno = e;
193*0b459c2cSDavid du Colombier   perror (msg);
194*0b459c2cSDavid du Colombier   exiterr ();
195*0b459c2cSDavid du Colombier }
196*0b459c2cSDavid du Colombier 
197*0b459c2cSDavid du Colombier 
198*0b459c2cSDavid du Colombier /* malloc freely or DIE! */
199*0b459c2cSDavid du Colombier static VOID *
xmalloc(size)200*0b459c2cSDavid du Colombier xmalloc (size)
201*0b459c2cSDavid du Colombier      size_t size;
202*0b459c2cSDavid du Colombier {
203*0b459c2cSDavid du Colombier   VOID *r = (VOID *) malloc (size);
204*0b459c2cSDavid du Colombier   if (!r)
205*0b459c2cSDavid du Colombier     fatal ("memory exhausted");
206*0b459c2cSDavid du Colombier   return r;
207*0b459c2cSDavid du Colombier }
208*0b459c2cSDavid du Colombier 
209*0b459c2cSDavid du Colombier static FILE *
ck_fopen(fname,type)210*0b459c2cSDavid du Colombier ck_fopen (fname, type)
211*0b459c2cSDavid du Colombier      char const *fname, *type;
212*0b459c2cSDavid du Colombier {
213*0b459c2cSDavid du Colombier   FILE *r = fopen (fname, type);
214*0b459c2cSDavid du Colombier   if (!r)
215*0b459c2cSDavid du Colombier     perror_fatal (fname);
216*0b459c2cSDavid du Colombier   return r;
217*0b459c2cSDavid du Colombier }
218*0b459c2cSDavid du Colombier 
219*0b459c2cSDavid du Colombier static void
ck_fclose(f)220*0b459c2cSDavid du Colombier ck_fclose (f)
221*0b459c2cSDavid du Colombier      FILE *f;
222*0b459c2cSDavid du Colombier {
223*0b459c2cSDavid du Colombier   if (fclose (f))
224*0b459c2cSDavid du Colombier     perror_fatal ("input/output error");
225*0b459c2cSDavid du Colombier }
226*0b459c2cSDavid du Colombier 
227*0b459c2cSDavid du Colombier static size_t
ck_fread(buf,size,f)228*0b459c2cSDavid du Colombier ck_fread (buf, size, f)
229*0b459c2cSDavid du Colombier      char *buf;
230*0b459c2cSDavid du Colombier      size_t size;
231*0b459c2cSDavid du Colombier      FILE *f;
232*0b459c2cSDavid du Colombier {
233*0b459c2cSDavid du Colombier   size_t r = fread (buf, sizeof (char), size, f);
234*0b459c2cSDavid du Colombier   if (r == 0 && ferror (f))
235*0b459c2cSDavid du Colombier     perror_fatal ("input error");
236*0b459c2cSDavid du Colombier   return r;
237*0b459c2cSDavid du Colombier }
238*0b459c2cSDavid du Colombier 
239*0b459c2cSDavid du Colombier static void
ck_fwrite(buf,size,f)240*0b459c2cSDavid du Colombier ck_fwrite (buf, size, f)
241*0b459c2cSDavid du Colombier      char const *buf;
242*0b459c2cSDavid du Colombier      size_t size;
243*0b459c2cSDavid du Colombier      FILE *f;
244*0b459c2cSDavid du Colombier {
245*0b459c2cSDavid du Colombier   if (fwrite (buf, sizeof (char), size, f) != size)
246*0b459c2cSDavid du Colombier     perror_fatal ("output error");
247*0b459c2cSDavid du Colombier }
248*0b459c2cSDavid du Colombier 
249*0b459c2cSDavid du Colombier static void
ck_fflush(f)250*0b459c2cSDavid du Colombier ck_fflush (f)
251*0b459c2cSDavid du Colombier      FILE *f;
252*0b459c2cSDavid du Colombier {
253*0b459c2cSDavid du Colombier   if (fflush (f) != 0)
254*0b459c2cSDavid du Colombier     perror_fatal ("output error");
255*0b459c2cSDavid du Colombier }
256*0b459c2cSDavid du Colombier 
257*0b459c2cSDavid du Colombier static char const *
expand_name(name,is_dir,other_name)258*0b459c2cSDavid du Colombier expand_name (name, is_dir, other_name)
259*0b459c2cSDavid du Colombier      char *name;
260*0b459c2cSDavid du Colombier      int is_dir;
261*0b459c2cSDavid du Colombier      char const *other_name;
262*0b459c2cSDavid du Colombier {
263*0b459c2cSDavid du Colombier   if (strcmp (name, "-") == 0)
264*0b459c2cSDavid du Colombier     fatal ("cannot interactively merge standard input");
265*0b459c2cSDavid du Colombier   if (!is_dir)
266*0b459c2cSDavid du Colombier     return name;
267*0b459c2cSDavid du Colombier   else
268*0b459c2cSDavid du Colombier     {
269*0b459c2cSDavid du Colombier       /* Yield NAME/BASE, where BASE is OTHER_NAME's basename.  */
270*0b459c2cSDavid du Colombier       char const *p = filename_lastdirchar (other_name);
271*0b459c2cSDavid du Colombier       char const *base = p ? p+1 : other_name;
272*0b459c2cSDavid du Colombier       size_t namelen = strlen (name), baselen = strlen (base);
273*0b459c2cSDavid du Colombier       char *r = xmalloc (namelen + baselen + 2);
274*0b459c2cSDavid du Colombier       memcpy (r, name, namelen);
275*0b459c2cSDavid du Colombier       r[namelen] = '/';
276*0b459c2cSDavid du Colombier       memcpy (r + namelen + 1, base, baselen + 1);
277*0b459c2cSDavid du Colombier       return r;
278*0b459c2cSDavid du Colombier     }
279*0b459c2cSDavid du Colombier }
280*0b459c2cSDavid du Colombier 
281*0b459c2cSDavid du Colombier 
282*0b459c2cSDavid du Colombier 
283*0b459c2cSDavid du Colombier struct line_filter {
284*0b459c2cSDavid du Colombier   FILE *infile;
285*0b459c2cSDavid du Colombier   char *bufpos;
286*0b459c2cSDavid du Colombier   char *buffer;
287*0b459c2cSDavid du Colombier   char *buflim;
288*0b459c2cSDavid du Colombier };
289*0b459c2cSDavid du Colombier 
290*0b459c2cSDavid du Colombier static void
lf_init(lf,infile)291*0b459c2cSDavid du Colombier lf_init (lf, infile)
292*0b459c2cSDavid du Colombier      struct line_filter *lf;
293*0b459c2cSDavid du Colombier      FILE *infile;
294*0b459c2cSDavid du Colombier {
295*0b459c2cSDavid du Colombier   lf->infile = infile;
296*0b459c2cSDavid du Colombier   lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);
297*0b459c2cSDavid du Colombier   lf->buflim[0] = '\n';
298*0b459c2cSDavid du Colombier }
299*0b459c2cSDavid du Colombier 
300*0b459c2cSDavid du Colombier /* Fill an exhausted line_filter buffer from its INFILE */
301*0b459c2cSDavid du Colombier static size_t
lf_refill(lf)302*0b459c2cSDavid du Colombier lf_refill (lf)
303*0b459c2cSDavid du Colombier      struct line_filter *lf;
304*0b459c2cSDavid du Colombier {
305*0b459c2cSDavid du Colombier   size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
306*0b459c2cSDavid du Colombier   lf->bufpos = lf->buffer;
307*0b459c2cSDavid du Colombier   lf->buflim = lf->buffer + s;
308*0b459c2cSDavid du Colombier   lf->buflim[0] = '\n';
309*0b459c2cSDavid du Colombier   checksigs ();
310*0b459c2cSDavid du Colombier   return s;
311*0b459c2cSDavid du Colombier }
312*0b459c2cSDavid du Colombier 
313*0b459c2cSDavid du Colombier /* Advance LINES on LF's infile, copying lines to OUTFILE */
314*0b459c2cSDavid du Colombier static void
lf_copy(lf,lines,outfile)315*0b459c2cSDavid du Colombier lf_copy (lf, lines, outfile)
316*0b459c2cSDavid du Colombier      struct line_filter *lf;
317*0b459c2cSDavid du Colombier      int lines;
318*0b459c2cSDavid du Colombier      FILE *outfile;
319*0b459c2cSDavid du Colombier {
320*0b459c2cSDavid du Colombier   char *start = lf->bufpos;
321*0b459c2cSDavid du Colombier 
322*0b459c2cSDavid du Colombier   while (lines)
323*0b459c2cSDavid du Colombier     {
324*0b459c2cSDavid du Colombier       lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
325*0b459c2cSDavid du Colombier       if (! lf->bufpos)
326*0b459c2cSDavid du Colombier 	{
327*0b459c2cSDavid du Colombier 	  ck_fwrite (start, lf->buflim - start, outfile);
328*0b459c2cSDavid du Colombier 	  if (! lf_refill (lf))
329*0b459c2cSDavid du Colombier 	    return;
330*0b459c2cSDavid du Colombier 	  start = lf->bufpos;
331*0b459c2cSDavid du Colombier 	}
332*0b459c2cSDavid du Colombier       else
333*0b459c2cSDavid du Colombier 	{
334*0b459c2cSDavid du Colombier 	  --lines;
335*0b459c2cSDavid du Colombier 	  ++lf->bufpos;
336*0b459c2cSDavid du Colombier 	}
337*0b459c2cSDavid du Colombier     }
338*0b459c2cSDavid du Colombier 
339*0b459c2cSDavid du Colombier   ck_fwrite (start, lf->bufpos - start, outfile);
340*0b459c2cSDavid du Colombier }
341*0b459c2cSDavid du Colombier 
342*0b459c2cSDavid du Colombier /* Advance LINES on LF's infile without doing output */
343*0b459c2cSDavid du Colombier static void
lf_skip(lf,lines)344*0b459c2cSDavid du Colombier lf_skip (lf, lines)
345*0b459c2cSDavid du Colombier      struct line_filter *lf;
346*0b459c2cSDavid du Colombier      int lines;
347*0b459c2cSDavid du Colombier {
348*0b459c2cSDavid du Colombier   while (lines)
349*0b459c2cSDavid du Colombier     {
350*0b459c2cSDavid du Colombier       lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
351*0b459c2cSDavid du Colombier       if (! lf->bufpos)
352*0b459c2cSDavid du Colombier 	{
353*0b459c2cSDavid du Colombier 	  if (! lf_refill (lf))
354*0b459c2cSDavid du Colombier 	    break;
355*0b459c2cSDavid du Colombier 	}
356*0b459c2cSDavid du Colombier       else
357*0b459c2cSDavid du Colombier 	{
358*0b459c2cSDavid du Colombier 	  --lines;
359*0b459c2cSDavid du Colombier 	  ++lf->bufpos;
360*0b459c2cSDavid du Colombier 	}
361*0b459c2cSDavid du Colombier     }
362*0b459c2cSDavid du Colombier }
363*0b459c2cSDavid du Colombier 
364*0b459c2cSDavid du Colombier /* Snarf a line into a buffer.  Return EOF if EOF, 0 if error, 1 if OK.  */
365*0b459c2cSDavid du Colombier static int
lf_snarf(lf,buffer,bufsize)366*0b459c2cSDavid du Colombier lf_snarf (lf, buffer, bufsize)
367*0b459c2cSDavid du Colombier      struct line_filter *lf;
368*0b459c2cSDavid du Colombier      char *buffer;
369*0b459c2cSDavid du Colombier      size_t bufsize;
370*0b459c2cSDavid du Colombier {
371*0b459c2cSDavid du Colombier   char *start = lf->bufpos;
372*0b459c2cSDavid du Colombier 
373*0b459c2cSDavid du Colombier   for (;;)
374*0b459c2cSDavid du Colombier     {
375*0b459c2cSDavid du Colombier       char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);
376*0b459c2cSDavid du Colombier       size_t s = next - start;
377*0b459c2cSDavid du Colombier       if (bufsize <= s)
378*0b459c2cSDavid du Colombier 	return 0;
379*0b459c2cSDavid du Colombier       memcpy (buffer, start, s);
380*0b459c2cSDavid du Colombier       if (next < lf->buflim)
381*0b459c2cSDavid du Colombier 	{
382*0b459c2cSDavid du Colombier 	  buffer[s] = 0;
383*0b459c2cSDavid du Colombier 	  lf->bufpos = next + 1;
384*0b459c2cSDavid du Colombier 	  return 1;
385*0b459c2cSDavid du Colombier 	}
386*0b459c2cSDavid du Colombier       if (! lf_refill (lf))
387*0b459c2cSDavid du Colombier 	return s ? 0 : EOF;
388*0b459c2cSDavid du Colombier       buffer += s;
389*0b459c2cSDavid du Colombier       bufsize -= s;
390*0b459c2cSDavid du Colombier       start = next;
391*0b459c2cSDavid du Colombier     }
392*0b459c2cSDavid du Colombier }
393*0b459c2cSDavid du Colombier 
394*0b459c2cSDavid du Colombier 
395*0b459c2cSDavid du Colombier 
396*0b459c2cSDavid du Colombier int
main(argc,argv)397*0b459c2cSDavid du Colombier main (argc, argv)
398*0b459c2cSDavid du Colombier      int argc;
399*0b459c2cSDavid du Colombier      char *argv[];
400*0b459c2cSDavid du Colombier {
401*0b459c2cSDavid du Colombier   int opt;
402*0b459c2cSDavid du Colombier   char *editor;
403*0b459c2cSDavid du Colombier   char *differ;
404*0b459c2cSDavid du Colombier 
405*0b459c2cSDavid du Colombier   initialize_main (&argc, &argv);
406*0b459c2cSDavid du Colombier   program_name = argv[0];
407*0b459c2cSDavid du Colombier 
408*0b459c2cSDavid du Colombier   editor = getenv ("EDITOR");
409*0b459c2cSDavid du Colombier   if (editor)
410*0b459c2cSDavid du Colombier     edbin = editor;
411*0b459c2cSDavid du Colombier   differ = getenv ("DIFF");
412*0b459c2cSDavid du Colombier   if (differ)
413*0b459c2cSDavid du Colombier     diffbin = differ;
414*0b459c2cSDavid du Colombier 
415*0b459c2cSDavid du Colombier   diffarg ("diff");
416*0b459c2cSDavid du Colombier 
417*0b459c2cSDavid du Colombier   /* parse command line args */
418*0b459c2cSDavid du Colombier   while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))
419*0b459c2cSDavid du Colombier 	 != EOF)
420*0b459c2cSDavid du Colombier     {
421*0b459c2cSDavid du Colombier       switch (opt)
422*0b459c2cSDavid du Colombier 	{
423*0b459c2cSDavid du Colombier 	case 'a':
424*0b459c2cSDavid du Colombier 	  diffarg ("-a");
425*0b459c2cSDavid du Colombier 	  break;
426*0b459c2cSDavid du Colombier 
427*0b459c2cSDavid du Colombier 	case 'b':
428*0b459c2cSDavid du Colombier 	  diffarg ("-b");
429*0b459c2cSDavid du Colombier 	  break;
430*0b459c2cSDavid du Colombier 
431*0b459c2cSDavid du Colombier 	case 'B':
432*0b459c2cSDavid du Colombier 	  diffarg ("-B");
433*0b459c2cSDavid du Colombier 	  break;
434*0b459c2cSDavid du Colombier 
435*0b459c2cSDavid du Colombier 	case 'd':
436*0b459c2cSDavid du Colombier 	  diffarg ("-d");
437*0b459c2cSDavid du Colombier 	  break;
438*0b459c2cSDavid du Colombier 
439*0b459c2cSDavid du Colombier 	case 'H':
440*0b459c2cSDavid du Colombier 	  diffarg ("-H");
441*0b459c2cSDavid du Colombier 	  break;
442*0b459c2cSDavid du Colombier 
443*0b459c2cSDavid du Colombier 	case 'i':
444*0b459c2cSDavid du Colombier 	  diffarg ("-i");
445*0b459c2cSDavid du Colombier 	  break;
446*0b459c2cSDavid du Colombier 
447*0b459c2cSDavid du Colombier 	case 'I':
448*0b459c2cSDavid du Colombier 	  diffarg ("-I");
449*0b459c2cSDavid du Colombier 	  diffarg (optarg);
450*0b459c2cSDavid du Colombier 	  break;
451*0b459c2cSDavid du Colombier 
452*0b459c2cSDavid du Colombier 	case 'l':
453*0b459c2cSDavid du Colombier 	  diffarg ("--left-column");
454*0b459c2cSDavid du Colombier 	  break;
455*0b459c2cSDavid du Colombier 
456*0b459c2cSDavid du Colombier 	case 'o':
457*0b459c2cSDavid du Colombier 	  out_file = optarg;
458*0b459c2cSDavid du Colombier 	  break;
459*0b459c2cSDavid du Colombier 
460*0b459c2cSDavid du Colombier 	case 's':
461*0b459c2cSDavid du Colombier 	  suppress_common_flag = 1;
462*0b459c2cSDavid du Colombier 	  break;
463*0b459c2cSDavid du Colombier 
464*0b459c2cSDavid du Colombier 	case 't':
465*0b459c2cSDavid du Colombier 	  diffarg ("-t");
466*0b459c2cSDavid du Colombier 	  break;
467*0b459c2cSDavid du Colombier 
468*0b459c2cSDavid du Colombier 	case 'v':
469*0b459c2cSDavid du Colombier 	  printf ("sdiff - GNU diffutils version %s\n", version_string);
470*0b459c2cSDavid du Colombier 	  exit (0);
471*0b459c2cSDavid du Colombier 
472*0b459c2cSDavid du Colombier 	case 'w':
473*0b459c2cSDavid du Colombier 	  diffarg ("-W");
474*0b459c2cSDavid du Colombier 	  diffarg (optarg);
475*0b459c2cSDavid du Colombier 	  break;
476*0b459c2cSDavid du Colombier 
477*0b459c2cSDavid du Colombier 	case 'W':
478*0b459c2cSDavid du Colombier 	  diffarg ("-w");
479*0b459c2cSDavid du Colombier 	  break;
480*0b459c2cSDavid du Colombier 
481*0b459c2cSDavid du Colombier 	case 129:
482*0b459c2cSDavid du Colombier 	  usage ();
483*0b459c2cSDavid du Colombier 	  if (ferror (stdout) || fclose (stdout) != 0)
484*0b459c2cSDavid du Colombier 	    fatal ("write error");
485*0b459c2cSDavid du Colombier 	  exit (0);
486*0b459c2cSDavid du Colombier 
487*0b459c2cSDavid du Colombier 	default:
488*0b459c2cSDavid du Colombier 	  try_help (0);
489*0b459c2cSDavid du Colombier 	}
490*0b459c2cSDavid du Colombier     }
491*0b459c2cSDavid du Colombier 
492*0b459c2cSDavid du Colombier   if (argc - optind != 2)
493*0b459c2cSDavid du Colombier     try_help (argc - optind < 2 ? "missing operand" : "extra operand");
494*0b459c2cSDavid du Colombier 
495*0b459c2cSDavid du Colombier   if (! out_file)
496*0b459c2cSDavid du Colombier     {
497*0b459c2cSDavid du Colombier       /* easy case: diff does everything for us */
498*0b459c2cSDavid du Colombier       if (suppress_common_flag)
499*0b459c2cSDavid du Colombier 	diffarg ("--suppress-common-lines");
500*0b459c2cSDavid du Colombier       diffarg ("-y");
501*0b459c2cSDavid du Colombier       diffarg ("--");
502*0b459c2cSDavid du Colombier       diffarg (argv[optind]);
503*0b459c2cSDavid du Colombier       diffarg (argv[optind + 1]);
504*0b459c2cSDavid du Colombier       diffarg (0);
505*0b459c2cSDavid du Colombier       execdiff ();
506*0b459c2cSDavid du Colombier     }
507*0b459c2cSDavid du Colombier   else
508*0b459c2cSDavid du Colombier     {
509*0b459c2cSDavid du Colombier       FILE *left, *right, *out, *diffout;
510*0b459c2cSDavid du Colombier       int interact_ok;
511*0b459c2cSDavid du Colombier       struct line_filter lfilt;
512*0b459c2cSDavid du Colombier       struct line_filter rfilt;
513*0b459c2cSDavid du Colombier       struct line_filter diff_filt;
514*0b459c2cSDavid du Colombier       int leftdir = diraccess (argv[optind]);
515*0b459c2cSDavid du Colombier       int rightdir = diraccess (argv[optind + 1]);
516*0b459c2cSDavid du Colombier 
517*0b459c2cSDavid du Colombier       if (leftdir && rightdir)
518*0b459c2cSDavid du Colombier 	fatal ("both files to be compared are directories");
519*0b459c2cSDavid du Colombier 
520*0b459c2cSDavid du Colombier       left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r");
521*0b459c2cSDavid du Colombier       ;
522*0b459c2cSDavid du Colombier       right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r");
523*0b459c2cSDavid du Colombier       out = ck_fopen (out_file, "w");
524*0b459c2cSDavid du Colombier 
525*0b459c2cSDavid du Colombier       diffarg ("--sdiff-merge-assist");
526*0b459c2cSDavid du Colombier       diffarg ("--");
527*0b459c2cSDavid du Colombier       diffarg (argv[optind]);
528*0b459c2cSDavid du Colombier       diffarg (argv[optind + 1]);
529*0b459c2cSDavid du Colombier       diffarg (0);
530*0b459c2cSDavid du Colombier 
531*0b459c2cSDavid du Colombier       trapsigs ();
532*0b459c2cSDavid du Colombier 
533*0b459c2cSDavid du Colombier #if ! HAVE_FORK
534*0b459c2cSDavid du Colombier       {
535*0b459c2cSDavid du Colombier 	size_t cmdsize = 1;
536*0b459c2cSDavid du Colombier 	char *p, *command;
537*0b459c2cSDavid du Colombier 	int i;
538*0b459c2cSDavid du Colombier 
539*0b459c2cSDavid du Colombier 	for (i = 0;  diffargv[i];  i++)
540*0b459c2cSDavid du Colombier 	  cmdsize += 4 * strlen (diffargv[i]) + 3;
541*0b459c2cSDavid du Colombier 	command = p = xmalloc (cmdsize);
542*0b459c2cSDavid du Colombier 	for (i = 0;  diffargv[i];  i++)
543*0b459c2cSDavid du Colombier 	  {
544*0b459c2cSDavid du Colombier 	    char const *a = diffargv[i];
545*0b459c2cSDavid du Colombier 	    SYSTEM_QUOTE_ARG (p, a);
546*0b459c2cSDavid du Colombier 	    *p++ = ' ';
547*0b459c2cSDavid du Colombier 	  }
548*0b459c2cSDavid du Colombier 	p[-1] = '\0';
549*0b459c2cSDavid du Colombier 	diffout = popen (command, "r");
550*0b459c2cSDavid du Colombier 	if (!diffout)
551*0b459c2cSDavid du Colombier 	  perror_fatal (command);
552*0b459c2cSDavid du Colombier 	free (command);
553*0b459c2cSDavid du Colombier       }
554*0b459c2cSDavid du Colombier #else /* HAVE_FORK */
555*0b459c2cSDavid du Colombier       {
556*0b459c2cSDavid du Colombier 	int diff_fds[2];
557*0b459c2cSDavid du Colombier 
558*0b459c2cSDavid du Colombier 	if (pipe (diff_fds) != 0)
559*0b459c2cSDavid du Colombier 	  perror_fatal ("pipe");
560*0b459c2cSDavid du Colombier 
561*0b459c2cSDavid du Colombier 	diffpid = fork ();
562*0b459c2cSDavid du Colombier 	if (diffpid < 0)
563*0b459c2cSDavid du Colombier 	  perror_fatal ("fork failed");
564*0b459c2cSDavid du Colombier 	if (!diffpid)
565*0b459c2cSDavid du Colombier 	  {
566*0b459c2cSDavid du Colombier 	    signal (SIGINT, SIG_IGN);  /* in case user interrupts editor */
567*0b459c2cSDavid du Colombier 	    signal (SIGPIPE, SIG_DFL);
568*0b459c2cSDavid du Colombier 
569*0b459c2cSDavid du Colombier 	    close (diff_fds[0]);
570*0b459c2cSDavid du Colombier 	    if (diff_fds[1] != STDOUT_FILENO)
571*0b459c2cSDavid du Colombier 	      {
572*0b459c2cSDavid du Colombier 		dup2 (diff_fds[1], STDOUT_FILENO);
573*0b459c2cSDavid du Colombier 		close (diff_fds[1]);
574*0b459c2cSDavid du Colombier 	      }
575*0b459c2cSDavid du Colombier 
576*0b459c2cSDavid du Colombier 	    execdiff ();
577*0b459c2cSDavid du Colombier 	  }
578*0b459c2cSDavid du Colombier 
579*0b459c2cSDavid du Colombier 	close (diff_fds[1]);
580*0b459c2cSDavid du Colombier 	diffout = fdopen (diff_fds[0], "r");
581*0b459c2cSDavid du Colombier 	if (!diffout)
582*0b459c2cSDavid du Colombier 	  perror_fatal ("fdopen");
583*0b459c2cSDavid du Colombier       }
584*0b459c2cSDavid du Colombier #endif /* HAVE_FORK */
585*0b459c2cSDavid du Colombier 
586*0b459c2cSDavid du Colombier       lf_init (&diff_filt, diffout);
587*0b459c2cSDavid du Colombier       lf_init (&lfilt, left);
588*0b459c2cSDavid du Colombier       lf_init (&rfilt, right);
589*0b459c2cSDavid du Colombier 
590*0b459c2cSDavid du Colombier       interact_ok = interact (&diff_filt, &lfilt, &rfilt, out);
591*0b459c2cSDavid du Colombier 
592*0b459c2cSDavid du Colombier       ck_fclose (left);
593*0b459c2cSDavid du Colombier       ck_fclose (right);
594*0b459c2cSDavid du Colombier       ck_fclose (out);
595*0b459c2cSDavid du Colombier 
596*0b459c2cSDavid du Colombier       {
597*0b459c2cSDavid du Colombier 	int wstatus;
598*0b459c2cSDavid du Colombier 
599*0b459c2cSDavid du Colombier #if ! HAVE_FORK
600*0b459c2cSDavid du Colombier 	wstatus = pclose (diffout);
601*0b459c2cSDavid du Colombier #else
602*0b459c2cSDavid du Colombier 	ck_fclose (diffout);
603*0b459c2cSDavid du Colombier 	while (waitpid (diffpid, &wstatus, 0) < 0)
604*0b459c2cSDavid du Colombier 	  if (errno == EINTR)
605*0b459c2cSDavid du Colombier 	    checksigs ();
606*0b459c2cSDavid du Colombier 	  else
607*0b459c2cSDavid du Colombier 	    perror_fatal ("wait failed");
608*0b459c2cSDavid du Colombier 	diffpid = 0;
609*0b459c2cSDavid du Colombier #endif
610*0b459c2cSDavid du Colombier 
611*0b459c2cSDavid du Colombier 	if (tmpmade)
612*0b459c2cSDavid du Colombier 	  {
613*0b459c2cSDavid du Colombier 	    unlink (tmpname);
614*0b459c2cSDavid du Colombier 	    tmpmade = 0;
615*0b459c2cSDavid du Colombier 	  }
616*0b459c2cSDavid du Colombier 
617*0b459c2cSDavid du Colombier 	if (! interact_ok)
618*0b459c2cSDavid du Colombier 	  exiterr ();
619*0b459c2cSDavid du Colombier 
620*0b459c2cSDavid du Colombier 	if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
621*0b459c2cSDavid du Colombier 	  fatal ("Subsidiary diff failed");
622*0b459c2cSDavid du Colombier 
623*0b459c2cSDavid du Colombier 	untrapsig (0);
624*0b459c2cSDavid du Colombier 	checksigs ();
625*0b459c2cSDavid du Colombier 	exit (WEXITSTATUS (wstatus));
626*0b459c2cSDavid du Colombier       }
627*0b459c2cSDavid du Colombier     }
628*0b459c2cSDavid du Colombier   return 0;			/* Fool -Wall . . . */
629*0b459c2cSDavid du Colombier }
630*0b459c2cSDavid du Colombier 
631*0b459c2cSDavid du Colombier static void
diffarg(a)632*0b459c2cSDavid du Colombier diffarg (a)
633*0b459c2cSDavid du Colombier      char const *a;
634*0b459c2cSDavid du Colombier {
635*0b459c2cSDavid du Colombier   static unsigned diffargs, diffargsmax;
636*0b459c2cSDavid du Colombier 
637*0b459c2cSDavid du Colombier   if (diffargs == diffargsmax)
638*0b459c2cSDavid du Colombier     {
639*0b459c2cSDavid du Colombier       if (! diffargsmax)
640*0b459c2cSDavid du Colombier 	{
641*0b459c2cSDavid du Colombier 	  diffargv = (char const **) xmalloc (sizeof (char));
642*0b459c2cSDavid du Colombier 	  diffargsmax = 8;
643*0b459c2cSDavid du Colombier 	}
644*0b459c2cSDavid du Colombier       diffargsmax *= 2;
645*0b459c2cSDavid du Colombier       diffargv = (char const **) realloc (diffargv,
646*0b459c2cSDavid du Colombier 					  diffargsmax * sizeof (char const *));
647*0b459c2cSDavid du Colombier       if (! diffargv)
648*0b459c2cSDavid du Colombier 	fatal ("out of memory");
649*0b459c2cSDavid du Colombier     }
650*0b459c2cSDavid du Colombier   diffargv[diffargs++] = a;
651*0b459c2cSDavid du Colombier }
652*0b459c2cSDavid du Colombier 
653*0b459c2cSDavid du Colombier static void
execdiff()654*0b459c2cSDavid du Colombier execdiff ()
655*0b459c2cSDavid du Colombier {
656*0b459c2cSDavid du Colombier   execvp (diffbin, (char **) diffargv);
657*0b459c2cSDavid du Colombier   write (STDERR_FILENO, diffbin, strlen (diffbin));
658*0b459c2cSDavid du Colombier   write (STDERR_FILENO, ": not found\n", 12);
659*0b459c2cSDavid du Colombier   _exit (2);
660*0b459c2cSDavid du Colombier }
661*0b459c2cSDavid du Colombier 
662*0b459c2cSDavid du Colombier 
663*0b459c2cSDavid du Colombier 
664*0b459c2cSDavid du Colombier 
665*0b459c2cSDavid du Colombier /* Signal handling */
666*0b459c2cSDavid du Colombier 
667*0b459c2cSDavid du Colombier #define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
668*0b459c2cSDavid du Colombier static int const sigs[] = {
669*0b459c2cSDavid du Colombier #ifdef SIGHUP
670*0b459c2cSDavid du Colombier        SIGHUP,
671*0b459c2cSDavid du Colombier #endif
672*0b459c2cSDavid du Colombier #ifdef SIGQUIT
673*0b459c2cSDavid du Colombier        SIGQUIT,
674*0b459c2cSDavid du Colombier #endif
675*0b459c2cSDavid du Colombier #ifdef SIGTERM
676*0b459c2cSDavid du Colombier        SIGTERM,
677*0b459c2cSDavid du Colombier #endif
678*0b459c2cSDavid du Colombier #ifdef SIGXCPU
679*0b459c2cSDavid du Colombier        SIGXCPU,
680*0b459c2cSDavid du Colombier #endif
681*0b459c2cSDavid du Colombier #ifdef SIGXFSZ
682*0b459c2cSDavid du Colombier        SIGXFSZ,
683*0b459c2cSDavid du Colombier #endif
684*0b459c2cSDavid du Colombier        SIGINT,
685*0b459c2cSDavid du Colombier        SIGPIPE
686*0b459c2cSDavid du Colombier };
687*0b459c2cSDavid du Colombier 
688*0b459c2cSDavid du Colombier /* Prefer `sigaction' if it is available, since `signal' can lose signals.  */
689*0b459c2cSDavid du Colombier #if HAVE_SIGACTION
690*0b459c2cSDavid du Colombier static struct sigaction initial_action[NUM_SIGS];
691*0b459c2cSDavid du Colombier #define initial_handler(i) (initial_action[i].sa_handler)
692*0b459c2cSDavid du Colombier #else
693*0b459c2cSDavid du Colombier static RETSIGTYPE (*initial_action[NUM_SIGS]) ();
694*0b459c2cSDavid du Colombier #define initial_handler(i) (initial_action[i])
695*0b459c2cSDavid du Colombier #endif
696*0b459c2cSDavid du Colombier 
697*0b459c2cSDavid du Colombier static int volatile ignore_SIGINT;
698*0b459c2cSDavid du Colombier static int volatile signal_received;
699*0b459c2cSDavid du Colombier static int sigs_trapped;
700*0b459c2cSDavid du Colombier 
701*0b459c2cSDavid du Colombier static RETSIGTYPE
catchsig(s)702*0b459c2cSDavid du Colombier catchsig (s)
703*0b459c2cSDavid du Colombier      int s;
704*0b459c2cSDavid du Colombier {
705*0b459c2cSDavid du Colombier #if ! HAVE_SIGACTION
706*0b459c2cSDavid du Colombier   signal (s, SIG_IGN);
707*0b459c2cSDavid du Colombier #endif
708*0b459c2cSDavid du Colombier   if (! (s == SIGINT && ignore_SIGINT))
709*0b459c2cSDavid du Colombier     signal_received = s;
710*0b459c2cSDavid du Colombier }
711*0b459c2cSDavid du Colombier 
712*0b459c2cSDavid du Colombier static void
trapsigs()713*0b459c2cSDavid du Colombier trapsigs ()
714*0b459c2cSDavid du Colombier {
715*0b459c2cSDavid du Colombier   int i;
716*0b459c2cSDavid du Colombier 
717*0b459c2cSDavid du Colombier #if HAVE_SIGACTION
718*0b459c2cSDavid du Colombier   struct sigaction catchaction;
719*0b459c2cSDavid du Colombier   bzero (&catchaction, sizeof (catchaction));
720*0b459c2cSDavid du Colombier   catchaction.sa_handler = catchsig;
721*0b459c2cSDavid du Colombier #ifdef SA_INTERRUPT
722*0b459c2cSDavid du Colombier   /* Non-Posix BSD-style systems like SunOS 4.1.x need this
723*0b459c2cSDavid du Colombier      so that `read' calls are interrupted properly.  */
724*0b459c2cSDavid du Colombier   catchaction.sa_flags = SA_INTERRUPT;
725*0b459c2cSDavid du Colombier #endif
726*0b459c2cSDavid du Colombier   sigemptyset (&catchaction.sa_mask);
727*0b459c2cSDavid du Colombier   for (i = 0;  i < NUM_SIGS;  i++)
728*0b459c2cSDavid du Colombier     sigaddset (&catchaction.sa_mask, sigs[i]);
729*0b459c2cSDavid du Colombier   for (i = 0;  i < NUM_SIGS;  i++)
730*0b459c2cSDavid du Colombier     {
731*0b459c2cSDavid du Colombier       sigaction (sigs[i], 0, &initial_action[i]);
732*0b459c2cSDavid du Colombier       if (initial_handler (i) != SIG_IGN
733*0b459c2cSDavid du Colombier 	  && sigaction (sigs[i], &catchaction, 0) != 0)
734*0b459c2cSDavid du Colombier 	fatal ("signal error");
735*0b459c2cSDavid du Colombier     }
736*0b459c2cSDavid du Colombier #else /* ! HAVE_SIGACTION */
737*0b459c2cSDavid du Colombier   for (i = 0;  i < NUM_SIGS;  i++)
738*0b459c2cSDavid du Colombier     {
739*0b459c2cSDavid du Colombier       initial_action[i] = signal (sigs[i], SIG_IGN);
740*0b459c2cSDavid du Colombier       if (initial_handler (i) != SIG_IGN
741*0b459c2cSDavid du Colombier 	  && signal (sigs[i], catchsig) != SIG_IGN)
742*0b459c2cSDavid du Colombier 	fatal ("signal error");
743*0b459c2cSDavid du Colombier     }
744*0b459c2cSDavid du Colombier #endif /* ! HAVE_SIGACTION */
745*0b459c2cSDavid du Colombier 
746*0b459c2cSDavid du Colombier #if !defined(SIGCHLD) && defined(SIGCLD)
747*0b459c2cSDavid du Colombier #define SIGCHLD SIGCLD
748*0b459c2cSDavid du Colombier #endif
749*0b459c2cSDavid du Colombier #ifdef SIGCHLD
750*0b459c2cSDavid du Colombier   /* System V fork+wait does not work if SIGCHLD is ignored.  */
751*0b459c2cSDavid du Colombier   signal (SIGCHLD, SIG_DFL);
752*0b459c2cSDavid du Colombier #endif
753*0b459c2cSDavid du Colombier 
754*0b459c2cSDavid du Colombier   sigs_trapped = 1;
755*0b459c2cSDavid du Colombier }
756*0b459c2cSDavid du Colombier 
757*0b459c2cSDavid du Colombier /* Untrap signal S, or all trapped signals if S is zero.  */
758*0b459c2cSDavid du Colombier static void
untrapsig(s)759*0b459c2cSDavid du Colombier untrapsig (s)
760*0b459c2cSDavid du Colombier      int s;
761*0b459c2cSDavid du Colombier {
762*0b459c2cSDavid du Colombier   int i;
763*0b459c2cSDavid du Colombier 
764*0b459c2cSDavid du Colombier   if (sigs_trapped)
765*0b459c2cSDavid du Colombier     for (i = 0;  i < NUM_SIGS;  i++)
766*0b459c2cSDavid du Colombier       if ((!s || sigs[i] == s)  &&  initial_handler (i) != SIG_IGN)
767*0b459c2cSDavid du Colombier #if HAVE_SIGACTION
768*0b459c2cSDavid du Colombier 	  sigaction (sigs[i], &initial_action[i], 0);
769*0b459c2cSDavid du Colombier #else
770*0b459c2cSDavid du Colombier 	  signal (sigs[i], initial_action[i]);
771*0b459c2cSDavid du Colombier #endif
772*0b459c2cSDavid du Colombier }
773*0b459c2cSDavid du Colombier 
774*0b459c2cSDavid du Colombier /* Exit if a signal has been received.  */
775*0b459c2cSDavid du Colombier static void
checksigs()776*0b459c2cSDavid du Colombier checksigs ()
777*0b459c2cSDavid du Colombier {
778*0b459c2cSDavid du Colombier   int s = signal_received;
779*0b459c2cSDavid du Colombier   if (s)
780*0b459c2cSDavid du Colombier     {
781*0b459c2cSDavid du Colombier       cleanup ();
782*0b459c2cSDavid du Colombier 
783*0b459c2cSDavid du Colombier       /* Yield an exit status indicating that a signal was received.  */
784*0b459c2cSDavid du Colombier       untrapsig (s);
785*0b459c2cSDavid du Colombier       kill (getpid (), s);
786*0b459c2cSDavid du Colombier 
787*0b459c2cSDavid du Colombier       /* That didn't work, so exit with error status.  */
788*0b459c2cSDavid du Colombier       exit (2);
789*0b459c2cSDavid du Colombier     }
790*0b459c2cSDavid du Colombier }
791*0b459c2cSDavid du Colombier 
792*0b459c2cSDavid du Colombier 
793*0b459c2cSDavid du Colombier 
794*0b459c2cSDavid du Colombier static void
give_help()795*0b459c2cSDavid du Colombier give_help ()
796*0b459c2cSDavid du Colombier {
797*0b459c2cSDavid du Colombier   fprintf (stderr,"l:\tuse the left version\n");
798*0b459c2cSDavid du Colombier   fprintf (stderr,"r:\tuse the right version\n");
799*0b459c2cSDavid du Colombier   fprintf (stderr,"e l:\tedit then use the left version\n");
800*0b459c2cSDavid du Colombier   fprintf (stderr,"e r:\tedit then use the right version\n");
801*0b459c2cSDavid du Colombier   fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n");
802*0b459c2cSDavid du Colombier   fprintf (stderr,"e:\tedit a new version\n");
803*0b459c2cSDavid du Colombier   fprintf (stderr,"s:\tsilently include common lines\n");
804*0b459c2cSDavid du Colombier   fprintf (stderr,"v:\tverbosely include common lines\n");
805*0b459c2cSDavid du Colombier   fprintf (stderr,"q:\tquit\n");
806*0b459c2cSDavid du Colombier }
807*0b459c2cSDavid du Colombier 
808*0b459c2cSDavid du Colombier static int
skip_white()809*0b459c2cSDavid du Colombier skip_white ()
810*0b459c2cSDavid du Colombier {
811*0b459c2cSDavid du Colombier   int c;
812*0b459c2cSDavid du Colombier   for (;;)
813*0b459c2cSDavid du Colombier     {
814*0b459c2cSDavid du Colombier       c = getchar ();
815*0b459c2cSDavid du Colombier       if (!ISSPACE (c) || c == '\n')
816*0b459c2cSDavid du Colombier 	break;
817*0b459c2cSDavid du Colombier       checksigs ();
818*0b459c2cSDavid du Colombier     }
819*0b459c2cSDavid du Colombier   if (ferror (stdin))
820*0b459c2cSDavid du Colombier     perror_fatal ("input error");
821*0b459c2cSDavid du Colombier   return c;
822*0b459c2cSDavid du Colombier }
823*0b459c2cSDavid du Colombier 
824*0b459c2cSDavid du Colombier static void
flush_line()825*0b459c2cSDavid du Colombier flush_line ()
826*0b459c2cSDavid du Colombier {
827*0b459c2cSDavid du Colombier   int c;
828*0b459c2cSDavid du Colombier   while ((c = getchar ()) != '\n' && c != EOF)
829*0b459c2cSDavid du Colombier     ;
830*0b459c2cSDavid du Colombier   if (ferror (stdin))
831*0b459c2cSDavid du Colombier     perror_fatal ("input error");
832*0b459c2cSDavid du Colombier }
833*0b459c2cSDavid du Colombier 
834*0b459c2cSDavid du Colombier 
835*0b459c2cSDavid du Colombier /* interpret an edit command */
836*0b459c2cSDavid du Colombier static int
edit(left,lenl,right,lenr,outfile)837*0b459c2cSDavid du Colombier edit (left, lenl, right, lenr, outfile)
838*0b459c2cSDavid du Colombier      struct line_filter *left;
839*0b459c2cSDavid du Colombier      int lenl;
840*0b459c2cSDavid du Colombier      struct line_filter *right;
841*0b459c2cSDavid du Colombier      int lenr;
842*0b459c2cSDavid du Colombier      FILE *outfile;
843*0b459c2cSDavid du Colombier {
844*0b459c2cSDavid du Colombier   for (;;)
845*0b459c2cSDavid du Colombier     {
846*0b459c2cSDavid du Colombier       int cmd0, cmd1;
847*0b459c2cSDavid du Colombier       int gotcmd = 0;
848*0b459c2cSDavid du Colombier 
849*0b459c2cSDavid du Colombier       cmd1 = 0; /* Pacify `gcc -W'.  */
850*0b459c2cSDavid du Colombier 
851*0b459c2cSDavid du Colombier       while (!gotcmd)
852*0b459c2cSDavid du Colombier 	{
853*0b459c2cSDavid du Colombier 	  if (putchar ('%') != '%')
854*0b459c2cSDavid du Colombier 	    perror_fatal ("output error");
855*0b459c2cSDavid du Colombier 	  ck_fflush (stdout);
856*0b459c2cSDavid du Colombier 
857*0b459c2cSDavid du Colombier 	  cmd0 = skip_white ();
858*0b459c2cSDavid du Colombier 	  switch (cmd0)
859*0b459c2cSDavid du Colombier 	    {
860*0b459c2cSDavid du Colombier 	    case 'l': case 'r': case 's': case 'v': case 'q':
861*0b459c2cSDavid du Colombier 	      if (skip_white () != '\n')
862*0b459c2cSDavid du Colombier 		{
863*0b459c2cSDavid du Colombier 		  give_help ();
864*0b459c2cSDavid du Colombier 		  flush_line ();
865*0b459c2cSDavid du Colombier 		  continue;
866*0b459c2cSDavid du Colombier 		}
867*0b459c2cSDavid du Colombier 	      gotcmd = 1;
868*0b459c2cSDavid du Colombier 	      break;
869*0b459c2cSDavid du Colombier 
870*0b459c2cSDavid du Colombier 	    case 'e':
871*0b459c2cSDavid du Colombier 	      cmd1 = skip_white ();
872*0b459c2cSDavid du Colombier 	      switch (cmd1)
873*0b459c2cSDavid du Colombier 		{
874*0b459c2cSDavid du Colombier 		case 'l': case 'r': case 'b':
875*0b459c2cSDavid du Colombier 		  if (skip_white () != '\n')
876*0b459c2cSDavid du Colombier 		    {
877*0b459c2cSDavid du Colombier 		      give_help ();
878*0b459c2cSDavid du Colombier 		      flush_line ();
879*0b459c2cSDavid du Colombier 		      continue;
880*0b459c2cSDavid du Colombier 		    }
881*0b459c2cSDavid du Colombier 		  gotcmd = 1;
882*0b459c2cSDavid du Colombier 		  break;
883*0b459c2cSDavid du Colombier 		case '\n':
884*0b459c2cSDavid du Colombier 		  gotcmd = 1;
885*0b459c2cSDavid du Colombier 		  break;
886*0b459c2cSDavid du Colombier 		default:
887*0b459c2cSDavid du Colombier 		  give_help ();
888*0b459c2cSDavid du Colombier 		  flush_line ();
889*0b459c2cSDavid du Colombier 		  continue;
890*0b459c2cSDavid du Colombier 		}
891*0b459c2cSDavid du Colombier 	      break;
892*0b459c2cSDavid du Colombier 	    case EOF:
893*0b459c2cSDavid du Colombier 	      if (feof (stdin))
894*0b459c2cSDavid du Colombier 		{
895*0b459c2cSDavid du Colombier 		  gotcmd = 1;
896*0b459c2cSDavid du Colombier 		  cmd0 = 'q';
897*0b459c2cSDavid du Colombier 		  break;
898*0b459c2cSDavid du Colombier 		}
899*0b459c2cSDavid du Colombier 	      /* falls through */
900*0b459c2cSDavid du Colombier 	    default:
901*0b459c2cSDavid du Colombier 	      flush_line ();
902*0b459c2cSDavid du Colombier 	      /* falls through */
903*0b459c2cSDavid du Colombier 	    case '\n':
904*0b459c2cSDavid du Colombier 	      give_help ();
905*0b459c2cSDavid du Colombier 	      continue;
906*0b459c2cSDavid du Colombier 	    }
907*0b459c2cSDavid du Colombier 	}
908*0b459c2cSDavid du Colombier 
909*0b459c2cSDavid du Colombier       switch (cmd0)
910*0b459c2cSDavid du Colombier 	{
911*0b459c2cSDavid du Colombier 	case 'l':
912*0b459c2cSDavid du Colombier 	  lf_copy (left, lenl, outfile);
913*0b459c2cSDavid du Colombier 	  lf_skip (right, lenr);
914*0b459c2cSDavid du Colombier 	  return 1;
915*0b459c2cSDavid du Colombier 	case 'r':
916*0b459c2cSDavid du Colombier 	  lf_copy (right, lenr, outfile);
917*0b459c2cSDavid du Colombier 	  lf_skip (left, lenl);
918*0b459c2cSDavid du Colombier 	  return 1;
919*0b459c2cSDavid du Colombier 	case 's':
920*0b459c2cSDavid du Colombier 	  suppress_common_flag = 1;
921*0b459c2cSDavid du Colombier 	  break;
922*0b459c2cSDavid du Colombier 	case 'v':
923*0b459c2cSDavid du Colombier 	  suppress_common_flag = 0;
924*0b459c2cSDavid du Colombier 	  break;
925*0b459c2cSDavid du Colombier 	case 'q':
926*0b459c2cSDavid du Colombier 	  return 0;
927*0b459c2cSDavid du Colombier 	case 'e':
928*0b459c2cSDavid du Colombier 	  {
929*0b459c2cSDavid du Colombier 	    int tfd;
930*0b459c2cSDavid du Colombier 	    FILE *tmp;
931*0b459c2cSDavid du Colombier 
932*0b459c2cSDavid du Colombier 	    if (tmpmade)
933*0b459c2cSDavid du Colombier 	      {
934*0b459c2cSDavid du Colombier 	        unlink (tmpname);
935*0b459c2cSDavid du Colombier 	        tmpmade = 0;
936*0b459c2cSDavid du Colombier 		free (tmpname);
937*0b459c2cSDavid du Colombier 	      }
938*0b459c2cSDavid du Colombier 
939*0b459c2cSDavid du Colombier 	    asprintf (&tmpname, "%s/sdiff.XXXXXX",
940*0b459c2cSDavid du Colombier 	      getenv("TMPDIR") ?: P_tmpdir);
941*0b459c2cSDavid du Colombier 	    if (tmpname == NULL)
942*0b459c2cSDavid du Colombier 	      perror_fatal ("temporary file name");
943*0b459c2cSDavid du Colombier 	    tfd = mkstemp(tmpname);
944*0b459c2cSDavid du Colombier 	    if (tfd == -1)
945*0b459c2cSDavid du Colombier 	      perror_fatal ("temporary file name");
946*0b459c2cSDavid du Colombier 	    tmp = fdopen (tfd, "w+");
947*0b459c2cSDavid du Colombier 	    if (tmp == NULL)
948*0b459c2cSDavid du Colombier 	      perror_fatal ("temporary file name");
949*0b459c2cSDavid du Colombier 
950*0b459c2cSDavid du Colombier 	    tmpmade = 1;
951*0b459c2cSDavid du Colombier 
952*0b459c2cSDavid du Colombier 	    if (cmd1 == 'l' || cmd1 == 'b')
953*0b459c2cSDavid du Colombier 	      lf_copy (left, lenl, tmp);
954*0b459c2cSDavid du Colombier 	    else
955*0b459c2cSDavid du Colombier 	      lf_skip (left, lenl);
956*0b459c2cSDavid du Colombier 
957*0b459c2cSDavid du Colombier 	    if (cmd1 == 'r' || cmd1 == 'b')
958*0b459c2cSDavid du Colombier 	      lf_copy (right, lenr, tmp);
959*0b459c2cSDavid du Colombier 	    else
960*0b459c2cSDavid du Colombier 	      lf_skip (right, lenr);
961*0b459c2cSDavid du Colombier 
962*0b459c2cSDavid du Colombier 	    ck_fflush (tmp);
963*0b459c2cSDavid du Colombier 
964*0b459c2cSDavid du Colombier 	    {
965*0b459c2cSDavid du Colombier 	      int wstatus;
966*0b459c2cSDavid du Colombier #if ! HAVE_FORK
967*0b459c2cSDavid du Colombier 	      char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2);
968*0b459c2cSDavid du Colombier 	      sprintf (command, "%s %s", edbin, tmpname);
969*0b459c2cSDavid du Colombier 	      wstatus = system (command);
970*0b459c2cSDavid du Colombier 	      free (command);
971*0b459c2cSDavid du Colombier #else /* HAVE_FORK */
972*0b459c2cSDavid du Colombier 	      pid_t pid;
973*0b459c2cSDavid du Colombier 
974*0b459c2cSDavid du Colombier 	      ignore_SIGINT = 1;
975*0b459c2cSDavid du Colombier 	      checksigs ();
976*0b459c2cSDavid du Colombier 
977*0b459c2cSDavid du Colombier 	      pid = fork ();
978*0b459c2cSDavid du Colombier 	      if (pid == 0)
979*0b459c2cSDavid du Colombier 		{
980*0b459c2cSDavid du Colombier 		  char const *argv[3];
981*0b459c2cSDavid du Colombier 		  int i = 0;
982*0b459c2cSDavid du Colombier 
983*0b459c2cSDavid du Colombier 		  argv[i++] = edbin;
984*0b459c2cSDavid du Colombier 		  argv[i++] = tmpname;
985*0b459c2cSDavid du Colombier 		  argv[i++] = 0;
986*0b459c2cSDavid du Colombier 
987*0b459c2cSDavid du Colombier 		  execvp (edbin, (char **) argv);
988*0b459c2cSDavid du Colombier 		  write (STDERR_FILENO, edbin, strlen (edbin));
989*0b459c2cSDavid du Colombier 		  write (STDERR_FILENO, ": not found\n", 12);
990*0b459c2cSDavid du Colombier 		  _exit (1);
991*0b459c2cSDavid du Colombier 		}
992*0b459c2cSDavid du Colombier 
993*0b459c2cSDavid du Colombier 	      if (pid < 0)
994*0b459c2cSDavid du Colombier 		perror_fatal ("fork failed");
995*0b459c2cSDavid du Colombier 
996*0b459c2cSDavid du Colombier 	      while (waitpid (pid, &wstatus, 0) < 0)
997*0b459c2cSDavid du Colombier 		if (errno == EINTR)
998*0b459c2cSDavid du Colombier 		  checksigs ();
999*0b459c2cSDavid du Colombier 		else
1000*0b459c2cSDavid du Colombier 		  perror_fatal ("wait failed");
1001*0b459c2cSDavid du Colombier 
1002*0b459c2cSDavid du Colombier 	      ignore_SIGINT = 0;
1003*0b459c2cSDavid du Colombier #endif /* HAVE_FORK */
1004*0b459c2cSDavid du Colombier 
1005*0b459c2cSDavid du Colombier 	      if (wstatus != 0)
1006*0b459c2cSDavid du Colombier 		fatal ("Subsidiary editor failed");
1007*0b459c2cSDavid du Colombier 	    }
1008*0b459c2cSDavid du Colombier 
1009*0b459c2cSDavid du Colombier 	    if (fseek (tmp, 0L, SEEK_SET) != 0)
1010*0b459c2cSDavid du Colombier 	      perror_fatal ("fseek");
1011*0b459c2cSDavid du Colombier 	    {
1012*0b459c2cSDavid du Colombier 	      /* SDIFF_BUFSIZE is too big for a local var
1013*0b459c2cSDavid du Colombier 		 in some compilers, so we allocate it dynamically.  */
1014*0b459c2cSDavid du Colombier 	      char *buf = xmalloc (SDIFF_BUFSIZE);
1015*0b459c2cSDavid du Colombier 	      size_t size;
1016*0b459c2cSDavid du Colombier 
1017*0b459c2cSDavid du Colombier 	      while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
1018*0b459c2cSDavid du Colombier 		{
1019*0b459c2cSDavid du Colombier 		  checksigs ();
1020*0b459c2cSDavid du Colombier 		  ck_fwrite (buf, size, outfile);
1021*0b459c2cSDavid du Colombier 		}
1022*0b459c2cSDavid du Colombier 	      ck_fclose (tmp);
1023*0b459c2cSDavid du Colombier 
1024*0b459c2cSDavid du Colombier 	      free (buf);
1025*0b459c2cSDavid du Colombier 	    }
1026*0b459c2cSDavid du Colombier 	    return 1;
1027*0b459c2cSDavid du Colombier 	  }
1028*0b459c2cSDavid du Colombier 	default:
1029*0b459c2cSDavid du Colombier 	  give_help ();
1030*0b459c2cSDavid du Colombier 	  break;
1031*0b459c2cSDavid du Colombier 	}
1032*0b459c2cSDavid du Colombier     }
1033*0b459c2cSDavid du Colombier }
1034*0b459c2cSDavid du Colombier 
1035*0b459c2cSDavid du Colombier 
1036*0b459c2cSDavid du Colombier 
1037*0b459c2cSDavid du Colombier /* Alternately reveal bursts of diff output and handle user commands.  */
1038*0b459c2cSDavid du Colombier static int
interact(diff,left,right,outfile)1039*0b459c2cSDavid du Colombier interact (diff, left, right, outfile)
1040*0b459c2cSDavid du Colombier      struct line_filter *diff;
1041*0b459c2cSDavid du Colombier      struct line_filter *left;
1042*0b459c2cSDavid du Colombier      struct line_filter *right;
1043*0b459c2cSDavid du Colombier      FILE *outfile;
1044*0b459c2cSDavid du Colombier {
1045*0b459c2cSDavid du Colombier   for (;;)
1046*0b459c2cSDavid du Colombier     {
1047*0b459c2cSDavid du Colombier       char diff_help[256];
1048*0b459c2cSDavid du Colombier       int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help));
1049*0b459c2cSDavid du Colombier 
1050*0b459c2cSDavid du Colombier       if (snarfed <= 0)
1051*0b459c2cSDavid du Colombier 	return snarfed;
1052*0b459c2cSDavid du Colombier 
1053*0b459c2cSDavid du Colombier       checksigs ();
1054*0b459c2cSDavid du Colombier 
1055*0b459c2cSDavid du Colombier       switch (diff_help[0])
1056*0b459c2cSDavid du Colombier 	{
1057*0b459c2cSDavid du Colombier 	case ' ':
1058*0b459c2cSDavid du Colombier 	  puts (diff_help + 1);
1059*0b459c2cSDavid du Colombier 	  break;
1060*0b459c2cSDavid du Colombier 	case 'i':
1061*0b459c2cSDavid du Colombier 	  {
1062*0b459c2cSDavid du Colombier 	    int lenl = atoi (diff_help + 1), lenr, lenmax;
1063*0b459c2cSDavid du Colombier 	    char *p = strchr (diff_help, ',');
1064*0b459c2cSDavid du Colombier 
1065*0b459c2cSDavid du Colombier 	    if (!p)
1066*0b459c2cSDavid du Colombier 	      fatal (diff_help);
1067*0b459c2cSDavid du Colombier 	    lenr = atoi (p + 1);
1068*0b459c2cSDavid du Colombier 	    lenmax = max (lenl, lenr);
1069*0b459c2cSDavid du Colombier 
1070*0b459c2cSDavid du Colombier 	    if (suppress_common_flag)
1071*0b459c2cSDavid du Colombier 	      lf_skip (diff, lenmax);
1072*0b459c2cSDavid du Colombier 	    else
1073*0b459c2cSDavid du Colombier 	      lf_copy (diff, lenmax, stdout);
1074*0b459c2cSDavid du Colombier 
1075*0b459c2cSDavid du Colombier 	    lf_copy (left, lenl, outfile);
1076*0b459c2cSDavid du Colombier 	    lf_skip (right, lenr);
1077*0b459c2cSDavid du Colombier 	    break;
1078*0b459c2cSDavid du Colombier 	  }
1079*0b459c2cSDavid du Colombier 	case 'c':
1080*0b459c2cSDavid du Colombier 	  {
1081*0b459c2cSDavid du Colombier 	    int lenl = atoi (diff_help + 1), lenr;
1082*0b459c2cSDavid du Colombier 	    char *p = strchr (diff_help, ',');
1083*0b459c2cSDavid du Colombier 
1084*0b459c2cSDavid du Colombier 	    if (!p)
1085*0b459c2cSDavid du Colombier 	      fatal (diff_help);
1086*0b459c2cSDavid du Colombier 	    lenr = atoi (p + 1);
1087*0b459c2cSDavid du Colombier 	    lf_copy (diff, max (lenl, lenr), stdout);
1088*0b459c2cSDavid du Colombier 	    if (! edit (left, lenl, right, lenr, outfile))
1089*0b459c2cSDavid du Colombier 	      return 0;
1090*0b459c2cSDavid du Colombier 	    break;
1091*0b459c2cSDavid du Colombier 	  }
1092*0b459c2cSDavid du Colombier 	default:
1093*0b459c2cSDavid du Colombier 	  fatal (diff_help);
1094*0b459c2cSDavid du Colombier 	  break;
1095*0b459c2cSDavid du Colombier 	}
1096*0b459c2cSDavid du Colombier     }
1097*0b459c2cSDavid du Colombier }
1098*0b459c2cSDavid du Colombier 
1099*0b459c2cSDavid du Colombier 
1100*0b459c2cSDavid du Colombier 
1101*0b459c2cSDavid du Colombier /* temporary lossage: this is torn from gnu libc */
1102*0b459c2cSDavid du Colombier /* Return nonzero if DIR is an existing directory.  */
1103*0b459c2cSDavid du Colombier static int
diraccess(dir)1104*0b459c2cSDavid du Colombier diraccess (dir)
1105*0b459c2cSDavid du Colombier      char const *dir;
1106*0b459c2cSDavid du Colombier {
1107*0b459c2cSDavid du Colombier   struct stat buf;
1108*0b459c2cSDavid du Colombier   return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
1109*0b459c2cSDavid du Colombier }
1110