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