Bug Summary

File:src/gnu/usr.bin/cvs/diff/util.c
Warning:line 230, column 4
This function call is prohibited after a successful vfork

Annotated Source Code

Press '?' to see keyboard shortcuts

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