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