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