sys/dev/disk/dm: Fix typos/etc in kprintf
[dragonfly.git] / contrib / diffutils / src / util.c
1 /* Support routines for GNU DIFF.
2
3    Copyright (C) 1988-1989, 1992-1995, 1998, 2001-2002, 2004, 2006, 2009-2013
4    Free Software Foundation, Inc.
5
6    This file is part of GNU DIFF.
7
8    This program is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include "diff.h"
22 #include <dirname.h>
23 #include <error.h>
24 #include <system-quote.h>
25 #include <xalloc.h>
26 #include "xvasprintf.h"
27
28 char const pr_program[] = PR_PROGRAM;
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
33 struct msg
34 {
35   struct msg *next;
36   char args[1]; /* Format + 4 args, each '\0' terminated, concatenated.  */
37 };
38
39 /* Head of the chain of queues messages.  */
40
41 static struct msg *msg_chain;
42
43 /* Tail of the chain of queues messages.  */
44
45 static struct msg **msg_chain_end = &msg_chain;
46 \f
47 /* Use when a system call returns non-zero status.
48    NAME should normally be the file name.  */
49
50 void
51 perror_with_name (char const *name)
52 {
53   error (0, errno, "%s", name);
54 }
55
56 /* Use when a system call returns non-zero status and that is fatal.  */
57
58 void
59 pfatal_with_name (char const *name)
60 {
61   int e = errno;
62   print_message_queue ();
63   error (EXIT_TROUBLE, e, "%s", name);
64   abort ();
65 }
66
67 /* Print an error message containing MSGID, then exit.  */
68
69 void
70 fatal (char const *msgid)
71 {
72   print_message_queue ();
73   error (EXIT_TROUBLE, 0, "%s", _(msgid));
74   abort ();
75 }
76 \f
77 /* Like printf, except if -l in effect then save the message and print later.
78    This is used for things like "Only in ...".  */
79
80 void
81 message (char const *format_msgid, char const *arg1, char const *arg2)
82 {
83   message5 (format_msgid, arg1, arg2, 0, 0);
84 }
85
86 void
87 message5 (char const *format_msgid, char const *arg1, char const *arg2,
88           char const *arg3, char const *arg4)
89 {
90   if (paginate)
91     {
92       char *p;
93       char const *arg[5];
94       int i;
95       size_t size[5];
96       size_t total_size = offsetof (struct msg, args);
97       struct msg *new;
98
99       arg[0] = format_msgid;
100       arg[1] = arg1;
101       arg[2] = arg2;
102       arg[3] = arg3 ? arg3 : "";
103       arg[4] = arg4 ? arg4 : "";
104
105       for (i = 0;  i < 5;  i++)
106         total_size += size[i] = strlen (arg[i]) + 1;
107
108       new = xmalloc (total_size);
109
110       for (i = 0, p = new->args;  i < 5;  p += size[i++])
111         memcpy (p, arg[i], size[i]);
112
113       *msg_chain_end = new;
114       new->next = 0;
115       msg_chain_end = &new->next;
116     }
117   else
118     {
119       if (sdiff_merge_assist)
120         putchar (' ');
121       printf (_(format_msgid), arg1, arg2, arg3, arg4);
122     }
123 }
124
125 /* Output all the messages that were saved up by calls to 'message'.  */
126
127 void
128 print_message_queue (void)
129 {
130   char const *arg[5];
131   int i;
132   struct msg *m = msg_chain;
133
134   while (m)
135     {
136       struct msg *next = m->next;
137       arg[0] = m->args;
138       for (i = 0;  i < 4;  i++)
139         arg[i + 1] = arg[i] + strlen (arg[i]) + 1;
140       printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]);
141       free (m);
142       m = next;
143     }
144 }
145 \f
146 /* Call before outputting the results of comparing files NAME0 and NAME1
147    to set up OUTFILE, the stdio stream for the output to go to.
148
149    Usually, OUTFILE is just stdout.  But when -l was specified
150    we fork off a 'pr' and make OUTFILE a pipe to it.
151    'pr' then outputs to our stdout.  */
152
153 static char const *current_name0;
154 static char const *current_name1;
155 static bool currently_recursive;
156
157 void
158 setup_output (char const *name0, char const *name1, bool recursive)
159 {
160   current_name0 = name0;
161   current_name1 = name1;
162   currently_recursive = recursive;
163   outfile = 0;
164 }
165
166 #if HAVE_WORKING_FORK
167 static pid_t pr_pid;
168 #endif
169
170 static char c_escape_char (char c)
171 {
172   switch (c) {
173     case '\a': return 'a';
174     case '\b': return 'b';
175     case '\t': return 't';
176     case '\n': return 'n';
177     case '\v': return 'v';
178     case '\f': return 'f';
179     case '\r': return 'r';
180     case '"': return '"';
181     case '\\': return '\\';
182     default:
183       return c < 32;
184   }
185 }
186
187 static char *
188 c_escape (char const *str)
189 {
190   char const *s;
191   size_t plus = 0;
192   bool must_quote = false;
193
194   for (s = str; *s; s++)
195     {
196       char c = *s;
197
198       if (c == ' ')
199         {
200           must_quote = true;
201           continue;
202         }
203       switch (c_escape_char (*s))
204         {
205           case 1:
206             plus += 3;
207             /* fall through */
208           case 0:
209             break;
210           default:
211             plus++;
212             break;
213         }
214     }
215
216   if (must_quote || plus)
217     {
218       size_t s_len = s - str;
219       char *buffer = xmalloc (s_len + plus + 3);
220       char *b = buffer;
221
222       *b++ = '"';
223       for (s = str; *s; s++)
224         {
225           char c = *s;
226           char escape = c_escape_char (c);
227
228           switch (escape)
229             {
230               case 0:
231                 *b++ = c;
232                 break;
233               case 1:
234                 *b++ = '\\';
235                 *b++ = ((c >> 6) & 03) + '0';
236                 *b++ = ((c >> 3) & 07) + '0';
237                 *b++ = ((c >> 0) & 07) + '0';
238                 break;
239               default:
240                 *b++ = '\\';
241                 *b++ = escape;
242                 break;
243             }
244         }
245       *b++ = '"';
246       *b = 0;
247       return buffer;
248     }
249
250   return (char *) str;
251 }
252
253 void
254 begin_output (void)
255 {
256   char *names[2];
257   char *name;
258
259   if (outfile != 0)
260     return;
261
262   names[0] = c_escape (current_name0);
263   names[1] = c_escape (current_name1);
264
265   /* Construct the header of this piece of diff.  */
266   /* POSIX 1003.1-2001 specifies this format.  But there are some bugs in
267      the standard: it says that we must print only the last component
268      of the pathnames, and it requires two spaces after "diff" if
269      there are no options.  These requirements are silly and do not
270      match historical practice.  */
271   name = xasprintf ("diff%s %s %s", switch_string, names[0], names[1]);
272
273   if (paginate)
274     {
275       char const *argv[4];
276
277       if (fflush (stdout) != 0)
278         pfatal_with_name (_("write failed"));
279
280       argv[0] = pr_program;
281       argv[1] = "-h";
282       argv[2] = name;
283       argv[3] = 0;
284
285       /* Make OUTFILE a pipe to a subsidiary 'pr'.  */
286       {
287 #if HAVE_WORKING_FORK
288         int pipes[2];
289
290         if (pipe (pipes) != 0)
291           pfatal_with_name ("pipe");
292
293         pr_pid = fork ();
294         if (pr_pid < 0)
295           pfatal_with_name ("fork");
296
297         if (pr_pid == 0)
298           {
299             close (pipes[1]);
300             if (pipes[0] != STDIN_FILENO)
301               {
302                 if (dup2 (pipes[0], STDIN_FILENO) < 0)
303                   pfatal_with_name ("dup2");
304                 close (pipes[0]);
305               }
306
307             execv (pr_program, (char **) argv);
308             _exit (errno == ENOENT ? 127 : 126);
309           }
310         else
311           {
312             close (pipes[0]);
313             outfile = fdopen (pipes[1], "w");
314             if (!outfile)
315               pfatal_with_name ("fdopen");
316           }
317 #else
318         char *command = system_quote_argv (SCI_SYSTEM, (char **) argv);
319         errno = 0;
320         outfile = popen (command, "w");
321         if (!outfile)
322           pfatal_with_name (command);
323         free (command);
324 #endif
325       }
326     }
327   else
328     {
329
330       /* If -l was not specified, output the diff straight to 'stdout'.  */
331
332       outfile = stdout;
333
334       /* If handling multiple files (because scanning a directory),
335          print which files the following output is about.  */
336       if (currently_recursive)
337         printf ("%s\n", name);
338     }
339
340   free (name);
341
342   /* A special header is needed at the beginning of context output.  */
343   switch (output_style)
344     {
345     case OUTPUT_CONTEXT:
346       print_context_header (files, (char const *const *)names, false);
347       break;
348
349     case OUTPUT_UNIFIED:
350       print_context_header (files, (char const *const *)names, true);
351       break;
352
353     default:
354       break;
355     }
356
357   if (names[0] != current_name0)
358     free (names[0]);
359   if (names[1] != current_name1)
360     free (names[1]);
361 }
362
363 /* Call after the end of output of diffs for one file.
364    Close OUTFILE and get rid of the 'pr' subfork.  */
365
366 void
367 finish_output (void)
368 {
369   if (outfile != 0 && outfile != stdout)
370     {
371       int status;
372       int wstatus;
373       int werrno = 0;
374       if (ferror (outfile))
375         fatal ("write failed");
376 #if ! HAVE_WORKING_FORK
377       wstatus = pclose (outfile);
378       if (wstatus == -1)
379         werrno = errno;
380 #else
381       if (fclose (outfile) != 0)
382         pfatal_with_name (_("write failed"));
383       if (waitpid (pr_pid, &wstatus, 0) < 0)
384         pfatal_with_name ("waitpid");
385 #endif
386       status = (! werrno && WIFEXITED (wstatus)
387                 ? WEXITSTATUS (wstatus)
388                 : INT_MAX);
389       if (status)
390         error (EXIT_TROUBLE, werrno,
391                _(status == 126
392                  ? "subsidiary program '%s' could not be invoked"
393                  : status == 127
394                  ? "subsidiary program '%s' not found"
395                  : status == INT_MAX
396                  ? "subsidiary program '%s' failed"
397                  : "subsidiary program '%s' failed (exit status %d)"),
398                pr_program, status);
399     }
400
401   outfile = 0;
402 }
403 \f
404 /* Compare two lines (typically one from each input file)
405    according to the command line options.
406    For efficiency, this is invoked only when the lines do not match exactly
407    but an option like -i might cause us to ignore the difference.
408    Return nonzero if the lines differ.  */
409
410 bool
411 lines_differ (char const *s1, char const *s2)
412 {
413   register char const *t1 = s1;
414   register char const *t2 = s2;
415   size_t column = 0;
416
417   while (1)
418     {
419       register unsigned char c1 = *t1++;
420       register unsigned char c2 = *t2++;
421
422       /* Test for exact char equality first, since it's a common case.  */
423       if (c1 != c2)
424         {
425           switch (ignore_white_space)
426             {
427             case IGNORE_ALL_SPACE:
428               /* For -w, just skip past any white space.  */
429               while (isspace (c1) && c1 != '\n') c1 = *t1++;
430               while (isspace (c2) && c2 != '\n') c2 = *t2++;
431               break;
432
433             case IGNORE_SPACE_CHANGE:
434               /* For -b, advance past any sequence of white space in
435                  line 1 and consider it just one space, or nothing at
436                  all if it is at the end of the line.  */
437               if (isspace (c1))
438                 {
439                   while (c1 != '\n')
440                     {
441                       c1 = *t1++;
442                       if (! isspace (c1))
443                         {
444                           --t1;
445                           c1 = ' ';
446                           break;
447                         }
448                     }
449                 }
450
451               /* Likewise for line 2.  */
452               if (isspace (c2))
453                 {
454                   while (c2 != '\n')
455                     {
456                       c2 = *t2++;
457                       if (! isspace (c2))
458                         {
459                           --t2;
460                           c2 = ' ';
461                           break;
462                         }
463                     }
464                 }
465
466               if (c1 != c2)
467                 {
468                   /* If we went too far when doing the simple test
469                      for equality, go back to the first non-white-space
470                      character in both sides and try again.  */
471                   if (c2 == ' ' && c1 != '\n'
472                       && s1 + 1 < t1
473                       && isspace ((unsigned char) t1[-2]))
474                     {
475                       --t1;
476                       continue;
477                     }
478                   if (c1 == ' ' && c2 != '\n'
479                       && s2 + 1 < t2
480                       && isspace ((unsigned char) t2[-2]))
481                     {
482                       --t2;
483                       continue;
484                     }
485                 }
486
487               break;
488
489             case IGNORE_TRAILING_SPACE:
490             case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
491               if (isspace (c1) && isspace (c2))
492                 {
493                   unsigned char c;
494                   if (c1 != '\n')
495                     {
496                       char const *p = t1;
497                       while ((c = *p) != '\n' && isspace (c))
498                         ++p;
499                       if (c != '\n')
500                         break;
501                     }
502                   if (c2 != '\n')
503                     {
504                       char const *p = t2;
505                       while ((c = *p) != '\n' && isspace (c))
506                         ++p;
507                       if (c != '\n')
508                         break;
509                     }
510                   /* Both lines have nothing but whitespace left.  */
511                   return false;
512                 }
513               if (ignore_white_space == IGNORE_TRAILING_SPACE)
514                 break;
515               /* Fall through.  */
516             case IGNORE_TAB_EXPANSION:
517               if ((c1 == ' ' && c2 == '\t')
518                   || (c1 == '\t' && c2 == ' '))
519                 {
520                   size_t column2 = column;
521                   for (;; c1 = *t1++)
522                     {
523                       if (c1 == ' ')
524                         column++;
525                       else if (c1 == '\t')
526                         column += tabsize - column % tabsize;
527                       else
528                         break;
529                     }
530                   for (;; c2 = *t2++)
531                     {
532                       if (c2 == ' ')
533                         column2++;
534                       else if (c2 == '\t')
535                         column2 += tabsize - column2 % tabsize;
536                       else
537                         break;
538                     }
539                   if (column != column2)
540                     return true;
541                 }
542               break;
543
544             case IGNORE_NO_WHITE_SPACE:
545               break;
546             }
547
548           /* Lowercase all letters if -i is specified.  */
549
550           if (ignore_case)
551             {
552               c1 = tolower (c1);
553               c2 = tolower (c2);
554             }
555
556           if (c1 != c2)
557             break;
558         }
559       if (c1 == '\n')
560         return false;
561
562       column += c1 == '\t' ? tabsize - column % tabsize : 1;
563     }
564
565   return true;
566 }
567 \f
568 /* Find the consecutive changes at the start of the script START.
569    Return the last link before the first gap.  */
570
571 struct change * _GL_ATTRIBUTE_CONST
572 find_change (struct change *start)
573 {
574   return start;
575 }
576
577 struct change * _GL_ATTRIBUTE_CONST
578 find_reverse_change (struct change *start)
579 {
580   return start;
581 }
582 \f
583 /* Divide SCRIPT into pieces by calling HUNKFUN and
584    print each piece with PRINTFUN.
585    Both functions take one arg, an edit script.
586
587    HUNKFUN is called with the tail of the script
588    and returns the last link that belongs together with the start
589    of the tail.
590
591    PRINTFUN takes a subscript which belongs together (with a null
592    link at the end) and prints it.  */
593
594 void
595 print_script (struct change *script,
596               struct change * (*hunkfun) (struct change *),
597               void (*printfun) (struct change *))
598 {
599   struct change *next = script;
600
601   while (next)
602     {
603       struct change *this, *end;
604
605       /* Find a set of changes that belong together.  */
606       this = next;
607       end = (*hunkfun) (next);
608
609       /* Disconnect them from the rest of the changes,
610          making them a hunk, and remember the rest for next iteration.  */
611       next = end->link;
612       end->link = 0;
613 #ifdef DEBUG
614       debug_script (this);
615 #endif
616
617       /* Print this hunk.  */
618       (*printfun) (this);
619
620       /* Reconnect the script so it will all be freed properly.  */
621       end->link = next;
622     }
623 }
624 \f
625 /* Print the text of a single line LINE,
626    flagging it with the characters in LINE_FLAG (which say whether
627    the line is inserted, deleted, changed, etc.).  LINE_FLAG must not
628    end in a blank, unless it is a single blank.  */
629
630 void
631 print_1_line (char const *line_flag, char const *const *line)
632 {
633   char const *base = line[0], *limit = line[1]; /* Help the compiler.  */
634   FILE *out = outfile; /* Help the compiler some more.  */
635   char const *flag_format = 0;
636
637   /* If -T was specified, use a Tab between the line-flag and the text.
638      Otherwise use a Space (as Unix diff does).
639      Print neither space nor tab if line-flags are empty.
640      But omit trailing blanks if requested.  */
641
642   if (line_flag && *line_flag)
643     {
644       char const *flag_format_1 = flag_format = initial_tab ? "%s\t" : "%s ";
645       char const *line_flag_1 = line_flag;
646
647       if (suppress_blank_empty && **line == '\n')
648         {
649           flag_format_1 = "%s";
650
651           /* This hack to omit trailing blanks takes advantage of the
652              fact that the only way that LINE_FLAG can end in a blank
653              is when LINE_FLAG consists of a single blank.  */
654           line_flag_1 += *line_flag_1 == ' ';
655         }
656
657       fprintf (out, flag_format_1, line_flag_1);
658     }
659
660   output_1_line (base, limit, flag_format, line_flag);
661
662   if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
663     fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
664 }
665
666 /* Output a line from BASE up to LIMIT.
667    With -t, expand white space characters to spaces, and if FLAG_FORMAT
668    is nonzero, output it with argument LINE_FLAG after every
669    internal carriage return, so that tab stops continue to line up.  */
670
671 void
672 output_1_line (char const *base, char const *limit, char const *flag_format,
673                char const *line_flag)
674 {
675   if (!expand_tabs)
676     fwrite (base, sizeof (char), limit - base, outfile);
677   else
678     {
679       register FILE *out = outfile;
680       register unsigned char c;
681       register char const *t = base;
682       register size_t column = 0;
683       size_t tab_size = tabsize;
684
685       while (t < limit)
686         switch ((c = *t++))
687           {
688           case '\t':
689             {
690               size_t spaces = tab_size - column % tab_size;
691               column += spaces;
692               do
693                 putc (' ', out);
694               while (--spaces);
695             }
696             break;
697
698           case '\r':
699             putc (c, out);
700             if (flag_format && t < limit && *t != '\n')
701               fprintf (out, flag_format, line_flag);
702             column = 0;
703             break;
704
705           case '\b':
706             if (column == 0)
707               continue;
708             column--;
709             putc (c, out);
710             break;
711
712           default:
713             column += isprint (c) != 0;
714             putc (c, out);
715             break;
716           }
717     }
718 }
719
720 char const change_letter[] = { 0, 'd', 'a', 'c' };
721 \f
722 /* Translate an internal line number (an index into diff's table of lines)
723    into an actual line number in the input file.
724    The internal line number is I.  FILE points to the data on the file.
725
726    Internal line numbers count from 0 starting after the prefix.
727    Actual line numbers count from 1 within the entire file.  */
728
729 lin _GL_ATTRIBUTE_PURE
730 translate_line_number (struct file_data const *file, lin i)
731 {
732   return i + file->prefix_lines + 1;
733 }
734
735 /* Translate a line number range.  This is always done for printing,
736    so for convenience translate to long int rather than lin, so that the
737    caller can use printf with "%ld" without casting.  */
738
739 void
740 translate_range (struct file_data const *file,
741                  lin a, lin b,
742                  long int *aptr, long int *bptr)
743 {
744   *aptr = translate_line_number (file, a - 1) + 1;
745   *bptr = translate_line_number (file, b + 1) - 1;
746 }
747
748 /* Print a pair of line numbers with SEPCHAR, translated for file FILE.
749    If the two numbers are identical, print just one number.
750
751    Args A and B are internal line numbers.
752    We print the translated (real) line numbers.  */
753
754 void
755 print_number_range (char sepchar, struct file_data *file, lin a, lin b)
756 {
757   long int trans_a, trans_b;
758   translate_range (file, a, b, &trans_a, &trans_b);
759
760   /* Note: we can have B < A in the case of a range of no lines.
761      In this case, we should print the line number before the range,
762      which is B.  */
763   if (trans_b > trans_a)
764     fprintf (outfile, "%ld%c%ld", trans_a, sepchar, trans_b);
765   else
766     fprintf (outfile, "%ld", trans_b);
767 }
768 \f
769 /* Look at a hunk of edit script and report the range of lines in each file
770    that it applies to.  HUNK is the start of the hunk, which is a chain
771    of 'struct change'.  The first and last line numbers of file 0 are stored in
772    *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
773    Note that these are internal line numbers that count from 0.
774
775    If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
776
777    Return UNCHANGED if only ignorable lines are inserted or deleted,
778    OLD if lines of file 0 are deleted,
779    NEW if lines of file 1 are inserted,
780    and CHANGED if both kinds of changes are found. */
781
782 enum changes
783 analyze_hunk (struct change *hunk,
784               lin *first0, lin *last0,
785               lin *first1, lin *last1)
786 {
787   struct change *next;
788   lin l0, l1;
789   lin show_from, show_to;
790   lin i;
791   bool trivial = ignore_blank_lines || ignore_regexp.fastmap;
792   size_t trivial_length = ignore_blank_lines - 1;
793     /* If 0, ignore zero-length lines;
794        if SIZE_MAX, do not ignore lines just because of their length.  */
795
796   bool skip_white_space =
797     ignore_blank_lines && IGNORE_TRAILING_SPACE <= ignore_white_space;
798   bool skip_leading_white_space =
799     skip_white_space && IGNORE_SPACE_CHANGE <= ignore_white_space;
800
801   char const * const *linbuf0 = files[0].linbuf;  /* Help the compiler.  */
802   char const * const *linbuf1 = files[1].linbuf;
803
804   show_from = show_to = 0;
805
806   *first0 = hunk->line0;
807   *first1 = hunk->line1;
808
809   next = hunk;
810   do
811     {
812       l0 = next->line0 + next->deleted - 1;
813       l1 = next->line1 + next->inserted - 1;
814       show_from += next->deleted;
815       show_to += next->inserted;
816
817       for (i = next->line0; i <= l0 && trivial; i++)
818         {
819           char const *line = linbuf0[i];
820           char const *newline = linbuf0[i + 1] - 1;
821           size_t len = newline - line;
822           char const *p = line;
823           if (skip_white_space)
824             for (; *p != '\n'; p++)
825               if (! isspace ((unsigned char) *p))
826                 {
827                   if (! skip_leading_white_space)
828                     p = line;
829                   break;
830                 }
831           if (newline - p != trivial_length
832               && (! ignore_regexp.fastmap
833                   || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
834             trivial = 0;
835         }
836
837       for (i = next->line1; i <= l1 && trivial; i++)
838         {
839           char const *line = linbuf1[i];
840           char const *newline = linbuf1[i + 1] - 1;
841           size_t len = newline - line;
842           char const *p = line;
843           if (skip_white_space)
844             for (; *p != '\n'; p++)
845               if (! isspace ((unsigned char) *p))
846                 {
847                   if (! skip_leading_white_space)
848                     p = line;
849                   break;
850                 }
851           if (newline - p != trivial_length
852               && (! ignore_regexp.fastmap
853                   || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
854             trivial = 0;
855         }
856     }
857   while ((next = next->link) != 0);
858
859   *last0 = l0;
860   *last1 = l1;
861
862   /* If all inserted or deleted lines are ignorable,
863      tell the caller to ignore this hunk.  */
864
865   if (trivial)
866     return UNCHANGED;
867
868   return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED);
869 }
870 \f
871 /* Concatenate three strings, returning a newly malloc'd string.  */
872
873 char *
874 concat (char const *s1, char const *s2, char const *s3)
875 {
876   char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
877   sprintf (new, "%s%s%s", s1, s2, s3);
878   return new;
879 }
880
881 /* Yield a new block of SIZE bytes, initialized to zero.  */
882
883 void *
884 zalloc (size_t size)
885 {
886   void *p = xmalloc (size);
887   memset (p, 0, size);
888   return p;
889 }
890 \f
891 void
892 debug_script (struct change *sp)
893 {
894   fflush (stdout);
895
896   for (; sp; sp = sp->link)
897     {
898       long int line0 = sp->line0;
899       long int line1 = sp->line1;
900       long int deleted = sp->deleted;
901       long int inserted = sp->inserted;
902       fprintf (stderr, "%3ld %3ld delete %ld insert %ld\n",
903                line0, line1, deleted, inserted);
904     }
905
906   fflush (stderr);
907 }