xref: /netbsd-src/external/gpl2/xcvs/dist/diff/util.c (revision 00f7e7b88ff2fefd1ee491c56482a1c6dba6887f)
1a7c91847Schristos /* Support routines for GNU DIFF.
2a7c91847Schristos    Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
3a7c91847Schristos 
4a7c91847Schristos This file is part of GNU DIFF.
5a7c91847Schristos 
6a7c91847Schristos GNU DIFF is free software; you can redistribute it and/or modify
7a7c91847Schristos it under the terms of the GNU General Public License as published by
8a7c91847Schristos the Free Software Foundation; either version 2, or (at your option)
9a7c91847Schristos any later version.
10a7c91847Schristos 
11a7c91847Schristos GNU DIFF is distributed in the hope that it will be useful,
12a7c91847Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13a7c91847Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14a7c91847Schristos GNU General Public License for more details.
15a7c91847Schristos 
16a7c91847Schristos */
17a7c91847Schristos 
18a7c91847Schristos #include "diff.h"
19a7c91847Schristos 
20a7c91847Schristos #if __STDC__
21a7c91847Schristos #include <stdarg.h>
22a7c91847Schristos #else
23a7c91847Schristos #include <varargs.h>
24a7c91847Schristos #endif
25a7c91847Schristos 
26a7c91847Schristos #ifndef strerror
27a7c91847Schristos extern char *strerror ();
28a7c91847Schristos #endif
29a7c91847Schristos 
30a7c91847Schristos /* Queue up one-line messages to be printed at the end,
31a7c91847Schristos    when -l is specified.  Each message is recorded with a `struct msg'.  */
32a7c91847Schristos 
33a7c91847Schristos struct msg
34a7c91847Schristos {
35a7c91847Schristos   struct msg *next;
36a7c91847Schristos   char const *format;
37a7c91847Schristos   char const *arg1;
38a7c91847Schristos   char const *arg2;
39a7c91847Schristos   char const *arg3;
40a7c91847Schristos   char const *arg4;
41a7c91847Schristos };
42a7c91847Schristos 
43a7c91847Schristos /* Head of the chain of queues messages.  */
44a7c91847Schristos 
45a7c91847Schristos static struct msg *msg_chain;
46a7c91847Schristos 
47a7c91847Schristos /* Tail of the chain of queues messages.  */
48a7c91847Schristos 
49a7c91847Schristos static struct msg **msg_chain_end = &msg_chain;
50a7c91847Schristos 
51a7c91847Schristos /* Use when a system call returns non-zero status.
52a7c91847Schristos    TEXT should normally be the file name.  */
53a7c91847Schristos 
54a7c91847Schristos void
perror_with_name(text)55a7c91847Schristos perror_with_name (text)
56a7c91847Schristos      char const *text;
57a7c91847Schristos {
58a7c91847Schristos   int e = errno;
59a7c91847Schristos 
60a7c91847Schristos   if (callbacks && callbacks->error)
61a7c91847Schristos     (*callbacks->error) ("%s: %s", text, strerror (e));
62a7c91847Schristos   else
63a7c91847Schristos     {
64a7c91847Schristos       fprintf (stderr, "%s: ", diff_program_name);
65a7c91847Schristos       errno = e;
66a7c91847Schristos       perror (text);
67a7c91847Schristos     }
68a7c91847Schristos }
69a7c91847Schristos 
70a7c91847Schristos /* Use when a system call returns non-zero status and that is fatal.  */
71a7c91847Schristos 
72a7c91847Schristos void
pfatal_with_name(text)73a7c91847Schristos pfatal_with_name (text)
74a7c91847Schristos      char const *text;
75a7c91847Schristos {
76a7c91847Schristos   int e = errno;
77a7c91847Schristos   print_message_queue ();
78a7c91847Schristos   if (callbacks && callbacks->error)
79a7c91847Schristos     (*callbacks->error) ("%s: %s", text, strerror (e));
80a7c91847Schristos   else
81a7c91847Schristos     {
82a7c91847Schristos       fprintf (stderr, "%s: ", diff_program_name);
83a7c91847Schristos       errno = e;
84a7c91847Schristos       perror (text);
85a7c91847Schristos     }
86a7c91847Schristos   DIFF_ABORT (2);
87a7c91847Schristos }
88a7c91847Schristos 
89a7c91847Schristos /* Print an error message from the format-string FORMAT
90a7c91847Schristos    with args ARG1 and ARG2.  */
91a7c91847Schristos 
92a7c91847Schristos void
diff_error(format,arg,arg1)93a7c91847Schristos diff_error (format, arg, arg1)
94a7c91847Schristos      char const *format, *arg, *arg1;
95a7c91847Schristos {
96a7c91847Schristos   if (callbacks && callbacks->error)
97a7c91847Schristos     (*callbacks->error) (format, arg, arg1);
98a7c91847Schristos   else
99a7c91847Schristos     {
100a7c91847Schristos       fprintf (stderr, "%s: ", diff_program_name);
101a7c91847Schristos       fprintf (stderr, format, arg, arg1);
102a7c91847Schristos       fprintf (stderr, "\n");
103a7c91847Schristos     }
104a7c91847Schristos }
105a7c91847Schristos 
106a7c91847Schristos /* Print an error message containing the string TEXT, then exit.  */
107a7c91847Schristos 
108a7c91847Schristos void
fatal(m)109a7c91847Schristos fatal (m)
110a7c91847Schristos      char const *m;
111a7c91847Schristos {
112a7c91847Schristos   print_message_queue ();
113a7c91847Schristos   diff_error ("%s", m, 0);
114a7c91847Schristos   DIFF_ABORT (2);
115a7c91847Schristos }
116a7c91847Schristos 
117a7c91847Schristos /* Like printf, except if -l in effect then save the message and print later.
118a7c91847Schristos    This is used for things like "binary files differ" and "Only in ...".  */
119a7c91847Schristos 
120a7c91847Schristos void
message(format,arg1,arg2)121a7c91847Schristos message (format, arg1, arg2)
122a7c91847Schristos      char const *format, *arg1, *arg2;
123a7c91847Schristos {
124a7c91847Schristos   message5 (format, arg1, arg2, 0, 0);
125a7c91847Schristos }
126a7c91847Schristos 
127a7c91847Schristos void
message5(format,arg1,arg2,arg3,arg4)128a7c91847Schristos message5 (format, arg1, arg2, arg3, arg4)
129a7c91847Schristos      char const *format, *arg1, *arg2, *arg3, *arg4;
130a7c91847Schristos {
131a7c91847Schristos   if (paginate_flag)
132a7c91847Schristos     {
133a7c91847Schristos       struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
134a7c91847Schristos       new->format = format;
135a7c91847Schristos       new->arg1 = concat (arg1, "", "");
136a7c91847Schristos       new->arg2 = concat (arg2, "", "");
137a7c91847Schristos       new->arg3 = arg3 ? concat (arg3, "", "") : 0;
138a7c91847Schristos       new->arg4 = arg4 ? concat (arg4, "", "") : 0;
139a7c91847Schristos       new->next = 0;
140a7c91847Schristos       *msg_chain_end = new;
141a7c91847Schristos       msg_chain_end = &new->next;
142a7c91847Schristos     }
143a7c91847Schristos   else
144a7c91847Schristos     {
145a7c91847Schristos       if (sdiff_help_sdiff)
146a7c91847Schristos 	write_output (" ", 1);
147a7c91847Schristos       printf_output (format, arg1, arg2, arg3, arg4);
148a7c91847Schristos     }
149a7c91847Schristos }
150a7c91847Schristos 
151a7c91847Schristos /* Output all the messages that were saved up by calls to `message'.  */
152a7c91847Schristos 
153a7c91847Schristos void
print_message_queue()154a7c91847Schristos print_message_queue ()
155a7c91847Schristos {
156a7c91847Schristos   struct msg *m;
157a7c91847Schristos 
158a7c91847Schristos   for (m = msg_chain; m; m = m->next)
159a7c91847Schristos     printf_output (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
160a7c91847Schristos }
161a7c91847Schristos 
162a7c91847Schristos /* Call before outputting the results of comparing files NAME0 and NAME1
163a7c91847Schristos    to set up OUTFILE, the stdio stream for the output to go to.
164a7c91847Schristos 
165a7c91847Schristos    Usually, OUTFILE is just stdout.  But when -l was specified
166a7c91847Schristos    we fork off a `pr' and make OUTFILE a pipe to it.
167a7c91847Schristos    `pr' then outputs to our stdout.  */
168a7c91847Schristos 
169a7c91847Schristos static char const *current_name0;
170a7c91847Schristos static char const *current_name1;
171a7c91847Schristos static int current_depth;
172a7c91847Schristos 
173a7c91847Schristos static int output_in_progress = 0;
174a7c91847Schristos 
175a7c91847Schristos void
setup_output(name0,name1,depth)176a7c91847Schristos setup_output (name0, name1, depth)
177a7c91847Schristos      char const *name0, *name1;
178a7c91847Schristos      int depth;
179a7c91847Schristos {
180a7c91847Schristos   current_name0 = name0;
181a7c91847Schristos   current_name1 = name1;
182a7c91847Schristos   current_depth = depth;
183a7c91847Schristos }
184a7c91847Schristos 
185a7c91847Schristos #if HAVE_FORK && defined (PR_PROGRAM)
186a7c91847Schristos static pid_t pr_pid;
187a7c91847Schristos #endif
188a7c91847Schristos 
189a7c91847Schristos void
begin_output()190a7c91847Schristos begin_output ()
191a7c91847Schristos {
192a7c91847Schristos   char *name;
193a7c91847Schristos 
194a7c91847Schristos   if (output_in_progress)
195a7c91847Schristos     return;
196a7c91847Schristos   output_in_progress = 1;
197a7c91847Schristos 
198a7c91847Schristos   /* Construct the header of this piece of diff.  */
199a7c91847Schristos   name = xmalloc (strlen (current_name0) + strlen (current_name1)
200a7c91847Schristos 		  + strlen (switch_string) + 7);
201a7c91847Schristos   /* Posix.2 section 4.17.6.1.1 specifies this format.  But there is a
202a7c91847Schristos      bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
203a7c91847Schristos      it says that we must print only the last component of the pathnames.
204a7c91847Schristos      This requirement is silly and does not match historical practice.  */
205a7c91847Schristos   sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
206a7c91847Schristos 
207a7c91847Schristos   if (paginate_flag && callbacks && callbacks->write_output)
208a7c91847Schristos     fatal ("can't paginate when using library callbacks");
209a7c91847Schristos 
210a7c91847Schristos   if (paginate_flag)
211a7c91847Schristos     {
212a7c91847Schristos       /* Make OUTFILE a pipe to a subsidiary `pr'.  */
213a7c91847Schristos 
214a7c91847Schristos #ifdef PR_PROGRAM
215a7c91847Schristos 
216a7c91847Schristos # if HAVE_FORK
217a7c91847Schristos       int pipes[2];
218a7c91847Schristos 
219a7c91847Schristos       if (pipe (pipes) != 0)
220a7c91847Schristos 	pfatal_with_name ("pipe");
221a7c91847Schristos 
222a7c91847Schristos       fflush (stdout);
223a7c91847Schristos 
224a7c91847Schristos       pr_pid = vfork ();
225a7c91847Schristos       if (pr_pid < 0)
226a7c91847Schristos 	pfatal_with_name ("vfork");
227a7c91847Schristos 
228a7c91847Schristos       if (pr_pid == 0)
229a7c91847Schristos 	{
230a7c91847Schristos 	  close (pipes[1]);
231a7c91847Schristos 	  if (pipes[0] != STDIN_FILENO)
232a7c91847Schristos 	    {
233a7c91847Schristos 	      if (dup2 (pipes[0], STDIN_FILENO) < 0)
234a7c91847Schristos 		pfatal_with_name ("dup2");
235a7c91847Schristos 	      close (pipes[0]);
236a7c91847Schristos 	    }
237a7c91847Schristos 
238*00f7e7b8Schristos 	  execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, NULL);
239a7c91847Schristos 	  pfatal_with_name (PR_PROGRAM);
240a7c91847Schristos 	}
241a7c91847Schristos       else
242a7c91847Schristos 	{
243a7c91847Schristos 	  close (pipes[0]);
244a7c91847Schristos 	  outfile = fdopen (pipes[1], "w");
245a7c91847Schristos 	  if (!outfile)
246a7c91847Schristos 	    pfatal_with_name ("fdopen");
247a7c91847Schristos 	}
248a7c91847Schristos # else /* ! HAVE_FORK */
249a7c91847Schristos       char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10);
250a7c91847Schristos       char *p;
251a7c91847Schristos       char const *a = name;
252a7c91847Schristos       sprintf (command, "%s -f -h ", PR_PROGRAM);
253a7c91847Schristos       p = command + strlen (command);
254a7c91847Schristos       SYSTEM_QUOTE_ARG (p, a);
255a7c91847Schristos       *p = 0;
256a7c91847Schristos       outfile = popen (command, "w");
257a7c91847Schristos       if (!outfile)
258a7c91847Schristos 	pfatal_with_name (command);
259a7c91847Schristos       free (command);
260a7c91847Schristos # endif /* ! HAVE_FORK */
261a7c91847Schristos #else
262a7c91847Schristos       fatal ("This port does not support the --paginate option to diff.");
263a7c91847Schristos #endif
264a7c91847Schristos     }
265a7c91847Schristos   else
266a7c91847Schristos     {
267a7c91847Schristos 
268a7c91847Schristos       /* If -l was not specified, output the diff straight to `stdout'.  */
269a7c91847Schristos 
270a7c91847Schristos       /* If handling multiple files (because scanning a directory),
271a7c91847Schristos 	 print which files the following output is about.  */
272a7c91847Schristos       if (current_depth > 0)
273a7c91847Schristos 	printf_output ("%s\n", name);
274a7c91847Schristos     }
275a7c91847Schristos 
276a7c91847Schristos   free (name);
277a7c91847Schristos 
278a7c91847Schristos   /* A special header is needed at the beginning of context output.  */
279a7c91847Schristos   switch (output_style)
280a7c91847Schristos     {
281a7c91847Schristos     case OUTPUT_CONTEXT:
282a7c91847Schristos       print_context_header (files, 0);
283a7c91847Schristos       break;
284a7c91847Schristos 
285a7c91847Schristos     case OUTPUT_UNIFIED:
286a7c91847Schristos       print_context_header (files, 1);
287a7c91847Schristos       break;
288a7c91847Schristos 
289a7c91847Schristos     default:
290a7c91847Schristos       break;
291a7c91847Schristos     }
292a7c91847Schristos }
293a7c91847Schristos 
294a7c91847Schristos /* Call after the end of output of diffs for one file.
295a7c91847Schristos    If -l was given, close OUTFILE and get rid of the `pr' subfork.  */
296a7c91847Schristos 
297a7c91847Schristos void
finish_output()298a7c91847Schristos finish_output ()
299a7c91847Schristos {
300a7c91847Schristos   if (paginate_flag && outfile != 0 && outfile != stdout)
301a7c91847Schristos     {
302a7c91847Schristos #ifdef PR_PROGRAM
303a7c91847Schristos       int wstatus, w;
304a7c91847Schristos       if (ferror (outfile))
305a7c91847Schristos 	fatal ("write error");
306a7c91847Schristos # if ! HAVE_FORK
307a7c91847Schristos       wstatus = pclose (outfile);
308a7c91847Schristos # else /* HAVE_FORK */
309a7c91847Schristos       if (fclose (outfile) != 0)
310a7c91847Schristos 	pfatal_with_name ("write error");
311a7c91847Schristos       while ((w = waitpid (pr_pid, &wstatus, 0)) < 0 && errno == EINTR)
312a7c91847Schristos 	;
313a7c91847Schristos       if (w < 0)
314a7c91847Schristos 	pfatal_with_name ("waitpid");
315a7c91847Schristos # endif /* HAVE_FORK */
316a7c91847Schristos       if (wstatus != 0)
317a7c91847Schristos 	fatal ("subsidiary pr failed");
318a7c91847Schristos #else
319a7c91847Schristos       fatal ("internal error in finish_output");
320a7c91847Schristos #endif
321a7c91847Schristos     }
322a7c91847Schristos 
323a7c91847Schristos   output_in_progress = 0;
324a7c91847Schristos }
325a7c91847Schristos 
326a7c91847Schristos /* Write something to the output file.  */
327a7c91847Schristos 
328a7c91847Schristos void
write_output(text,len)329a7c91847Schristos write_output (text, len)
330a7c91847Schristos      char const *text;
331a7c91847Schristos      size_t len;
332a7c91847Schristos {
333a7c91847Schristos   if (callbacks && callbacks->write_output)
334a7c91847Schristos     (*callbacks->write_output) (text, len);
335a7c91847Schristos   else if (len == 1)
336a7c91847Schristos     putc (*text, outfile);
337a7c91847Schristos   else
338a7c91847Schristos     fwrite (text, sizeof (char), len, outfile);
339a7c91847Schristos }
340a7c91847Schristos 
341a7c91847Schristos /* Printf something to the output file.  */
342a7c91847Schristos 
343a7c91847Schristos #if __STDC__
344a7c91847Schristos #define VA_START(args, lastarg) va_start(args, lastarg)
345a7c91847Schristos #else /* ! __STDC__ */
346a7c91847Schristos #define VA_START(args, lastarg) va_start(args)
347a7c91847Schristos #endif /* __STDC__ */
348a7c91847Schristos 
349a7c91847Schristos void
350a7c91847Schristos #if __STDC__
printf_output(const char * format,...)351a7c91847Schristos printf_output (const char *format, ...)
352a7c91847Schristos #else
353a7c91847Schristos printf_output (format, va_alist)
354a7c91847Schristos      char const *format;
355a7c91847Schristos      va_dcl
356a7c91847Schristos #endif
357a7c91847Schristos {
358a7c91847Schristos   va_list args;
359a7c91847Schristos 
360a7c91847Schristos   VA_START (args, format);
361a7c91847Schristos   if (callbacks && callbacks->write_output)
362a7c91847Schristos     {
363a7c91847Schristos       /* We implement our own limited printf-like functionality (%s, %d,
364a7c91847Schristos 	 and %c only).  Callers who want something fancier can use
365a7c91847Schristos 	 sprintf.  */
366a7c91847Schristos       const char *p = format;
367a7c91847Schristos       char *q;
368a7c91847Schristos       char *str;
369a7c91847Schristos       int num;
370a7c91847Schristos       int ch;
371a7c91847Schristos       char buf[100];
372a7c91847Schristos 
373a7c91847Schristos       while ((q = strchr (p, '%')) != NULL)
374a7c91847Schristos 	{
375a7c91847Schristos 	  static const char msg[] =
376a7c91847Schristos 	    "\ninternal error: bad % in printf_output\n";
377a7c91847Schristos 	  (*callbacks->write_output) (p, q - p);
378a7c91847Schristos 
379a7c91847Schristos 	  switch (q[1])
380a7c91847Schristos 	    {
381a7c91847Schristos 	    case 's':
382a7c91847Schristos 	      str = va_arg (args, char *);
383a7c91847Schristos 	      (*callbacks->write_output) (str, strlen (str));
384a7c91847Schristos 	      break;
385a7c91847Schristos 	    case 'd':
386a7c91847Schristos 	      num = va_arg (args, int);
387a7c91847Schristos 	      sprintf (buf, "%d", num);
388a7c91847Schristos 	      (*callbacks->write_output) (buf, strlen (buf));
389a7c91847Schristos 	      break;
390a7c91847Schristos 	    case 'c':
391a7c91847Schristos 	      ch = va_arg (args, int);
392a7c91847Schristos 	      buf[0] = ch;
393a7c91847Schristos 	      (*callbacks->write_output) (buf, 1);
394a7c91847Schristos 	      break;
395a7c91847Schristos 	    default:
396a7c91847Schristos 	      (*callbacks->write_output) (msg, sizeof (msg) - 1);
397a7c91847Schristos 	      /* Don't just keep going, because q + 1 might point to the
398a7c91847Schristos 		 terminating '\0'.  */
399a7c91847Schristos 	      goto out;
400a7c91847Schristos 	    }
401a7c91847Schristos 	  p = q + 2;
402a7c91847Schristos 	}
403a7c91847Schristos       (*callbacks->write_output) (p, strlen (p));
404a7c91847Schristos     }
405a7c91847Schristos   else
406a7c91847Schristos     vfprintf (outfile, format, args);
407a7c91847Schristos  out:
408a7c91847Schristos   va_end (args);
409a7c91847Schristos }
410a7c91847Schristos 
411a7c91847Schristos /* Flush the output file.  */
412a7c91847Schristos 
413a7c91847Schristos void
flush_output()414a7c91847Schristos flush_output ()
415a7c91847Schristos {
416a7c91847Schristos   if (callbacks && callbacks->flush_output)
417a7c91847Schristos     (*callbacks->flush_output) ();
418a7c91847Schristos   else
419a7c91847Schristos     fflush (outfile);
420a7c91847Schristos }
421a7c91847Schristos 
422a7c91847Schristos /* Compare two lines (typically one from each input file)
423a7c91847Schristos    according to the command line options.
424a7c91847Schristos    For efficiency, this is invoked only when the lines do not match exactly
425a7c91847Schristos    but an option like -i might cause us to ignore the difference.
426a7c91847Schristos    Return nonzero if the lines differ.  */
427a7c91847Schristos 
428a7c91847Schristos int
line_cmp(s1,s2)429a7c91847Schristos line_cmp (s1, s2)
430a7c91847Schristos      char const *s1, *s2;
431a7c91847Schristos {
432a7c91847Schristos   register unsigned char const *t1 = (unsigned char const *) s1;
433a7c91847Schristos   register unsigned char const *t2 = (unsigned char const *) s2;
434a7c91847Schristos 
435a7c91847Schristos   while (1)
436a7c91847Schristos     {
437a7c91847Schristos       register unsigned char c1 = *t1++;
438a7c91847Schristos       register unsigned char c2 = *t2++;
439a7c91847Schristos 
440a7c91847Schristos       /* Test for exact char equality first, since it's a common case.  */
441a7c91847Schristos       if (c1 != c2)
442a7c91847Schristos 	{
443a7c91847Schristos 	  /* Ignore horizontal white space if -b or -w is specified.  */
444a7c91847Schristos 
445a7c91847Schristos 	  if (ignore_all_space_flag)
446a7c91847Schristos 	    {
447a7c91847Schristos 	      /* For -w, just skip past any white space.  */
448a7c91847Schristos 	      while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
449a7c91847Schristos 	      while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
450a7c91847Schristos 	    }
451a7c91847Schristos 	  else if (ignore_space_change_flag)
452a7c91847Schristos 	    {
453a7c91847Schristos 	      /* For -b, advance past any sequence of white space in line 1
454a7c91847Schristos 		 and consider it just one Space, or nothing at all
455a7c91847Schristos 		 if it is at the end of the line.  */
456a7c91847Schristos 	      if (ISSPACE (c1))
457a7c91847Schristos 		{
458a7c91847Schristos 		  while (c1 != '\n')
459a7c91847Schristos 		    {
460a7c91847Schristos 		      c1 = *t1++;
461a7c91847Schristos 		      if (! ISSPACE (c1))
462a7c91847Schristos 			{
463a7c91847Schristos 			  --t1;
464a7c91847Schristos 			  c1 = ' ';
465a7c91847Schristos 			  break;
466a7c91847Schristos 			}
467a7c91847Schristos 		    }
468a7c91847Schristos 		}
469a7c91847Schristos 
470a7c91847Schristos 	      /* Likewise for line 2.  */
471a7c91847Schristos 	      if (ISSPACE (c2))
472a7c91847Schristos 		{
473a7c91847Schristos 		  while (c2 != '\n')
474a7c91847Schristos 		    {
475a7c91847Schristos 		      c2 = *t2++;
476a7c91847Schristos 		      if (! ISSPACE (c2))
477a7c91847Schristos 			{
478a7c91847Schristos 			  --t2;
479a7c91847Schristos 			  c2 = ' ';
480a7c91847Schristos 			  break;
481a7c91847Schristos 			}
482a7c91847Schristos 		    }
483a7c91847Schristos 		}
484a7c91847Schristos 
485a7c91847Schristos 	      if (c1 != c2)
486a7c91847Schristos 		{
487a7c91847Schristos 		  /* If we went too far when doing the simple test
488a7c91847Schristos 		     for equality, go back to the first non-white-space
489a7c91847Schristos 		     character in both sides and try again.  */
490a7c91847Schristos 		  if (c2 == ' ' && c1 != '\n'
491a7c91847Schristos 		      && (unsigned char const *) s1 + 1 < t1
492a7c91847Schristos 		      && ISSPACE(t1[-2]))
493a7c91847Schristos 		    {
494a7c91847Schristos 		      --t1;
495a7c91847Schristos 		      continue;
496a7c91847Schristos 		    }
497a7c91847Schristos 		  if (c1 == ' ' && c2 != '\n'
498a7c91847Schristos 		      && (unsigned char const *) s2 + 1 < t2
499a7c91847Schristos 		      && ISSPACE(t2[-2]))
500a7c91847Schristos 		    {
501a7c91847Schristos 		      --t2;
502a7c91847Schristos 		      continue;
503a7c91847Schristos 		    }
504a7c91847Schristos 		}
505a7c91847Schristos 	    }
506a7c91847Schristos 
507a7c91847Schristos 	  /* Lowercase all letters if -i is specified.  */
508a7c91847Schristos 
509a7c91847Schristos 	  if (ignore_case_flag)
510a7c91847Schristos 	    {
511a7c91847Schristos 	      if (ISUPPER (c1))
512a7c91847Schristos 		c1 = tolower (c1);
513a7c91847Schristos 	      if (ISUPPER (c2))
514a7c91847Schristos 		c2 = tolower (c2);
515a7c91847Schristos 	    }
516a7c91847Schristos 
517a7c91847Schristos 	  if (c1 != c2)
518a7c91847Schristos 	    break;
519a7c91847Schristos 	}
520a7c91847Schristos       if (c1 == '\n')
521a7c91847Schristos 	return 0;
522a7c91847Schristos     }
523a7c91847Schristos 
524a7c91847Schristos   return (1);
525a7c91847Schristos }
526a7c91847Schristos 
527a7c91847Schristos /* Find the consecutive changes at the start of the script START.
528a7c91847Schristos    Return the last link before the first gap.  */
529a7c91847Schristos 
530a7c91847Schristos struct change *
find_change(start)531a7c91847Schristos find_change (start)
532a7c91847Schristos      struct change *start;
533a7c91847Schristos {
534a7c91847Schristos   return start;
535a7c91847Schristos }
536a7c91847Schristos 
537a7c91847Schristos struct change *
find_reverse_change(start)538a7c91847Schristos find_reverse_change (start)
539a7c91847Schristos      struct change *start;
540a7c91847Schristos {
541a7c91847Schristos   return start;
542a7c91847Schristos }
543a7c91847Schristos 
544a7c91847Schristos /* Divide SCRIPT into pieces by calling HUNKFUN and
545a7c91847Schristos    print each piece with PRINTFUN.
546a7c91847Schristos    Both functions take one arg, an edit script.
547a7c91847Schristos 
548a7c91847Schristos    HUNKFUN is called with the tail of the script
549a7c91847Schristos    and returns the last link that belongs together with the start
550a7c91847Schristos    of the tail.
551a7c91847Schristos 
552a7c91847Schristos    PRINTFUN takes a subscript which belongs together (with a null
553a7c91847Schristos    link at the end) and prints it.  */
554a7c91847Schristos 
555a7c91847Schristos void
print_script(script,hunkfun,printfun)556a7c91847Schristos print_script (script, hunkfun, printfun)
557a7c91847Schristos      struct change *script;
558a7c91847Schristos      struct change * (*hunkfun) PARAMS((struct change *));
559a7c91847Schristos      void (*printfun) PARAMS((struct change *));
560a7c91847Schristos {
561a7c91847Schristos   struct change *next = script;
562a7c91847Schristos 
563a7c91847Schristos   while (next)
564a7c91847Schristos     {
565a7c91847Schristos       struct change *this, *end;
566a7c91847Schristos 
567a7c91847Schristos       /* Find a set of changes that belong together.  */
568a7c91847Schristos       this = next;
569a7c91847Schristos       end = (*hunkfun) (next);
570a7c91847Schristos 
571a7c91847Schristos       /* Disconnect them from the rest of the changes,
572a7c91847Schristos 	 making them a hunk, and remember the rest for next iteration.  */
573a7c91847Schristos       next = end->link;
574a7c91847Schristos       end->link = 0;
575a7c91847Schristos #ifdef DEBUG
576a7c91847Schristos       debug_script (this);
577a7c91847Schristos #endif
578a7c91847Schristos 
579a7c91847Schristos       /* Print this hunk.  */
580a7c91847Schristos       (*printfun) (this);
581a7c91847Schristos 
582a7c91847Schristos       /* Reconnect the script so it will all be freed properly.  */
583a7c91847Schristos       end->link = next;
584a7c91847Schristos     }
585a7c91847Schristos }
586a7c91847Schristos 
587a7c91847Schristos /* Print the text of a single line LINE,
588a7c91847Schristos    flagging it with the characters in LINE_FLAG (which say whether
589a7c91847Schristos    the line is inserted, deleted, changed, etc.).  */
590a7c91847Schristos 
591a7c91847Schristos void
print_1_line(line_flag,line)592a7c91847Schristos print_1_line (line_flag, line)
593a7c91847Schristos      char const *line_flag;
594a7c91847Schristos      char const * const *line;
595a7c91847Schristos {
596a7c91847Schristos   char const *text = line[0], *limit = line[1]; /* Help the compiler.  */
597a7c91847Schristos   char const *flag_format = 0;
598a7c91847Schristos 
599a7c91847Schristos   /* If -T was specified, use a Tab between the line-flag and the text.
600a7c91847Schristos      Otherwise use a Space (as Unix diff does).
601a7c91847Schristos      Print neither space nor tab if line-flags are empty.  */
602a7c91847Schristos 
603a7c91847Schristos   if (line_flag && *line_flag)
604a7c91847Schristos     {
605a7c91847Schristos       flag_format = tab_align_flag ? "%s\t" : "%s ";
606a7c91847Schristos       printf_output (flag_format, line_flag);
607a7c91847Schristos     }
608a7c91847Schristos 
609a7c91847Schristos   output_1_line (text, limit, flag_format, line_flag);
610a7c91847Schristos 
611a7c91847Schristos   if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
612a7c91847Schristos     printf_output ("\n\\ No newline at end of file\n");
613a7c91847Schristos }
614a7c91847Schristos 
615a7c91847Schristos /* Output a line from TEXT up to LIMIT.  Without -t, output verbatim.
616a7c91847Schristos    With -t, expand white space characters to spaces, and if FLAG_FORMAT
617a7c91847Schristos    is nonzero, output it with argument LINE_FLAG after every
618a7c91847Schristos    internal carriage return, so that tab stops continue to line up.  */
619a7c91847Schristos 
620a7c91847Schristos void
output_1_line(text,limit,flag_format,line_flag)621a7c91847Schristos output_1_line (text, limit, flag_format, line_flag)
622a7c91847Schristos      char const *text, *limit, *flag_format, *line_flag;
623a7c91847Schristos {
624a7c91847Schristos   if (!tab_expand_flag)
625a7c91847Schristos     write_output (text, limit - text);
626a7c91847Schristos   else
627a7c91847Schristos     {
628a7c91847Schristos       register unsigned char c;
629a7c91847Schristos       register char const *t = text;
630a7c91847Schristos       register unsigned column = 0;
631a7c91847Schristos       /* CC is used to avoid taking the address of the register
632a7c91847Schristos          variable C.  */
633a7c91847Schristos       char cc;
634a7c91847Schristos 
635a7c91847Schristos       while (t < limit)
636a7c91847Schristos 	switch ((c = *t++))
637a7c91847Schristos 	  {
638a7c91847Schristos 	  case '\t':
639a7c91847Schristos 	    {
640a7c91847Schristos 	      unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
641a7c91847Schristos 	      column += spaces;
642a7c91847Schristos 	      do
643a7c91847Schristos 		write_output (" ", 1);
644a7c91847Schristos 	      while (--spaces);
645a7c91847Schristos 	    }
646a7c91847Schristos 	    break;
647a7c91847Schristos 
648a7c91847Schristos 	  case '\r':
649a7c91847Schristos 	    write_output ("\r", 1);
650a7c91847Schristos 	    if (flag_format && t < limit && *t != '\n')
651a7c91847Schristos 	      printf_output (flag_format, line_flag);
652a7c91847Schristos 	    column = 0;
653a7c91847Schristos 	    break;
654a7c91847Schristos 
655a7c91847Schristos 	  case '\b':
656a7c91847Schristos 	    if (column == 0)
657a7c91847Schristos 	      continue;
658a7c91847Schristos 	    column--;
659a7c91847Schristos 	    write_output ("\b", 1);
660a7c91847Schristos 	    break;
661a7c91847Schristos 
662a7c91847Schristos 	  default:
663a7c91847Schristos 	    if (ISPRINT (c))
664a7c91847Schristos 	      column++;
665a7c91847Schristos 	    cc = c;
666a7c91847Schristos 	    write_output (&cc, 1);
667a7c91847Schristos 	    break;
668a7c91847Schristos 	  }
669a7c91847Schristos     }
670a7c91847Schristos }
671a7c91847Schristos 
672a7c91847Schristos int
change_letter(inserts,deletes)673a7c91847Schristos change_letter (inserts, deletes)
674a7c91847Schristos      int inserts, deletes;
675a7c91847Schristos {
676a7c91847Schristos   if (!inserts)
677a7c91847Schristos     return 'd';
678a7c91847Schristos   else if (!deletes)
679a7c91847Schristos     return 'a';
680a7c91847Schristos   else
681a7c91847Schristos     return 'c';
682a7c91847Schristos }
683a7c91847Schristos 
684a7c91847Schristos /* Translate an internal line number (an index into diff's table of lines)
685a7c91847Schristos    into an actual line number in the input file.
686a7c91847Schristos    The internal line number is LNUM.  FILE points to the data on the file.
687a7c91847Schristos 
688a7c91847Schristos    Internal line numbers count from 0 starting after the prefix.
689a7c91847Schristos    Actual line numbers count from 1 within the entire file.  */
690a7c91847Schristos 
691a7c91847Schristos int
translate_line_number(file,lnum)692a7c91847Schristos translate_line_number (file, lnum)
693a7c91847Schristos      struct file_data const *file;
694a7c91847Schristos      int lnum;
695a7c91847Schristos {
696a7c91847Schristos   return lnum + file->prefix_lines + 1;
697a7c91847Schristos }
698a7c91847Schristos 
699a7c91847Schristos void
translate_range(file,a,b,aptr,bptr)700a7c91847Schristos translate_range (file, a, b, aptr, bptr)
701a7c91847Schristos      struct file_data const *file;
702a7c91847Schristos      int a, b;
703a7c91847Schristos      int *aptr, *bptr;
704a7c91847Schristos {
705a7c91847Schristos   *aptr = translate_line_number (file, a - 1) + 1;
706a7c91847Schristos   *bptr = translate_line_number (file, b + 1) - 1;
707a7c91847Schristos }
708a7c91847Schristos 
709a7c91847Schristos /* Print a pair of line numbers with SEPCHAR, translated for file FILE.
710a7c91847Schristos    If the two numbers are identical, print just one number.
711a7c91847Schristos 
712a7c91847Schristos    Args A and B are internal line numbers.
713a7c91847Schristos    We print the translated (real) line numbers.  */
714a7c91847Schristos 
715a7c91847Schristos void
print_number_range(sepchar,file,a,b)716a7c91847Schristos print_number_range (sepchar, file, a, b)
717a7c91847Schristos      int sepchar;
718a7c91847Schristos      struct file_data *file;
719a7c91847Schristos      int a, b;
720a7c91847Schristos {
721a7c91847Schristos   int trans_a, trans_b;
722a7c91847Schristos   translate_range (file, a, b, &trans_a, &trans_b);
723a7c91847Schristos 
724a7c91847Schristos   /* Note: we can have B < A in the case of a range of no lines.
725a7c91847Schristos      In this case, we should print the line number before the range,
726a7c91847Schristos      which is B.  */
727a7c91847Schristos   if (trans_b > trans_a)
728a7c91847Schristos     printf_output ("%d%c%d", trans_a, sepchar, trans_b);
729a7c91847Schristos   else
730a7c91847Schristos     printf_output ("%d", trans_b);
731a7c91847Schristos }
732a7c91847Schristos 
733a7c91847Schristos /* Look at a hunk of edit script and report the range of lines in each file
734a7c91847Schristos    that it applies to.  HUNK is the start of the hunk, which is a chain
735a7c91847Schristos    of `struct change'.  The first and last line numbers of file 0 are stored in
736a7c91847Schristos    *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
737a7c91847Schristos    Note that these are internal line numbers that count from 0.
738a7c91847Schristos 
739a7c91847Schristos    If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
740a7c91847Schristos 
741a7c91847Schristos    Also set *DELETES nonzero if any lines of file 0 are deleted
742a7c91847Schristos    and set *INSERTS nonzero if any lines of file 1 are inserted.
743a7c91847Schristos    If only ignorable lines are inserted or deleted, both are
744a7c91847Schristos    set to 0.  */
745a7c91847Schristos 
746a7c91847Schristos void
analyze_hunk(hunk,first0,last0,first1,last1,deletes,inserts)747a7c91847Schristos analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
748a7c91847Schristos      struct change *hunk;
749a7c91847Schristos      int *first0, *last0, *first1, *last1;
750a7c91847Schristos      int *deletes, *inserts;
751a7c91847Schristos {
752a7c91847Schristos   int l0, l1, show_from, show_to;
753a7c91847Schristos   int i;
754a7c91847Schristos   int trivial = ignore_blank_lines_flag || ignore_regexp_list;
755a7c91847Schristos   struct change *next;
756a7c91847Schristos 
757a7c91847Schristos   show_from = show_to = 0;
758a7c91847Schristos 
759a7c91847Schristos   *first0 = hunk->line0;
760a7c91847Schristos   *first1 = hunk->line1;
761a7c91847Schristos 
762a7c91847Schristos   next = hunk;
763a7c91847Schristos   do
764a7c91847Schristos     {
765a7c91847Schristos       l0 = next->line0 + next->deleted - 1;
766a7c91847Schristos       l1 = next->line1 + next->inserted - 1;
767a7c91847Schristos       show_from += next->deleted;
768a7c91847Schristos       show_to += next->inserted;
769a7c91847Schristos 
770a7c91847Schristos       for (i = next->line0; i <= l0 && trivial; i++)
771a7c91847Schristos 	if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
772a7c91847Schristos 	  {
773a7c91847Schristos 	    struct regexp_list *r;
774a7c91847Schristos 	    char const *line = files[0].linbuf[i];
775a7c91847Schristos 	    int len = files[0].linbuf[i + 1] - line;
776a7c91847Schristos 
777a7c91847Schristos 	    for (r = ignore_regexp_list; r; r = r->next)
778a7c91847Schristos 	      if (0 <= re_search (&r->buf, line, len, 0, len, 0))
779a7c91847Schristos 		break;	/* Found a match.  Ignore this line.  */
780a7c91847Schristos 	    /* If we got all the way through the regexp list without
781a7c91847Schristos 	       finding a match, then it's nontrivial.  */
782a7c91847Schristos 	    if (!r)
783a7c91847Schristos 	      trivial = 0;
784a7c91847Schristos 	  }
785a7c91847Schristos 
786a7c91847Schristos       for (i = next->line1; i <= l1 && trivial; i++)
787a7c91847Schristos 	if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
788a7c91847Schristos 	  {
789a7c91847Schristos 	    struct regexp_list *r;
790a7c91847Schristos 	    char const *line = files[1].linbuf[i];
791a7c91847Schristos 	    int len = files[1].linbuf[i + 1] - line;
792a7c91847Schristos 
793a7c91847Schristos 	    for (r = ignore_regexp_list; r; r = r->next)
794a7c91847Schristos 	      if (0 <= re_search (&r->buf, line, len, 0, len, 0))
795a7c91847Schristos 		break;	/* Found a match.  Ignore this line.  */
796a7c91847Schristos 	    /* If we got all the way through the regexp list without
797a7c91847Schristos 	       finding a match, then it's nontrivial.  */
798a7c91847Schristos 	    if (!r)
799a7c91847Schristos 	      trivial = 0;
800a7c91847Schristos 	  }
801a7c91847Schristos     }
802a7c91847Schristos   while ((next = next->link) != 0);
803a7c91847Schristos 
804a7c91847Schristos   *last0 = l0;
805a7c91847Schristos   *last1 = l1;
806a7c91847Schristos 
807a7c91847Schristos   /* If all inserted or deleted lines are ignorable,
808a7c91847Schristos      tell the caller to ignore this hunk.  */
809a7c91847Schristos 
810a7c91847Schristos   if (trivial)
811a7c91847Schristos     show_from = show_to = 0;
812a7c91847Schristos 
813a7c91847Schristos   *deletes = show_from;
814a7c91847Schristos   *inserts = show_to;
815a7c91847Schristos }
816a7c91847Schristos 
817a7c91847Schristos /* Concatenate three strings, returning a newly malloc'd string.  */
818a7c91847Schristos 
819a7c91847Schristos char *
concat(s1,s2,s3)820a7c91847Schristos concat (s1, s2, s3)
821a7c91847Schristos      char const *s1, *s2, *s3;
822a7c91847Schristos {
823a7c91847Schristos   size_t len = strlen (s1) + strlen (s2) + strlen (s3);
824a7c91847Schristos   char *new = xmalloc (len + 1);
825a7c91847Schristos   sprintf (new, "%s%s%s", s1, s2, s3);
826a7c91847Schristos   return new;
827a7c91847Schristos }
828a7c91847Schristos 
829a7c91847Schristos /* Yield the newly malloc'd pathname
830a7c91847Schristos    of the file in DIR whose filename is FILE.  */
831a7c91847Schristos 
832a7c91847Schristos char *
dir_file_pathname(dir,file)833a7c91847Schristos dir_file_pathname (dir, file)
834a7c91847Schristos      char const *dir, *file;
835a7c91847Schristos {
836a7c91847Schristos   char const *p = filename_lastdirchar (dir);
837a7c91847Schristos   return concat (dir, "/" + (p && !p[1]), file);
838a7c91847Schristos }
839a7c91847Schristos 
840a7c91847Schristos void
debug_script(sp)841a7c91847Schristos debug_script (sp)
842a7c91847Schristos      struct change *sp;
843a7c91847Schristos {
844a7c91847Schristos   fflush (stdout);
845a7c91847Schristos   for (; sp; sp = sp->link)
846a7c91847Schristos     fprintf (stderr, "%3d %3d delete %d insert %d\n",
847a7c91847Schristos 	     sp->line0, sp->line1, sp->deleted, sp->inserted);
848a7c91847Schristos   fflush (stderr);
849a7c91847Schristos }
850