Blame src/util.c

Packit Service fdd496
/* Support routines for GNU DIFF.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1988-1989, 1992-1995, 1998, 2001-2002, 2004, 2006, 2009-2013,
Packit Service fdd496
   2015-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This file is part of GNU DIFF.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation, either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
#include "diff.h"
Packit Service fdd496
#include "argmatch.h"
Packit Service fdd496
#include "die.h"
Packit Service fdd496
#include <dirname.h>
Packit Service fdd496
#include <error.h>
Packit Service fdd496
#include <system-quote.h>
Packit Service fdd496
#include <xalloc.h>
Packit Service fdd496
#include "xvasprintf.h"
Packit Service fdd496
#include <signal.h>
Packit Service fdd496
Packit Service fdd496
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
Packit Service fdd496
   present.  */
Packit Service fdd496
#ifndef SA_NOCLDSTOP
Packit Service fdd496
# define SA_NOCLDSTOP 0
Packit Service fdd496
# define sigprocmask(How, Set, Oset) /* empty */
Packit Service fdd496
# define sigset_t int
Packit Service fdd496
# if ! HAVE_SIGINTERRUPT
Packit Service fdd496
#  define siginterrupt(sig, flag) /* empty */
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifndef SA_RESTART
Packit Service fdd496
# define SA_RESTART 0
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
char const pr_program[] = PR_PROGRAM;
Packit Service fdd496
Packit Service fdd496
/* Queue up one-line messages to be printed at the end,
Packit Service fdd496
   when -l is specified.  Each message is recorded with a 'struct msg'.  */
Packit Service fdd496
Packit Service fdd496
struct msg
Packit Service fdd496
{
Packit Service fdd496
  struct msg *next;
Packit Service fdd496
  char args[1]; /* Format + 4 args, each '\0' terminated, concatenated.  */
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
/* Head of the chain of queues messages.  */
Packit Service fdd496
Packit Service fdd496
static struct msg *msg_chain;
Packit Service fdd496
Packit Service fdd496
/* Tail of the chain of queues messages.  */
Packit Service fdd496
Packit Service fdd496
static struct msg **msg_chain_end = &msg_chain;
Packit Service fdd496

Packit Service fdd496
/* Use when a system call returns non-zero status.
Packit Service fdd496
   NAME should normally be the file name.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
perror_with_name (char const *name)
Packit Service fdd496
{
Packit Service fdd496
  error (0, errno, "%s", name);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Use when a system call returns non-zero status and that is fatal.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
pfatal_with_name (char const *name)
Packit Service fdd496
{
Packit Service fdd496
  int e = errno;
Packit Service fdd496
  print_message_queue ();
Packit Service fdd496
  die (EXIT_TROUBLE, e, "%s", name);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print an error message containing MSGID, then exit.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
fatal (char const *msgid)
Packit Service fdd496
{
Packit Service fdd496
  print_message_queue ();
Packit Service fdd496
  die (EXIT_TROUBLE, 0, "%s", _(msgid));
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Like printf, except if -l in effect then save the message and print later.
Packit Service fdd496
   This is used for things like "Only in ...".  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
message (char const *format_msgid, char const *arg1, char const *arg2)
Packit Service fdd496
{
Packit Service fdd496
  message5 (format_msgid, arg1, arg2, 0, 0);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
message5 (char const *format_msgid, char const *arg1, char const *arg2,
Packit Service fdd496
	  char const *arg3, char const *arg4)
Packit Service fdd496
{
Packit Service fdd496
  if (paginate)
Packit Service fdd496
    {
Packit Service fdd496
      char *p;
Packit Service fdd496
      char const *arg[5];
Packit Service fdd496
      int i;
Packit Service fdd496
      size_t size[5];
Packit Service fdd496
      size_t total_size = offsetof (struct msg, args);
Packit Service fdd496
      struct msg *new;
Packit Service fdd496
Packit Service fdd496
      arg[0] = format_msgid;
Packit Service fdd496
      arg[1] = arg1;
Packit Service fdd496
      arg[2] = arg2;
Packit Service fdd496
      arg[3] = arg3 ? arg3 : "";
Packit Service fdd496
      arg[4] = arg4 ? arg4 : "";
Packit Service fdd496
Packit Service fdd496
      for (i = 0;  i < 5;  i++)
Packit Service fdd496
	total_size += size[i] = strlen (arg[i]) + 1;
Packit Service fdd496
Packit Service fdd496
      new = xmalloc (total_size);
Packit Service fdd496
Packit Service fdd496
      for (i = 0, p = new->args;  i < 5;  p += size[i++])
Packit Service fdd496
	memcpy (p, arg[i], size[i]);
Packit Service fdd496
Packit Service fdd496
      *msg_chain_end = new;
Packit Service fdd496
      new->next = 0;
Packit Service fdd496
      msg_chain_end = &new->next;
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      if (sdiff_merge_assist)
Packit Service fdd496
	putchar (' ');
Packit Service fdd496
      printf (_(format_msgid), arg1, arg2, arg3, arg4);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Output all the messages that were saved up by calls to 'message'.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_message_queue (void)
Packit Service fdd496
{
Packit Service fdd496
  char const *arg[5];
Packit Service fdd496
  int i;
Packit Service fdd496
  struct msg *m = msg_chain;
Packit Service fdd496
Packit Service fdd496
  while (m)
Packit Service fdd496
    {
Packit Service fdd496
      struct msg *next = m->next;
Packit Service fdd496
      arg[0] = m->args;
Packit Service fdd496
      for (i = 0;  i < 4;  i++)
Packit Service fdd496
	arg[i + 1] = arg[i] + strlen (arg[i]) + 1;
Packit Service fdd496
      printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]);
Packit Service fdd496
      free (m);
Packit Service fdd496
      m = next;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* The set of signals that are caught.  */
Packit Service fdd496
Packit Service fdd496
static sigset_t caught_signals;
Packit Service fdd496
Packit Service fdd496
/* If nonzero, the value of the pending fatal signal.  */
Packit Service fdd496
Packit Service fdd496
static sig_atomic_t volatile interrupt_signal;
Packit Service fdd496
Packit Service fdd496
/* A count of the number of pending stop signals that have been received.  */
Packit Service fdd496
Packit Service fdd496
static sig_atomic_t volatile stop_signal_count;
Packit Service fdd496
Packit Service fdd496
/* An ordinary signal was received; arrange for the program to exit.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
sighandler (int sig)
Packit Service fdd496
{
Packit Service fdd496
  if (! SA_NOCLDSTOP)
Packit Service fdd496
    signal (sig, SIG_IGN);
Packit Service fdd496
  if (! interrupt_signal)
Packit Service fdd496
    interrupt_signal = sig;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* A SIGTSTP was received; arrange for the program to suspend itself.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
stophandler (int sig)
Packit Service fdd496
{
Packit Service fdd496
  if (! SA_NOCLDSTOP)
Packit Service fdd496
    signal (sig, stophandler);
Packit Service fdd496
  if (! interrupt_signal)
Packit Service fdd496
    stop_signal_count++;
Packit Service fdd496
}
Packit Service fdd496
/* Process any pending signals.  If signals are caught, this function
Packit Service fdd496
   should be called periodically.  Ideally there should never be an
Packit Service fdd496
   unbounded amount of time when signals are not being processed.
Packit Service fdd496
   Signal handling can restore the default colors, so callers must
Packit Service fdd496
   immediately change colors after invoking this function.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
process_signals (void)
Packit Service fdd496
{
Packit Service fdd496
  while (interrupt_signal || stop_signal_count)
Packit Service fdd496
    {
Packit Service fdd496
      int sig;
Packit Service fdd496
      int stops;
Packit Service fdd496
      sigset_t oldset;
Packit Service fdd496
Packit Service fdd496
      set_color_context (RESET_CONTEXT);
Packit Service fdd496
      fflush (stdout);
Packit Service fdd496
Packit Service fdd496
      sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
Packit Service fdd496
Packit Service fdd496
      /* Reload interrupt_signal and stop_signal_count, in case a new
Packit Service fdd496
         signal was handled before sigprocmask took effect.  */
Packit Service fdd496
      sig = interrupt_signal;
Packit Service fdd496
      stops = stop_signal_count;
Packit Service fdd496
Packit Service fdd496
      /* SIGTSTP is special, since the application can receive that signal
Packit Service fdd496
         more than once.  In this case, don't set the signal handler to the
Packit Service fdd496
         default.  Instead, just raise the uncatchable SIGSTOP.  */
Packit Service fdd496
      if (stops)
Packit Service fdd496
        {
Packit Service fdd496
          stop_signal_count = stops - 1;
Packit Service fdd496
          sig = SIGSTOP;
Packit Service fdd496
        }
Packit Service fdd496
      else
Packit Service fdd496
        signal (sig, SIG_DFL);
Packit Service fdd496
Packit Service fdd496
      /* Exit or suspend the program.  */
Packit Service fdd496
      raise (sig);
Packit Service fdd496
      sigprocmask (SIG_SETMASK, &oldset, NULL);
Packit Service fdd496
Packit Service fdd496
      /* If execution reaches here, then the program has been
Packit Service fdd496
         continued (after being suspended).  */
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
install_signal_handlers (void)
Packit Service fdd496
{
Packit Service fdd496
  /* The signals that are trapped, and the number of such signals.  */
Packit Service fdd496
  static int const sig[] =
Packit Service fdd496
    {
Packit Service fdd496
      /* This one is handled specially.  */
Packit Service fdd496
      SIGTSTP,
Packit Service fdd496
Packit Service fdd496
      /* The usual suspects.  */
Packit Service fdd496
      SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
Packit Service fdd496
#ifdef SIGPOLL
Packit Service fdd496
      SIGPOLL,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGPROF
Packit Service fdd496
      SIGPROF,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGVTALRM
Packit Service fdd496
      SIGVTALRM,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGXCPU
Packit Service fdd496
      SIGXCPU,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGXFSZ
Packit Service fdd496
      SIGXFSZ,
Packit Service fdd496
#endif
Packit Service fdd496
    };
Packit Service fdd496
  enum { nsigs = sizeof (sig) / sizeof *(sig) };
Packit Service fdd496
Packit Service fdd496
#if ! SA_NOCLDSTOP
Packit Service fdd496
  bool caught_sig[nsigs];
Packit Service fdd496
#endif
Packit Service fdd496
  {
Packit Service fdd496
    int j;
Packit Service fdd496
#if SA_NOCLDSTOP
Packit Service fdd496
    struct sigaction act;
Packit Service fdd496
Packit Service fdd496
    sigemptyset (&caught_signals);
Packit Service fdd496
    for (j = 0; j < nsigs; j++)
Packit Service fdd496
      {
Packit Service fdd496
        sigaction (sig[j], NULL, &act;;
Packit Service fdd496
        if (act.sa_handler != SIG_IGN)
Packit Service fdd496
          sigaddset (&caught_signals, sig[j]);
Packit Service fdd496
      }
Packit Service fdd496
Packit Service fdd496
    act.sa_mask = caught_signals;
Packit Service fdd496
    act.sa_flags = SA_RESTART;
Packit Service fdd496
Packit Service fdd496
    for (j = 0; j < nsigs; j++)
Packit Service fdd496
      if (sigismember (&caught_signals, sig[j]))
Packit Service fdd496
        {
Packit Service fdd496
          act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler;
Packit Service fdd496
          sigaction (sig[j], &act, NULL);
Packit Service fdd496
        }
Packit Service fdd496
#else
Packit Service fdd496
    for (j = 0; j < nsigs; j++)
Packit Service fdd496
      {
Packit Service fdd496
        caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN);
Packit Service fdd496
        if (caught_sig[j])
Packit Service fdd496
          {
Packit Service fdd496
            signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler);
Packit Service fdd496
            siginterrupt (sig[j], 0);
Packit Service fdd496
          }
Packit Service fdd496
      }
Packit Service fdd496
#endif
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char const *current_name0;
Packit Service fdd496
static char const *current_name1;
Packit Service fdd496
static bool currently_recursive;
Packit Service fdd496
static bool colors_enabled;
Packit Service fdd496
Packit Service fdd496
static struct color_ext_type *color_ext_list = NULL;
Packit Service fdd496
Packit Service fdd496
struct bin_str
Packit Service fdd496
  {
Packit Service fdd496
    size_t len;			/* Number of bytes */
Packit Service fdd496
    const char *string;		/* Pointer to the same */
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
struct color_ext_type
Packit Service fdd496
  {
Packit Service fdd496
    struct bin_str ext;		/* The extension we're looking for */
Packit Service fdd496
    struct bin_str seq;		/* The sequence to output when we do */
Packit Service fdd496
    struct color_ext_type *next;	/* Next in list */
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
/* Parse a string as part of the --palette argument; this may involve
Packit Service fdd496
   decoding all kinds of escape characters.  If equals_end is set an
Packit Service fdd496
   unescaped equal sign ends the string, otherwise only a : or \0
Packit Service fdd496
   does.  Set *OUTPUT_COUNT to the number of bytes output.  Return
Packit Service fdd496
   true if successful.
Packit Service fdd496
Packit Service fdd496
   The resulting string is *not* null-terminated, but may contain
Packit Service fdd496
   embedded nulls.
Packit Service fdd496
Packit Service fdd496
   Note that both dest and src are char **; on return they point to
Packit Service fdd496
   the first free byte after the array and the character that ended
Packit Service fdd496
   the input string, respectively.  */
Packit Service fdd496
Packit Service fdd496
static bool
Packit Service fdd496
get_funky_string (char **dest, const char **src, bool equals_end,
Packit Service fdd496
                  size_t *output_count)
Packit Service fdd496
{
Packit Service fdd496
  char num;			/* For numerical codes */
Packit Service fdd496
  size_t count;			/* Something to count with */
Packit Service fdd496
  enum {
Packit Service fdd496
    ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
Packit Service fdd496
  } state;
Packit Service fdd496
  const char *p;
Packit Service fdd496
  char *q;
Packit Service fdd496
Packit Service fdd496
  p = *src;			/* We don't want to double-indirect */
Packit Service fdd496
  q = *dest;			/* the whole darn time.  */
Packit Service fdd496
Packit Service fdd496
  count = 0;			/* No characters counted in yet.  */
Packit Service fdd496
  num = 0;
Packit Service fdd496
Packit Service fdd496
  state = ST_GND;		/* Start in ground state.  */
Packit Service fdd496
  while (state < ST_END)
Packit Service fdd496
    {
Packit Service fdd496
      switch (state)
Packit Service fdd496
        {
Packit Service fdd496
        case ST_GND:		/* Ground state (no escapes) */
Packit Service fdd496
          switch (*p)
Packit Service fdd496
            {
Packit Service fdd496
            case ':':
Packit Service fdd496
            case '\0':
Packit Service fdd496
              state = ST_END;	/* End of string */
Packit Service fdd496
              break;
Packit Service fdd496
            case '\\':
Packit Service fdd496
              state = ST_BACKSLASH; /* Backslash scape sequence */
Packit Service fdd496
              ++p;
Packit Service fdd496
              break;
Packit Service fdd496
            case '^':
Packit Service fdd496
              state = ST_CARET; /* Caret escape */
Packit Service fdd496
              ++p;
Packit Service fdd496
              break;
Packit Service fdd496
            case '=':
Packit Service fdd496
              if (equals_end)
Packit Service fdd496
                {
Packit Service fdd496
                  state = ST_END; /* End */
Packit Service fdd496
                  break;
Packit Service fdd496
                }
Packit Service fdd496
              FALLTHROUGH;
Packit Service fdd496
            default:
Packit Service fdd496
              *(q++) = *(p++);
Packit Service fdd496
              ++count;
Packit Service fdd496
              break;
Packit Service fdd496
            }
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case ST_BACKSLASH:	/* Backslash escaped character */
Packit Service fdd496
          switch (*p)
Packit Service fdd496
            {
Packit Service fdd496
            case '0':
Packit Service fdd496
            case '1':
Packit Service fdd496
            case '2':
Packit Service fdd496
            case '3':
Packit Service fdd496
            case '4':
Packit Service fdd496
            case '5':
Packit Service fdd496
            case '6':
Packit Service fdd496
            case '7':
Packit Service fdd496
              state = ST_OCTAL;	/* Octal sequence */
Packit Service fdd496
              num = *p - '0';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'x':
Packit Service fdd496
            case 'X':
Packit Service fdd496
              state = ST_HEX;	/* Hex sequence */
Packit Service fdd496
              num = 0;
Packit Service fdd496
              break;
Packit Service fdd496
            case 'a':		/* Bell */
Packit Service fdd496
              num = '\a';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'b':		/* Backspace */
Packit Service fdd496
              num = '\b';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'e':		/* Escape */
Packit Service fdd496
              num = 27;
Packit Service fdd496
              break;
Packit Service fdd496
            case 'f':		/* Form feed */
Packit Service fdd496
              num = '\f';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'n':		/* Newline */
Packit Service fdd496
              num = '\n';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'r':		/* Carriage return */
Packit Service fdd496
              num = '\r';
Packit Service fdd496
              break;
Packit Service fdd496
            case 't':		/* Tab */
Packit Service fdd496
              num = '\t';
Packit Service fdd496
              break;
Packit Service fdd496
            case 'v':		/* Vtab */
Packit Service fdd496
              num = '\v';
Packit Service fdd496
              break;
Packit Service fdd496
            case '?':		/* Delete */
Packit Service fdd496
              num = 127;
Packit Service fdd496
              break;
Packit Service fdd496
            case '_':		/* Space */
Packit Service fdd496
              num = ' ';
Packit Service fdd496
              break;
Packit Service fdd496
            case '\0':		/* End of string */
Packit Service fdd496
              state = ST_ERROR;	/* Error! */
Packit Service fdd496
              break;
Packit Service fdd496
            default:		/* Escaped character like \ ^ : = */
Packit Service fdd496
              num = *p;
Packit Service fdd496
              break;
Packit Service fdd496
            }
Packit Service fdd496
          if (state == ST_BACKSLASH)
Packit Service fdd496
            {
Packit Service fdd496
              *(q++) = num;
Packit Service fdd496
              ++count;
Packit Service fdd496
              state = ST_GND;
Packit Service fdd496
            }
Packit Service fdd496
          ++p;
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case ST_OCTAL:		/* Octal sequence */
Packit Service fdd496
          if (*p < '0' || *p > '7')
Packit Service fdd496
            {
Packit Service fdd496
              *(q++) = num;
Packit Service fdd496
              ++count;
Packit Service fdd496
              state = ST_GND;
Packit Service fdd496
            }
Packit Service fdd496
          else
Packit Service fdd496
            num = (num << 3) + (*(p++) - '0');
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case ST_HEX:		/* Hex sequence */
Packit Service fdd496
          switch (*p)
Packit Service fdd496
            {
Packit Service fdd496
            case '0':
Packit Service fdd496
            case '1':
Packit Service fdd496
            case '2':
Packit Service fdd496
            case '3':
Packit Service fdd496
            case '4':
Packit Service fdd496
            case '5':
Packit Service fdd496
            case '6':
Packit Service fdd496
            case '7':
Packit Service fdd496
            case '8':
Packit Service fdd496
            case '9':
Packit Service fdd496
              num = (num << 4) + (*(p++) - '0');
Packit Service fdd496
              break;
Packit Service fdd496
            case 'a':
Packit Service fdd496
            case 'b':
Packit Service fdd496
            case 'c':
Packit Service fdd496
            case 'd':
Packit Service fdd496
            case 'e':
Packit Service fdd496
            case 'f':
Packit Service fdd496
              num = (num << 4) + (*(p++) - 'a') + 10;
Packit Service fdd496
              break;
Packit Service fdd496
            case 'A':
Packit Service fdd496
            case 'B':
Packit Service fdd496
            case 'C':
Packit Service fdd496
            case 'D':
Packit Service fdd496
            case 'E':
Packit Service fdd496
            case 'F':
Packit Service fdd496
              num = (num << 4) + (*(p++) - 'A') + 10;
Packit Service fdd496
              break;
Packit Service fdd496
            default:
Packit Service fdd496
              *(q++) = num;
Packit Service fdd496
              ++count;
Packit Service fdd496
              state = ST_GND;
Packit Service fdd496
              break;
Packit Service fdd496
            }
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case ST_CARET:		/* Caret escape */
Packit Service fdd496
          state = ST_GND;	/* Should be the next state... */
Packit Service fdd496
          if (*p >= '@' && *p <= '~')
Packit Service fdd496
            {
Packit Service fdd496
              *(q++) = *(p++) & 037;
Packit Service fdd496
              ++count;
Packit Service fdd496
            }
Packit Service fdd496
          else if (*p == '?')
Packit Service fdd496
            {
Packit Service fdd496
              *(q++) = 127;
Packit Service fdd496
              ++count;
Packit Service fdd496
            }
Packit Service fdd496
          else
Packit Service fdd496
            state = ST_ERROR;
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        default:
Packit Service fdd496
          abort ();
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  *dest = q;
Packit Service fdd496
  *src = p;
Packit Service fdd496
  *output_count = count;
Packit Service fdd496
Packit Service fdd496
  return state != ST_ERROR;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
enum parse_state
Packit Service fdd496
  {
Packit Service fdd496
    PS_START = 1,
Packit Service fdd496
    PS_2,
Packit Service fdd496
    PS_3,
Packit Service fdd496
    PS_4,
Packit Service fdd496
    PS_DONE,
Packit Service fdd496
    PS_FAIL
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
#define LEN_STR_PAIR(s) sizeof (s) - 1, s
Packit Service fdd496
Packit Service fdd496
static struct bin_str color_indicator[] =
Packit Service fdd496
  {
Packit Service fdd496
    { LEN_STR_PAIR ("\033[") },		/* lc: Left of color sequence */
Packit Service fdd496
    { LEN_STR_PAIR ("m") },		/* rc: Right of color sequence */
Packit Service fdd496
    { 0, NULL },			/* ec: End color (replaces lc+rs+rc) */
Packit Service fdd496
    { LEN_STR_PAIR ("0") },		/* rs: Reset to ordinary colors */
Packit Service fdd496
    { LEN_STR_PAIR ("1") },		/* hd: Header */
Packit Service fdd496
    { LEN_STR_PAIR ("32") },		/* ad: Add line */
Packit Service fdd496
    { LEN_STR_PAIR ("31") },		/* de: Delete line */
Packit Service fdd496
    { LEN_STR_PAIR ("36") },		/* ln: Line number */
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
static const char *const indicator_name[] =
Packit Service fdd496
  {
Packit Service fdd496
    "lc", "rc", "ec", "rs", "hd", "ad", "de", "ln", NULL
Packit Service fdd496
  };
Packit Service fdd496
ARGMATCH_VERIFY (indicator_name, color_indicator);
Packit Service fdd496
Packit Service fdd496
static char const *color_palette;
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
set_color_palette (char const *palette)
Packit Service fdd496
{
Packit Service fdd496
  color_palette = palette;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
parse_diff_color (void)
Packit Service fdd496
{
Packit Service fdd496
  char *color_buf;
Packit Service fdd496
  const char *p;		/* Pointer to character being parsed */
Packit Service fdd496
  char *buf;			/* color_buf buffer pointer */
Packit Service fdd496
  int ind_no;			/* Indicator number */
Packit Service fdd496
  char label[3];		/* Indicator label */
Packit Service fdd496
  struct color_ext_type *ext;	/* Extension we are working on */
Packit Service fdd496
Packit Service fdd496
  if ((p = color_palette) == NULL || *p == '\0')
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  ext = NULL;
Packit Service fdd496
  strcpy (label, "??");
Packit Service fdd496
Packit Service fdd496
  /* This is an overly conservative estimate, but any possible
Packit Service fdd496
     --palette string will *not* generate a color_buf longer than
Packit Service fdd496
     itself, so it is a safe way of allocating a buffer in
Packit Service fdd496
     advance.  */
Packit Service fdd496
  buf = color_buf = xstrdup (p);
Packit Service fdd496
Packit Service fdd496
  enum parse_state state = PS_START;
Packit Service fdd496
  while (true)
Packit Service fdd496
    {
Packit Service fdd496
      switch (state)
Packit Service fdd496
        {
Packit Service fdd496
        case PS_START:		/* First label character */
Packit Service fdd496
          switch (*p)
Packit Service fdd496
            {
Packit Service fdd496
            case ':':
Packit Service fdd496
              ++p;
Packit Service fdd496
              break;
Packit Service fdd496
Packit Service fdd496
            case '*':
Packit Service fdd496
              /* Allocate new extension block and add to head of
Packit Service fdd496
                 linked list (this way a later definition will
Packit Service fdd496
                 override an earlier one, which can be useful for
Packit Service fdd496
                 having terminal-specific defs override global).  */
Packit Service fdd496
Packit Service fdd496
              ext = xmalloc (sizeof *ext);
Packit Service fdd496
              ext->next = color_ext_list;
Packit Service fdd496
              color_ext_list = ext;
Packit Service fdd496
Packit Service fdd496
              ++p;
Packit Service fdd496
              ext->ext.string = buf;
Packit Service fdd496
Packit Service fdd496
              state = (get_funky_string (&buf, &p, true, &ext->ext.len)
Packit Service fdd496
                       ? PS_4 : PS_FAIL);
Packit Service fdd496
              break;
Packit Service fdd496
Packit Service fdd496
            case '\0':
Packit Service fdd496
              state = PS_DONE;	/* Done! */
Packit Service fdd496
              goto done;
Packit Service fdd496
Packit Service fdd496
            default:	/* Assume it is file type label */
Packit Service fdd496
              label[0] = *(p++);
Packit Service fdd496
              state = PS_2;
Packit Service fdd496
              break;
Packit Service fdd496
            }
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case PS_2:		/* Second label character */
Packit Service fdd496
          if (*p)
Packit Service fdd496
            {
Packit Service fdd496
              label[1] = *(p++);
Packit Service fdd496
              state = PS_3;
Packit Service fdd496
            }
Packit Service fdd496
          else
Packit Service fdd496
            state = PS_FAIL;	/* Error */
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case PS_3:		/* Equal sign after indicator label */
Packit Service fdd496
          state = PS_FAIL;	/* Assume failure...  */
Packit Service fdd496
          if (*(p++) == '=')/* It *should* be...  */
Packit Service fdd496
            {
Packit Service fdd496
              for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
Packit Service fdd496
                {
Packit Service fdd496
                  if (STREQ (label, indicator_name[ind_no]))
Packit Service fdd496
                    {
Packit Service fdd496
                      color_indicator[ind_no].string = buf;
Packit Service fdd496
                      state = (get_funky_string (&buf, &p, false,
Packit Service fdd496
                                                 &color_indicator[ind_no].len)
Packit Service fdd496
                               ? PS_START : PS_FAIL);
Packit Service fdd496
                      break;
Packit Service fdd496
                    }
Packit Service fdd496
                }
Packit Service fdd496
              if (state == PS_FAIL)
Packit Service fdd496
                error (0, 0, _("unrecognized prefix: %s"), label);
Packit Service fdd496
            }
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case PS_4:		/* Equal sign after *.ext */
Packit Service fdd496
          if (*(p++) == '=')
Packit Service fdd496
            {
Packit Service fdd496
              ext->seq.string = buf;
Packit Service fdd496
              state = (get_funky_string (&buf, &p, false, &ext->seq.len)
Packit Service fdd496
                       ? PS_START : PS_FAIL);
Packit Service fdd496
            }
Packit Service fdd496
          else
Packit Service fdd496
            state = PS_FAIL;
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case PS_FAIL:
Packit Service fdd496
          goto done;
Packit Service fdd496
Packit Service fdd496
        default:
Packit Service fdd496
          abort ();
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
 done:
Packit Service fdd496
Packit Service fdd496
  if (state == PS_FAIL)
Packit Service fdd496
    {
Packit Service fdd496
      struct color_ext_type *e;
Packit Service fdd496
      struct color_ext_type *e2;
Packit Service fdd496
Packit Service fdd496
      error (0, 0,
Packit Service fdd496
             _("unparsable value for --palette"));
Packit Service fdd496
      free (color_buf);
Packit Service fdd496
      for (e = color_ext_list; e != NULL; /* empty */)
Packit Service fdd496
        {
Packit Service fdd496
          e2 = e;
Packit Service fdd496
          e = e->next;
Packit Service fdd496
          free (e2);
Packit Service fdd496
        }
Packit Service fdd496
      colors_enabled = false;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
check_color_output (bool is_pipe)
Packit Service fdd496
{
Packit Service fdd496
  bool output_is_tty;
Packit Service fdd496
Packit Service fdd496
  if (! outfile || colors_style == NEVER)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  output_is_tty = presume_output_tty || (!is_pipe && isatty (fileno (outfile)));
Packit Service fdd496
Packit Service fdd496
  colors_enabled = (colors_style == ALWAYS
Packit Service fdd496
                    || (colors_style == AUTO && output_is_tty));
Packit Service fdd496
Packit Service fdd496
  if (colors_enabled)
Packit Service fdd496
    parse_diff_color ();
Packit Service fdd496
Packit Service fdd496
  if (output_is_tty)
Packit Service fdd496
    install_signal_handlers ();
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Call before outputting the results of comparing files NAME0 and NAME1
Packit Service fdd496
   to set up OUTFILE, the stdio stream for the output to go to.
Packit Service fdd496
Packit Service fdd496
   Usually, OUTFILE is just stdout.  But when -l was specified
Packit Service fdd496
   we fork off a 'pr' and make OUTFILE a pipe to it.
Packit Service fdd496
   'pr' then outputs to our stdout.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
setup_output (char const *name0, char const *name1, bool recursive)
Packit Service fdd496
{
Packit Service fdd496
  current_name0 = name0;
Packit Service fdd496
  current_name1 = name1;
Packit Service fdd496
  currently_recursive = recursive;
Packit Service fdd496
  outfile = 0;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#if HAVE_WORKING_FORK
Packit Service fdd496
static pid_t pr_pid;
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
static char c_escape_char (char c)
Packit Service fdd496
{
Packit Service fdd496
  switch (c) {
Packit Service fdd496
    case '\a': return 'a';
Packit Service fdd496
    case '\b': return 'b';
Packit Service fdd496
    case '\t': return 't';
Packit Service fdd496
    case '\n': return 'n';
Packit Service fdd496
    case '\v': return 'v';
Packit Service fdd496
    case '\f': return 'f';
Packit Service fdd496
    case '\r': return 'r';
Packit Service fdd496
    case '"': return '"';
Packit Service fdd496
    case '\\': return '\\';
Packit Service fdd496
    default:
Packit Service fdd496
      return c < 32;
Packit Service fdd496
  }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char *
Packit Service fdd496
c_escape (char const *str)
Packit Service fdd496
{
Packit Service fdd496
  char const *s;
Packit Service fdd496
  size_t plus = 0;
Packit Service fdd496
  bool must_quote = false;
Packit Service fdd496
Packit Service fdd496
  for (s = str; *s; s++)
Packit Service fdd496
    {
Packit Service fdd496
      char c = *s;
Packit Service fdd496
Packit Service fdd496
      if (c == ' ')
Packit Service fdd496
	{
Packit Service fdd496
	  must_quote = true;
Packit Service fdd496
	  continue;
Packit Service fdd496
	}
Packit Service fdd496
      switch (c_escape_char (*s))
Packit Service fdd496
	{
Packit Service fdd496
	  case 1:
Packit Service fdd496
	    plus += 3;
Packit Service fdd496
	    /* fall through */
Packit Service fdd496
	  case 0:
Packit Service fdd496
	    break;
Packit Service fdd496
	  default:
Packit Service fdd496
	    plus++;
Packit Service fdd496
	    break;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (must_quote || plus)
Packit Service fdd496
    {
Packit Service fdd496
      size_t s_len = s - str;
Packit Service fdd496
      char *buffer = xmalloc (s_len + plus + 3);
Packit Service fdd496
      char *b = buffer;
Packit Service fdd496
Packit Service fdd496
      *b++ = '"';
Packit Service fdd496
      for (s = str; *s; s++)
Packit Service fdd496
	{
Packit Service fdd496
	  char c = *s;
Packit Service fdd496
	  char escape = c_escape_char (c);
Packit Service fdd496
Packit Service fdd496
	  switch (escape)
Packit Service fdd496
	    {
Packit Service fdd496
	      case 0:
Packit Service fdd496
		*b++ = c;
Packit Service fdd496
		break;
Packit Service fdd496
	      case 1:
Packit Service fdd496
		*b++ = '\\';
Packit Service fdd496
		*b++ = ((c >> 6) & 03) + '0';
Packit Service fdd496
		*b++ = ((c >> 3) & 07) + '0';
Packit Service fdd496
		*b++ = ((c >> 0) & 07) + '0';
Packit Service fdd496
		break;
Packit Service fdd496
	      default:
Packit Service fdd496
		*b++ = '\\';
Packit Service fdd496
		*b++ = escape;
Packit Service fdd496
		break;
Packit Service fdd496
	    }
Packit Service fdd496
	}
Packit Service fdd496
      *b++ = '"';
Packit Service fdd496
      *b = 0;
Packit Service fdd496
      return buffer;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return (char *) str;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
begin_output (void)
Packit Service fdd496
{
Packit Service fdd496
  char *names[2];
Packit Service fdd496
  char *name;
Packit Service fdd496
Packit Service fdd496
  if (outfile != 0)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  names[0] = c_escape (current_name0);
Packit Service fdd496
  names[1] = c_escape (current_name1);
Packit Service fdd496
Packit Service fdd496
  /* Construct the header of this piece of diff.  */
Packit Service fdd496
  /* POSIX 1003.1-2001 specifies this format.  But there are some bugs in
Packit Service fdd496
     the standard: it says that we must print only the last component
Packit Service fdd496
     of the pathnames, and it requires two spaces after "diff" if
Packit Service fdd496
     there are no options.  These requirements are silly and do not
Packit Service fdd496
     match historical practice.  */
Packit Service fdd496
  name = xasprintf ("diff%s %s %s", switch_string, names[0], names[1]);
Packit Service fdd496
Packit Service fdd496
  if (paginate)
Packit Service fdd496
    {
Packit Service fdd496
      char const *argv[4];
Packit Service fdd496
Packit Service fdd496
      if (fflush (stdout) != 0)
Packit Service fdd496
	pfatal_with_name (_("write failed"));
Packit Service fdd496
Packit Service fdd496
      argv[0] = pr_program;
Packit Service fdd496
      argv[1] = "-h";
Packit Service fdd496
      argv[2] = name;
Packit Service fdd496
      argv[3] = 0;
Packit Service fdd496
Packit Service fdd496
      /* Make OUTFILE a pipe to a subsidiary 'pr'.  */
Packit Service fdd496
      {
Packit Service fdd496
#if HAVE_WORKING_FORK
Packit Service fdd496
	int pipes[2];
Packit Service fdd496
Packit Service fdd496
	if (pipe (pipes) != 0)
Packit Service fdd496
	  pfatal_with_name ("pipe");
Packit Service fdd496
Packit Service fdd496
	pr_pid = fork ();
Packit Service fdd496
	if (pr_pid < 0)
Packit Service fdd496
	  pfatal_with_name ("fork");
Packit Service fdd496
Packit Service fdd496
	if (pr_pid == 0)
Packit Service fdd496
	  {
Packit Service fdd496
	    close (pipes[1]);
Packit Service fdd496
	    if (pipes[0] != STDIN_FILENO)
Packit Service fdd496
	      {
Packit Service fdd496
		if (dup2 (pipes[0], STDIN_FILENO) < 0)
Packit Service fdd496
		  pfatal_with_name ("dup2");
Packit Service fdd496
		close (pipes[0]);
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	    execv (pr_program, (char **) argv);
Packit Service fdd496
	    _exit (errno == ENOENT ? 127 : 126);
Packit Service fdd496
	  }
Packit Service fdd496
	else
Packit Service fdd496
	  {
Packit Service fdd496
	    close (pipes[0]);
Packit Service fdd496
	    outfile = fdopen (pipes[1], "w");
Packit Service fdd496
	    if (!outfile)
Packit Service fdd496
	      pfatal_with_name ("fdopen");
Packit Service fdd496
	    check_color_output (true);
Packit Service fdd496
	  }
Packit Service fdd496
#else
Packit Service fdd496
	char *command = system_quote_argv (SCI_SYSTEM, (char **) argv);
Packit Service fdd496
	errno = 0;
Packit Service fdd496
	outfile = popen (command, "w");
Packit Service fdd496
	if (!outfile)
Packit Service fdd496
	  pfatal_with_name (command);
Packit Service fdd496
	check_color_output (true);
Packit Service fdd496
	free (command);
Packit Service fdd496
#endif
Packit Service fdd496
      }
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
Packit Service fdd496
      /* If -l was not specified, output the diff straight to 'stdout'.  */
Packit Service fdd496
Packit Service fdd496
      outfile = stdout;
Packit Service fdd496
      check_color_output (false);
Packit Service fdd496
Packit Service fdd496
      /* If handling multiple files (because scanning a directory),
Packit Service fdd496
	 print which files the following output is about.  */
Packit Service fdd496
      if (currently_recursive)
Packit Service fdd496
	printf ("%s\n", name);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  free (name);
Packit Service fdd496
Packit Service fdd496
  /* A special header is needed at the beginning of context output.  */
Packit Service fdd496
  switch (output_style)
Packit Service fdd496
    {
Packit Service fdd496
    case OUTPUT_CONTEXT:
Packit Service fdd496
      print_context_header (files, (char const *const *)names, false);
Packit Service fdd496
      break;
Packit Service fdd496
Packit Service fdd496
    case OUTPUT_UNIFIED:
Packit Service fdd496
      print_context_header (files, (char const *const *)names, true);
Packit Service fdd496
      break;
Packit Service fdd496
Packit Service fdd496
    default:
Packit Service fdd496
      break;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (names[0] != current_name0)
Packit Service fdd496
    free (names[0]);
Packit Service fdd496
  if (names[1] != current_name1)
Packit Service fdd496
    free (names[1]);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Call after the end of output of diffs for one file.
Packit Service fdd496
   Close OUTFILE and get rid of the 'pr' subfork.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
finish_output (void)
Packit Service fdd496
{
Packit Service fdd496
  if (outfile != 0 && outfile != stdout)
Packit Service fdd496
    {
Packit Service fdd496
      int status;
Packit Service fdd496
      int wstatus;
Packit Service fdd496
      int werrno = 0;
Packit Service fdd496
      if (ferror (outfile))
Packit Service fdd496
	fatal ("write failed");
Packit Service fdd496
#if ! HAVE_WORKING_FORK
Packit Service fdd496
      wstatus = pclose (outfile);
Packit Service fdd496
      if (wstatus == -1)
Packit Service fdd496
	werrno = errno;
Packit Service fdd496
#else
Packit Service fdd496
      if (fclose (outfile) != 0)
Packit Service fdd496
	pfatal_with_name (_("write failed"));
Packit Service fdd496
      if (waitpid (pr_pid, &wstatus, 0) < 0)
Packit Service fdd496
	pfatal_with_name ("waitpid");
Packit Service fdd496
#endif
Packit Service fdd496
      status = (! werrno && WIFEXITED (wstatus)
Packit Service fdd496
		? WEXITSTATUS (wstatus)
Packit Service fdd496
		: INT_MAX);
Packit Service fdd496
      if (status)
Packit Service fdd496
	die (EXIT_TROUBLE, werrno,
Packit Service fdd496
	       _(status == 126
Packit Service fdd496
		 ? "subsidiary program '%s' could not be invoked"
Packit Service fdd496
		 : status == 127
Packit Service fdd496
		 ? "subsidiary program '%s' not found"
Packit Service fdd496
		 : status == INT_MAX
Packit Service fdd496
		 ? "subsidiary program '%s' failed"
Packit Service fdd496
		 : "subsidiary program '%s' failed (exit status %d)"),
Packit Service fdd496
	       pr_program, status);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  outfile = 0;
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Compare two lines (typically one from each input file)
Packit Service fdd496
   according to the command line options.
Packit Service fdd496
   For efficiency, this is invoked only when the lines do not match exactly
Packit Service fdd496
   but an option like -i might cause us to ignore the difference.
Packit Service fdd496
   Return nonzero if the lines differ.  */
Packit Service fdd496
Packit Service fdd496
bool
Packit Service 1d0110
lines_differ_singlebyte (char const *s1, size_t s1len,
Packit Service 1d0110
			 char const *s2, size_t s2len)
Packit Service fdd496
{
Packit Service fdd496
  register char const *t1 = s1;
Packit Service fdd496
  register char const *t2 = s2;
Packit Service fdd496
  size_t column = 0;
Packit Service fdd496
Packit Service fdd496
  while (1)
Packit Service fdd496
    {
Packit Service fdd496
      register unsigned char c1 = *t1++;
Packit Service fdd496
      register unsigned char c2 = *t2++;
Packit Service fdd496
Packit Service fdd496
      /* Test for exact char equality first, since it's a common case.  */
Packit Service fdd496
      if (c1 != c2)
Packit Service fdd496
	{
Packit Service fdd496
	  switch (ignore_white_space)
Packit Service fdd496
	    {
Packit Service fdd496
	    case IGNORE_ALL_SPACE:
Packit Service fdd496
	      /* For -w, just skip past any white space.  */
Packit Service fdd496
	      while (isspace (c1) && c1 != '\n') c1 = *t1++;
Packit Service fdd496
	      while (isspace (c2) && c2 != '\n') c2 = *t2++;
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case IGNORE_SPACE_CHANGE:
Packit Service fdd496
	      /* For -b, advance past any sequence of white space in
Packit Service fdd496
		 line 1 and consider it just one space, or nothing at
Packit Service fdd496
		 all if it is at the end of the line.  */
Packit Service fdd496
	      if (isspace (c1))
Packit Service fdd496
		{
Packit Service fdd496
		  while (c1 != '\n')
Packit Service fdd496
		    {
Packit Service fdd496
		      c1 = *t1++;
Packit Service fdd496
		      if (! isspace (c1))
Packit Service fdd496
			{
Packit Service fdd496
			  --t1;
Packit Service fdd496
			  c1 = ' ';
Packit Service fdd496
			  break;
Packit Service fdd496
			}
Packit Service fdd496
		    }
Packit Service fdd496
		}
Packit Service fdd496
Packit Service fdd496
	      /* Likewise for line 2.  */
Packit Service fdd496
	      if (isspace (c2))
Packit Service fdd496
		{
Packit Service fdd496
		  while (c2 != '\n')
Packit Service fdd496
		    {
Packit Service fdd496
		      c2 = *t2++;
Packit Service fdd496
		      if (! isspace (c2))
Packit Service fdd496
			{
Packit Service fdd496
			  --t2;
Packit Service fdd496
			  c2 = ' ';
Packit Service fdd496
			  break;
Packit Service fdd496
			}
Packit Service fdd496
		    }
Packit Service fdd496
		}
Packit Service fdd496
Packit Service fdd496
	      if (c1 != c2)
Packit Service fdd496
		{
Packit Service fdd496
		  /* If we went too far when doing the simple test
Packit Service fdd496
		     for equality, go back to the first non-white-space
Packit Service fdd496
		     character in both sides and try again.  */
Packit Service fdd496
		  if (c2 == ' ' && c1 != '\n'
Packit Service fdd496
		      && s1 + 1 < t1
Packit Service fdd496
		      && isspace ((unsigned char) t1[-2]))
Packit Service fdd496
		    {
Packit Service fdd496
		      --t1;
Packit Service fdd496
		      continue;
Packit Service fdd496
		    }
Packit Service fdd496
		  if (c1 == ' ' && c2 != '\n'
Packit Service fdd496
		      && s2 + 1 < t2
Packit Service fdd496
		      && isspace ((unsigned char) t2[-2]))
Packit Service fdd496
		    {
Packit Service fdd496
		      --t2;
Packit Service fdd496
		      continue;
Packit Service fdd496
		    }
Packit Service fdd496
		}
Packit Service fdd496
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case IGNORE_TRAILING_SPACE:
Packit Service fdd496
	    case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
Packit Service fdd496
	      if (isspace (c1) && isspace (c2))
Packit Service fdd496
		{
Packit Service fdd496
		  unsigned char c;
Packit Service fdd496
		  if (c1 != '\n')
Packit Service fdd496
		    {
Packit Service fdd496
		      char const *p = t1;
Packit Service fdd496
		      while ((c = *p) != '\n' && isspace (c))
Packit Service fdd496
			++p;
Packit Service fdd496
		      if (c != '\n')
Packit Service fdd496
			break;
Packit Service fdd496
		    }
Packit Service fdd496
		  if (c2 != '\n')
Packit Service fdd496
		    {
Packit Service fdd496
		      char const *p = t2;
Packit Service fdd496
		      while ((c = *p) != '\n' && isspace (c))
Packit Service fdd496
			++p;
Packit Service fdd496
		      if (c != '\n')
Packit Service fdd496
			break;
Packit Service fdd496
		    }
Packit Service fdd496
		  /* Both lines have nothing but whitespace left.  */
Packit Service fdd496
		  return false;
Packit Service fdd496
		}
Packit Service fdd496
	      if (ignore_white_space == IGNORE_TRAILING_SPACE)
Packit Service fdd496
		break;
Packit Service fdd496
	      FALLTHROUGH;
Packit Service fdd496
	    case IGNORE_TAB_EXPANSION:
Packit Service fdd496
	      if ((c1 == ' ' && c2 == '\t')
Packit Service fdd496
		  || (c1 == '\t' && c2 == ' '))
Packit Service fdd496
		{
Packit Service fdd496
		  size_t column2 = column;
Packit Service fdd496
		  for (;; c1 = *t1++)
Packit Service fdd496
		    {
Packit Service fdd496
		      if (c1 == ' ')
Packit Service fdd496
			column++;
Packit Service fdd496
		      else if (c1 == '\t')
Packit Service fdd496
			column += tabsize - column % tabsize;
Packit Service fdd496
		      else
Packit Service fdd496
			break;
Packit Service fdd496
		    }
Packit Service fdd496
		  for (;; c2 = *t2++)
Packit Service fdd496
		    {
Packit Service fdd496
		      if (c2 == ' ')
Packit Service fdd496
			column2++;
Packit Service fdd496
		      else if (c2 == '\t')
Packit Service fdd496
			column2 += tabsize - column2 % tabsize;
Packit Service fdd496
		      else
Packit Service fdd496
			break;
Packit Service fdd496
		    }
Packit Service fdd496
		  if (column != column2)
Packit Service fdd496
		    return true;
Packit Service fdd496
		}
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case IGNORE_NO_WHITE_SPACE:
Packit Service fdd496
	      break;
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  /* Lowercase all letters if -i is specified.  */
Packit Service fdd496
Packit Service fdd496
	  if (ignore_case)
Packit Service fdd496
	    {
Packit Service fdd496
	      c1 = tolower (c1);
Packit Service fdd496
	      c2 = tolower (c2);
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  if (c1 != c2)
Packit Service fdd496
	    break;
Packit Service fdd496
	}
Packit Service fdd496
      if (c1 == '\n')
Packit Service fdd496
	return false;
Packit Service fdd496
Packit Service fdd496
      column += c1 == '\t' ? tabsize - column % tabsize : 1;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return true;
Packit Service fdd496
}
Packit Service 1d0110
Packit Service 1d0110
#ifdef HANDLE_MULTIBYTE
Packit Service 1d0110
# define MBC2WC(T, END, MBLENGTH, WC, STATE, CONVFAIL)	\
Packit Service 1d0110
do							\
Packit Service 1d0110
  {							\
Packit Service 1d0110
    mbstate_t bak = STATE;				\
Packit Service 1d0110
							\
Packit Service 1d0110
    CONVFAIL = 0;					\
Packit Service 1d0110
    MBLENGTH = mbrtowc (&WC, T, END - T, &STATE);	\
Packit Service 1d0110
							\
Packit Service 1d0110
    switch (MBLENGTH)					\
Packit Service 1d0110
      {							\
Packit Service 1d0110
      case (size_t)-2:					\
Packit Service 1d0110
      case (size_t)-1:					\
Packit Service 1d0110
	STATE = bak;					\
Packit Service 1d0110
	++CONVFAIL;					\
Packit Service 1d0110
	/* Fall through. */				\
Packit Service 1d0110
      case 0:						\
Packit Service 1d0110
	MBLENGTH = 1;					\
Packit Service 1d0110
      }							\
Packit Service 1d0110
  }							\
Packit Service 1d0110
 while (0)
Packit Service 1d0110
Packit Service 1d0110
bool
Packit Service 1d0110
lines_differ_multibyte (char const *s1, size_t s1len,
Packit Service 1d0110
			char const *s2, size_t s2len)
Packit Service 1d0110
{
Packit Service 1d0110
  char const *end1, *end2;
Packit Service 1d0110
  char c1, c2;
Packit Service 1d0110
  wchar_t wc1, wc2, wc1_bak, wc2_bak;
Packit Service 1d0110
  size_t mblen1, mblen2;
Packit Service 1d0110
  mbstate_t state1, state2, state1_bak, state2_bak;
Packit Service 1d0110
  int convfail1, convfail2, convfail1_bak, convfail2_bak;
Packit Service 1d0110
  
Packit Service 1d0110
  char const *t1 = s1;
Packit Service 1d0110
  char const *t2 = s2;
Packit Service 1d0110
  char const *t1_bak, *t2_bak;
Packit Service 1d0110
  size_t column = 0;
Packit Service 1d0110
Packit Service 1d0110
  if (ignore_white_space == IGNORE_NO_WHITE_SPACE  && !ignore_case)
Packit Service 1d0110
    {
Packit Service 1d0110
      while (*t1 != '\n')
Packit Service 1d0110
	if (*t1++ != *t2++)
Packit Service 1d0110
	  return 1;
Packit Service 1d0110
      return 0;
Packit Service 1d0110
    }
Packit Service 1d0110
Packit Service 1d0110
  end1 = t1 + s1len;
Packit Service 1d0110
  end2 = t2 + s2len;
Packit Service 1d0110
Packit Service 1d0110
  memset (&state1, '\0', sizeof (mbstate_t));
Packit Service 1d0110
  memset (&state2, '\0', sizeof (mbstate_t));
Packit Service 1d0110
Packit Service 1d0110
  while (1)
Packit Service 1d0110
    {
Packit Service 1d0110
      c1 = *t1;
Packit Service 1d0110
      c2 = *t2;
Packit Service 1d0110
      MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
Packit Service 1d0110
      MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
Packit Service 1d0110
Packit Service 1d0110
      /* Test for exact char equality first, since it's a common case.  */
Packit Service 1d0110
      if (convfail1 ^ convfail2)
Packit Service 1d0110
	break;
Packit Service 1d0110
      else if (convfail1 && convfail2 && c1 != c2)
Packit Service 1d0110
	break;
Packit Service 1d0110
      else if (!convfail1 && !convfail2 && wc1 != wc2)
Packit Service 1d0110
	{
Packit Service 1d0110
	  switch (ignore_white_space)
Packit Service 1d0110
	    {
Packit Service 1d0110
	    case IGNORE_ALL_SPACE:
Packit Service 1d0110
	      /* For -w, just skip past any white space.  */
Packit Service 1d0110
	      while (1)
Packit Service 1d0110
		{
Packit Service 1d0110
		  if (convfail1)
Packit Service 1d0110
		    break;
Packit Service 1d0110
		  else if (wc1 == L'\n' || !iswspace (wc1))
Packit Service 1d0110
		    break;
Packit Service 1d0110
Packit Service 1d0110
		  t1 += mblen1;
Packit Service 1d0110
		  c1 = *t1;
Packit Service 1d0110
		  MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
Packit Service 1d0110
		}
Packit Service 1d0110
Packit Service 1d0110
	      while (1)
Packit Service 1d0110
		{
Packit Service 1d0110
		  if (convfail2)
Packit Service 1d0110
		    break;
Packit Service 1d0110
		  else if (wc2 == L'\n' || !iswspace (wc2))
Packit Service 1d0110
		    break;
Packit Service 1d0110
Packit Service 1d0110
		  t2 += mblen2;
Packit Service 1d0110
		  c2 = *t2;
Packit Service 1d0110
		  MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
Packit Service 1d0110
		}
Packit Service 1d0110
	      t1 += mblen1;
Packit Service 1d0110
	      t2 += mblen2;
Packit Service 1d0110
	      break;
Packit Service 1d0110
Packit Service 1d0110
	    case IGNORE_SPACE_CHANGE:
Packit Service 1d0110
	      /* For -b, advance past any sequence of white space in
Packit Service 1d0110
		 line 1 and consider it just one space, or nothing at
Packit Service 1d0110
		 all if it is at the end of the line.  */
Packit Service 1d0110
	      if (wc1 != L'\n' && iswspace (wc1))
Packit Service 1d0110
		{
Packit Service 1d0110
		  size_t mblen_bak;
Packit Service 1d0110
		  mbstate_t state_bak;
Packit Service 1d0110
Packit Service 1d0110
		  do
Packit Service 1d0110
		    {
Packit Service 1d0110
		      t1 += mblen1;
Packit Service 1d0110
		      mblen_bak = mblen1;
Packit Service 1d0110
		      state_bak = state1;
Packit Service 1d0110
		      MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
Packit Service 1d0110
		    }
Packit Service 1d0110
		  while (!convfail1 && (wc1 != L'\n' && iswspace (wc1)));
Packit Service 1d0110
Packit Service 1d0110
		  state1 = state_bak;
Packit Service 1d0110
		  mblen1 = mblen_bak;
Packit Service 1d0110
		  t1 -= mblen1;
Packit Service 1d0110
		  convfail1 = 0;
Packit Service 1d0110
		  wc1 = L' ';
Packit Service 1d0110
		}
Packit Service 1d0110
Packit Service 1d0110
	      /* Likewise for line 2.  */
Packit Service 1d0110
	      if (wc2 != L'\n' && iswspace (wc2))
Packit Service 1d0110
		{
Packit Service 1d0110
		  size_t mblen_bak;
Packit Service 1d0110
		  mbstate_t state_bak;
Packit Service 1d0110
Packit Service 1d0110
		  do
Packit Service 1d0110
		    {
Packit Service 1d0110
		      t2 += mblen2;
Packit Service 1d0110
		      mblen_bak = mblen2;
Packit Service 1d0110
		      state_bak = state2;
Packit Service 1d0110
		      MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
Packit Service 1d0110
		    }
Packit Service 1d0110
		  while (!convfail2 && (wc2 != L'\n' && iswspace (wc2)));
Packit Service 1d0110
Packit Service 1d0110
		  state2 = state_bak;
Packit Service 1d0110
		  mblen2 = mblen_bak;
Packit Service 1d0110
		  t2 -= mblen2;
Packit Service 1d0110
		  convfail2 = 0;
Packit Service 1d0110
		  wc2 = L' ';
Packit Service 1d0110
		}
Packit Service 1d0110
Packit Service 1d0110
	      if (wc1 != wc2)
Packit Service 1d0110
		{
Packit Service 1d0110
		  /* If we went too far when doing the simple test for
Packit Service 1d0110
		     equality, go back to the first non-whitespace
Packit Service 1d0110
		     character in both sides and try again.  */
Packit Service 1d0110
		  if (wc2 == L' ' && wc1 != L'\n' &&
Packit Service 1d0110
		      t1 > s1 &&
Packit Service 1d0110
		      !convfail1_bak && iswspace (wc1_bak))
Packit Service 1d0110
		    {
Packit Service 1d0110
		      t1 = t1_bak;
Packit Service 1d0110
		      wc1 = wc1_bak;
Packit Service 1d0110
		      state1 = state1_bak;
Packit Service 1d0110
		      convfail1 = convfail1_bak;
Packit Service 1d0110
		      continue;
Packit Service 1d0110
		    }
Packit Service 1d0110
		  if (wc1 == L' ' && wc2 != L'\n'
Packit Service 1d0110
		      && t2 > s2
Packit Service 1d0110
		      && !convfail2_bak && iswspace (wc2_bak))
Packit Service 1d0110
		    {
Packit Service 1d0110
		      t2 = t2_bak;
Packit Service 1d0110
		      wc2 = wc2_bak;
Packit Service 1d0110
		      state2 = state2_bak;
Packit Service 1d0110
		      convfail2 = convfail2_bak;
Packit Service 1d0110
		      continue;
Packit Service 1d0110
		    }
Packit Service 1d0110
		}
Packit Service 1d0110
Packit Service 1d0110
	      t1_bak = t1;		  t2_bak = t2;
Packit Service 1d0110
	      wc1_bak = wc1;		  wc2_bak = wc2;
Packit Service 1d0110
	      state1_bak = state1;	  state2_bak = state2;
Packit Service 1d0110
	      convfail1_bak = convfail1;  convfail2_bak = convfail2;
Packit Service 1d0110
Packit Service 1d0110
	      if (wc1 == L'\n')
Packit Service 1d0110
		wc1 = L' ';
Packit Service 1d0110
	      else
Packit Service 1d0110
		t1 += mblen1;
Packit Service 1d0110
Packit Service 1d0110
	      if (wc2 == L'\n')
Packit Service 1d0110
		wc2 = L' ';
Packit Service 1d0110
	      else
Packit Service 1d0110
		t2 += mblen2;
Packit Service 1d0110
Packit Service 1d0110
	      break;
Packit Service 1d0110
Packit Service 1d0110
	    case IGNORE_TRAILING_SPACE:
Packit Service 1d0110
	    case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
Packit Service 1d0110
	      if (iswspace (wc1) && iswspace (wc2))
Packit Service 1d0110
		{
Packit Service 1d0110
		  char const *p;
Packit Service 1d0110
		  wchar_t wc;
Packit Service 1d0110
		  size_t mblength;
Packit Service 1d0110
		  int convfail;
Packit Service 1d0110
		  mbstate_t state;
Packit Service 1d0110
		  bool just_whitespace_left = 1;
Packit Service 1d0110
		  if (wc1 != L'\n')
Packit Service 1d0110
		    {
Packit Service 1d0110
		      mblength = mblen1;
Packit Service 1d0110
		      p = t1;
Packit Service 1d0110
		      memset (&state, '\0', sizeof(mbstate_t));
Packit Service 1d0110
		      while (p < end1)
Packit Service 1d0110
			{
Packit Service 1d0110
			  if (*p == '\n')
Packit Service 1d0110
			    break;
Packit Service 1d0110
Packit Service 1d0110
			  p += mblength;
Packit Service 1d0110
			  MBC2WC (p, end1, mblength, wc, state, convfail);
Packit Service 1d0110
			  if (convfail || !iswspace (wc))
Packit Service 1d0110
			    {
Packit Service 1d0110
			      just_whitespace_left = 0;
Packit Service 1d0110
			      break;
Packit Service 1d0110
			    }
Packit Service 1d0110
			}
Packit Service 1d0110
		    }
Packit Service 1d0110
		  if (just_whitespace_left && wc2 != L'\n')
Packit Service 1d0110
		    {
Packit Service 1d0110
		      mblength = mblen2;
Packit Service 1d0110
		      p = t2;
Packit Service 1d0110
		      memset (&state, '\0', sizeof(mbstate_t));
Packit Service 1d0110
		      while (p < end2)
Packit Service 1d0110
			{
Packit Service 1d0110
			  if (*p == '\n')
Packit Service 1d0110
			    break;
Packit Service 1d0110
Packit Service 1d0110
			  p += mblength;
Packit Service 1d0110
			  MBC2WC (p, end2, mblength, wc, state, convfail);
Packit Service 1d0110
			  if (convfail || !iswspace (wc))
Packit Service 1d0110
			    {
Packit Service 1d0110
			      just_whitespace_left = 0;
Packit Service 1d0110
			      break;
Packit Service 1d0110
			    }
Packit Service 1d0110
			}
Packit Service 1d0110
		    }
Packit Service 1d0110
Packit Service 1d0110
		  if (just_whitespace_left)
Packit Service 1d0110
		    /* Both lines have nothing but whitespace left.  */
Packit Service 1d0110
		    return false;
Packit Service 1d0110
		}
Packit Service 1d0110
Packit Service 1d0110
	      if (ignore_white_space == IGNORE_TRAILING_SPACE)
Packit Service 1d0110
		break;
Packit Service 1d0110
	      /* Fall through.  */
Packit Service 1d0110
	    case IGNORE_TAB_EXPANSION:
Packit Service 1d0110
	      if ((wc1 == L' ' && wc2 == L'\t')
Packit Service 1d0110
		  || (wc1 == L'\t' && wc2 == L' '))
Packit Service 1d0110
		{
Packit Service 1d0110
		  size_t column2 = column;
Packit Service 1d0110
Packit Service 1d0110
		  while (1)
Packit Service 1d0110
		    {
Packit Service 1d0110
		      if (convfail1)
Packit Service 1d0110
			{
Packit Service 1d0110
			  ++t1;
Packit Service 1d0110
			  break;
Packit Service 1d0110
			}
Packit Service 1d0110
		      else if (wc1 == L' ')
Packit Service 1d0110
			column++;
Packit Service 1d0110
		      else if (wc1 == L'\t')
Packit Service 1d0110
			column += tabsize - column % tabsize;
Packit Service 1d0110
		      else
Packit Service 1d0110
			{
Packit Service 1d0110
			  t1 += mblen1;
Packit Service 1d0110
			  break;
Packit Service 1d0110
			}
Packit Service 1d0110
Packit Service 1d0110
		      t1 += mblen1;
Packit Service 1d0110
		      c1 = *t1;
Packit Service 1d0110
		      MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
Packit Service 1d0110
		    }
Packit Service 1d0110
Packit Service 1d0110
		  while (1)
Packit Service 1d0110
		    {
Packit Service 1d0110
		      if (convfail2)
Packit Service 1d0110
			{
Packit Service 1d0110
			  ++t2;
Packit Service 1d0110
			  break;
Packit Service 1d0110
			}
Packit Service 1d0110
		      else if (wc2 == L' ')
Packit Service 1d0110
			column2++;
Packit Service 1d0110
		      else if (wc2 == L'\t')
Packit Service 1d0110
			column2 += tabsize - column2 % tabsize;
Packit Service 1d0110
		      else
Packit Service 1d0110
			{
Packit Service 1d0110
			  t2 += mblen2;
Packit Service 1d0110
			  break;
Packit Service 1d0110
			}
Packit Service 1d0110
Packit Service 1d0110
		      t2 += mblen2;
Packit Service 1d0110
		      c2 = *t2;
Packit Service 1d0110
		      MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
Packit Service 1d0110
		    }
Packit Service 1d0110
Packit Service 1d0110
		  if (column != column2)
Packit Service 1d0110
		    return 1;
Packit Service 1d0110
		}
Packit Service 1d0110
	      else
Packit Service 1d0110
		{
Packit Service 1d0110
		  t1 += mblen1;
Packit Service 1d0110
		  t2 += mblen2;
Packit Service 1d0110
		}
Packit Service 1d0110
	      break;
Packit Service 1d0110
Packit Service 1d0110
	    case IGNORE_NO_WHITE_SPACE:
Packit Service 1d0110
	      t1 += mblen1;
Packit Service 1d0110
	      t2 += mblen2;
Packit Service 1d0110
	      break;
Packit Service 1d0110
	    }
Packit Service 1d0110
Packit Service 1d0110
	  /* Lowercase all letters if -i is specified.  */
Packit Service 1d0110
	  if (ignore_case)
Packit Service 1d0110
	    {
Packit Service 1d0110
	      if (!convfail1)
Packit Service 1d0110
		wc1 = towlower (wc1);
Packit Service 1d0110
	      if (!convfail2)
Packit Service 1d0110
		wc2 = towlower (wc2);
Packit Service 1d0110
	    }
Packit Service 1d0110
Packit Service 1d0110
	  if (convfail1 ^ convfail2)
Packit Service 1d0110
	    break;
Packit Service 1d0110
	  else if (convfail1 && convfail2 && c1 != c2)
Packit Service 1d0110
	    break;
Packit Service 1d0110
	  else if (!convfail1 && !convfail2 && wc1 != wc2)
Packit Service 1d0110
	    break;
Packit Service 1d0110
	}
Packit Service 1d0110
      else
Packit Service 1d0110
	{
Packit Service 1d0110
	  t1_bak = t1;			t2_bak = t2;
Packit Service 1d0110
	  wc1_bak = wc1;		wc2_bak = wc2;
Packit Service 1d0110
	  state1_bak = state1;		state2_bak = state2;
Packit Service 1d0110
	  convfail1_bak = convfail1;	convfail2_bak = convfail2;
Packit Service 1d0110
Packit Service 1d0110
	  t1 += mblen1;			t2 += mblen2;
Packit Service 1d0110
	}
Packit Service 1d0110
      
Packit Service 1d0110
      if (!convfail1 && wc1 == L'\n')
Packit Service 1d0110
	return 0;
Packit Service 1d0110
Packit Service 1d0110
      column += convfail1 ? 1 :
Packit Service 1d0110
	(wc1 == L'\t') ? tabsize - column % tabsize : wcwidth (wc1);
Packit Service 1d0110
    }
Packit Service 1d0110
Packit Service 1d0110
  return 1;
Packit Service 1d0110
}
Packit Service 1d0110
#endif
Packit Service fdd496

Packit Service fdd496
/* Find the consecutive changes at the start of the script START.
Packit Service fdd496
   Return the last link before the first gap.  */
Packit Service fdd496
Packit Service fdd496
struct change * _GL_ATTRIBUTE_CONST
Packit Service fdd496
find_change (struct change *start)
Packit Service fdd496
{
Packit Service fdd496
  return start;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
struct change * _GL_ATTRIBUTE_CONST
Packit Service fdd496
find_reverse_change (struct change *start)
Packit Service fdd496
{
Packit Service fdd496
  return start;
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Divide SCRIPT into pieces by calling HUNKFUN and
Packit Service fdd496
   print each piece with PRINTFUN.
Packit Service fdd496
   Both functions take one arg, an edit script.
Packit Service fdd496
Packit Service fdd496
   HUNKFUN is called with the tail of the script
Packit Service fdd496
   and returns the last link that belongs together with the start
Packit Service fdd496
   of the tail.
Packit Service fdd496
Packit Service fdd496
   PRINTFUN takes a subscript which belongs together (with a null
Packit Service fdd496
   link at the end) and prints it.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_script (struct change *script,
Packit Service fdd496
	      struct change * (*hunkfun) (struct change *),
Packit Service fdd496
	      void (*printfun) (struct change *))
Packit Service fdd496
{
Packit Service fdd496
  struct change *next = script;
Packit Service fdd496
Packit Service fdd496
  while (next)
Packit Service fdd496
    {
Packit Service fdd496
      struct change *this, *end;
Packit Service fdd496
Packit Service fdd496
      /* Find a set of changes that belong together.  */
Packit Service fdd496
      this = next;
Packit Service fdd496
      end = (*hunkfun) (next);
Packit Service fdd496
Packit Service fdd496
      /* Disconnect them from the rest of the changes,
Packit Service fdd496
	 making them a hunk, and remember the rest for next iteration.  */
Packit Service fdd496
      next = end->link;
Packit Service fdd496
      end->link = 0;
Packit Service fdd496
#ifdef DEBUG
Packit Service fdd496
      debug_script (this);
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
      /* Print this hunk.  */
Packit Service fdd496
      (*printfun) (this);
Packit Service fdd496
Packit Service fdd496
      /* Reconnect the script so it will all be freed properly.  */
Packit Service fdd496
      end->link = next;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Print the text of a single line LINE,
Packit Service fdd496
   flagging it with the characters in LINE_FLAG (which say whether
Packit Service fdd496
   the line is inserted, deleted, changed, etc.).  LINE_FLAG must not
Packit Service fdd496
   end in a blank, unless it is a single blank.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_1_line (char const *line_flag, char const *const *line)
Packit Service fdd496
{
Packit Service fdd496
  print_1_line_nl (line_flag, line, false);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print the text of a single line LINE,
Packit Service fdd496
   flagging it with the characters in LINE_FLAG (which say whether
Packit Service fdd496
   the line is inserted, deleted, changed, etc.).  LINE_FLAG must not
Packit Service fdd496
   end in a blank, unless it is a single blank.  If SKIP_NL is set, then
Packit Service fdd496
   the final '\n' is not printed.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_1_line_nl (char const *line_flag, char const *const *line, bool skip_nl)
Packit Service fdd496
{
Packit Service fdd496
  char const *base = line[0], *limit = line[1]; /* Help the compiler.  */
Packit Service fdd496
  FILE *out = outfile; /* Help the compiler some more.  */
Packit Service fdd496
  char const *flag_format = 0;
Packit Service fdd496
Packit Service fdd496
  /* If -T was specified, use a Tab between the line-flag and the text.
Packit Service fdd496
     Otherwise use a Space (as Unix diff does).
Packit Service fdd496
     Print neither space nor tab if line-flags are empty.
Packit Service fdd496
     But omit trailing blanks if requested.  */
Packit Service fdd496
Packit Service fdd496
  if (line_flag && *line_flag)
Packit Service fdd496
    {
Packit Service fdd496
      char const *flag_format_1 = flag_format = initial_tab ? "%s\t" : "%s ";
Packit Service fdd496
      char const *line_flag_1 = line_flag;
Packit Service fdd496
Packit Service fdd496
      if (suppress_blank_empty && **line == '\n')
Packit Service fdd496
	{
Packit Service fdd496
	  flag_format_1 = "%s";
Packit Service fdd496
Packit Service fdd496
	  /* This hack to omit trailing blanks takes advantage of the
Packit Service fdd496
	     fact that the only way that LINE_FLAG can end in a blank
Packit Service fdd496
	     is when LINE_FLAG consists of a single blank.  */
Packit Service fdd496
	  line_flag_1 += *line_flag_1 == ' ';
Packit Service fdd496
	}
Packit Service fdd496
Packit Service fdd496
      fprintf (out, flag_format_1, line_flag_1);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  output_1_line (base, limit - (skip_nl && limit[-1] == '\n'), flag_format, line_flag);
Packit Service fdd496
Packit Service fdd496
  if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
Packit Service fdd496
    {
Packit Service fdd496
      set_color_context (RESET_CONTEXT);
Packit Service fdd496
      fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Output a line from BASE up to LIMIT.
Packit Service fdd496
   With -t, expand white space characters to spaces, and if FLAG_FORMAT
Packit Service fdd496
   is nonzero, output it with argument LINE_FLAG after every
Packit Service fdd496
   internal carriage return, so that tab stops continue to line up.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
output_1_line (char const *base, char const *limit, char const *flag_format,
Packit Service fdd496
	       char const *line_flag)
Packit Service fdd496
{
Packit Service fdd496
  const size_t MAX_CHUNK = 1024;
Packit Service fdd496
  if (!expand_tabs)
Packit Service fdd496
    {
Packit Service fdd496
      size_t left = limit - base;
Packit Service fdd496
      while (left)
Packit Service fdd496
        {
Packit Service fdd496
          size_t to_write = MIN (left, MAX_CHUNK);
Packit Service fdd496
          size_t written = fwrite (base, sizeof (char), to_write, outfile);
Packit Service fdd496
          if (written < to_write)
Packit Service fdd496
            return;
Packit Service fdd496
          base += written;
Packit Service fdd496
          left -= written;
Packit Service fdd496
          process_signals ();
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      register FILE *out = outfile;
Packit Service fdd496
      register unsigned char c;
Packit Service fdd496
      register char const *t = base;
Packit Service fdd496
      register size_t column = 0;
Packit Service fdd496
      size_t tab_size = tabsize;
Packit Service fdd496
      size_t counter_proc_signals = 0;
Packit Service fdd496
Packit Service fdd496
      while (t < limit)
Packit Service fdd496
        {
Packit Service fdd496
          counter_proc_signals++;
Packit Service fdd496
          if (counter_proc_signals == MAX_CHUNK)
Packit Service fdd496
            {
Packit Service fdd496
              process_signals ();
Packit Service fdd496
              counter_proc_signals = 0;
Packit Service fdd496
            }
Packit Service fdd496
Packit Service fdd496
          switch ((c = *t++))
Packit Service fdd496
            {
Packit Service fdd496
            case '\t':
Packit Service fdd496
              {
Packit Service fdd496
                size_t spaces = tab_size - column % tab_size;
Packit Service fdd496
                column += spaces;
Packit Service fdd496
                do
Packit Service fdd496
                  putc (' ', out);
Packit Service fdd496
                while (--spaces);
Packit Service fdd496
              }
Packit Service fdd496
              break;
Packit Service fdd496
Packit Service fdd496
            case '\r':
Packit Service fdd496
              putc (c, out);
Packit Service fdd496
              if (flag_format && t < limit && *t != '\n')
Packit Service fdd496
                fprintf (out, flag_format, line_flag);
Packit Service fdd496
              column = 0;
Packit Service fdd496
              break;
Packit Service fdd496
Packit Service fdd496
            case '\b':
Packit Service fdd496
              if (column == 0)
Packit Service fdd496
                continue;
Packit Service fdd496
              column--;
Packit Service fdd496
              putc (c, out);
Packit Service fdd496
              break;
Packit Service fdd496
Packit Service fdd496
            default:
Packit Service fdd496
              column += isprint (c) != 0;
Packit Service fdd496
              putc (c, out);
Packit Service fdd496
              break;
Packit Service fdd496
            }
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
enum indicator_no
Packit Service fdd496
  {
Packit Service fdd496
    C_LEFT, C_RIGHT, C_END, C_RESET, C_HEADER, C_ADD, C_DELETE, C_LINE
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
put_indicator (const struct bin_str *ind)
Packit Service fdd496
{
Packit Service fdd496
  fwrite (ind->string, ind->len, 1, outfile);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static enum color_context last_context = RESET_CONTEXT;
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
set_color_context (enum color_context color_context)
Packit Service fdd496
{
Packit Service fdd496
  if (color_context != RESET_CONTEXT)
Packit Service fdd496
    process_signals ();
Packit Service fdd496
  if (colors_enabled && last_context != color_context)
Packit Service fdd496
    {
Packit Service fdd496
      put_indicator (&color_indicator[C_LEFT]);
Packit Service fdd496
      switch (color_context)
Packit Service fdd496
        {
Packit Service fdd496
        case HEADER_CONTEXT:
Packit Service fdd496
          put_indicator (&color_indicator[C_HEADER]);
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case LINE_NUMBER_CONTEXT:
Packit Service fdd496
          put_indicator (&color_indicator[C_LINE]);
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case ADD_CONTEXT:
Packit Service fdd496
          put_indicator (&color_indicator[C_ADD]);
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case DELETE_CONTEXT:
Packit Service fdd496
          put_indicator (&color_indicator[C_DELETE]);
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        case RESET_CONTEXT:
Packit Service fdd496
          put_indicator (&color_indicator[C_RESET]);
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
        default:
Packit Service fdd496
          abort ();
Packit Service fdd496
        }
Packit Service fdd496
      put_indicator (&color_indicator[C_RIGHT]);
Packit Service fdd496
      last_context = color_context;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
char const change_letter[] = { 0, 'd', 'a', 'c' };
Packit Service fdd496

Packit Service fdd496
/* Translate an internal line number (an index into diff's table of lines)
Packit Service fdd496
   into an actual line number in the input file.
Packit Service fdd496
   The internal line number is I.  FILE points to the data on the file.
Packit Service fdd496
Packit Service fdd496
   Internal line numbers count from 0 starting after the prefix.
Packit Service fdd496
   Actual line numbers count from 1 within the entire file.  */
Packit Service fdd496
Packit Service fdd496
lin _GL_ATTRIBUTE_PURE
Packit Service fdd496
translate_line_number (struct file_data const *file, lin i)
Packit Service fdd496
{
Packit Service fdd496
  return i + file->prefix_lines + 1;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Translate a line number range.  This is always done for printing,
Packit Service fdd496
   so for convenience translate to printint rather than lin, so that the
Packit Service fdd496
   caller can use printf with "%"pI"d" without casting.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
translate_range (struct file_data const *file,
Packit Service fdd496
		 lin a, lin b,
Packit Service fdd496
		 printint *aptr, printint *bptr)
Packit Service fdd496
{
Packit Service fdd496
  *aptr = translate_line_number (file, a - 1) + 1;
Packit Service fdd496
  *bptr = translate_line_number (file, b + 1) - 1;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
Packit Service fdd496
   If the two numbers are identical, print just one number.
Packit Service fdd496
Packit Service fdd496
   Args A and B are internal line numbers.
Packit Service fdd496
   We print the translated (real) line numbers.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_number_range (char sepchar, struct file_data *file, lin a, lin b)
Packit Service fdd496
{
Packit Service fdd496
  printint trans_a, trans_b;
Packit Service fdd496
  translate_range (file, a, b, &trans_a, &trans_b);
Packit Service fdd496
Packit Service fdd496
  /* Note: we can have B < A in the case of a range of no lines.
Packit Service fdd496
     In this case, we should print the line number before the range,
Packit Service fdd496
     which is B.  */
Packit Service fdd496
  if (trans_b > trans_a)
Packit Service fdd496
    fprintf (outfile, "%"pI"d%c%"pI"d", trans_a, sepchar, trans_b);
Packit Service fdd496
  else
Packit Service fdd496
    fprintf (outfile, "%"pI"d", trans_b);
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Look at a hunk of edit script and report the range of lines in each file
Packit Service fdd496
   that it applies to.  HUNK is the start of the hunk, which is a chain
Packit Service fdd496
   of 'struct change'.  The first and last line numbers of file 0 are stored in
Packit Service fdd496
   *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
Packit Service fdd496
   Note that these are internal line numbers that count from 0.
Packit Service fdd496
Packit Service fdd496
   If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
Packit Service fdd496
Packit Service fdd496
   Return UNCHANGED if only ignorable lines are inserted or deleted,
Packit Service fdd496
   OLD if lines of file 0 are deleted,
Packit Service fdd496
   NEW if lines of file 1 are inserted,
Packit Service fdd496
   and CHANGED if both kinds of changes are found. */
Packit Service fdd496
Packit Service fdd496
enum changes
Packit Service fdd496
analyze_hunk (struct change *hunk,
Packit Service fdd496
	      lin *first0, lin *last0,
Packit Service fdd496
	      lin *first1, lin *last1)
Packit Service fdd496
{
Packit Service fdd496
  struct change *next;
Packit Service fdd496
  lin l0, l1;
Packit Service fdd496
  lin show_from, show_to;
Packit Service fdd496
  lin i;
Packit Service fdd496
  bool trivial = ignore_blank_lines || ignore_regexp.fastmap;
Packit Service fdd496
  size_t trivial_length = ignore_blank_lines - 1;
Packit Service fdd496
    /* If 0, ignore zero-length lines;
Packit Service fdd496
       if SIZE_MAX, do not ignore lines just because of their length.  */
Packit Service fdd496
Packit Service fdd496
  bool skip_white_space =
Packit Service fdd496
    ignore_blank_lines && IGNORE_TRAILING_SPACE <= ignore_white_space;
Packit Service fdd496
  bool skip_leading_white_space =
Packit Service fdd496
    skip_white_space && IGNORE_SPACE_CHANGE <= ignore_white_space;
Packit Service fdd496
Packit Service fdd496
  char const * const *linbuf0 = files[0].linbuf;  /* Help the compiler.  */
Packit Service fdd496
  char const * const *linbuf1 = files[1].linbuf;
Packit Service fdd496
Packit Service fdd496
  show_from = show_to = 0;
Packit Service fdd496
Packit Service fdd496
  *first0 = hunk->line0;
Packit Service fdd496
  *first1 = hunk->line1;
Packit Service fdd496
Packit Service fdd496
  next = hunk;
Packit Service fdd496
  do
Packit Service fdd496
    {
Packit Service fdd496
      l0 = next->line0 + next->deleted - 1;
Packit Service fdd496
      l1 = next->line1 + next->inserted - 1;
Packit Service fdd496
      show_from += next->deleted;
Packit Service fdd496
      show_to += next->inserted;
Packit Service fdd496
Packit Service fdd496
      for (i = next->line0; i <= l0 && trivial; i++)
Packit Service fdd496
	{
Packit Service fdd496
	  char const *line = linbuf0[i];
Packit Service fdd496
	  char const *lastbyte = linbuf0[i + 1] - 1;
Packit Service fdd496
	  char const *newline = lastbyte + (*lastbyte != '\n');
Packit Service fdd496
	  size_t len = newline - line;
Packit Service fdd496
	  char const *p = line;
Packit Service fdd496
	  if (skip_white_space)
Packit Service fdd496
	    for (; *p != '\n'; p++)
Packit Service fdd496
	      if (! isspace ((unsigned char) *p))
Packit Service fdd496
		{
Packit Service fdd496
		  if (! skip_leading_white_space)
Packit Service fdd496
		    p = line;
Packit Service fdd496
		  break;
Packit Service fdd496
		}
Packit Service fdd496
	  if (newline - p != trivial_length
Packit Service fdd496
	      && (! ignore_regexp.fastmap
Packit Service fdd496
		  || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
Packit Service fdd496
	    trivial = 0;
Packit Service fdd496
	}
Packit Service fdd496
Packit Service fdd496
      for (i = next->line1; i <= l1 && trivial; i++)
Packit Service fdd496
	{
Packit Service fdd496
	  char const *line = linbuf1[i];
Packit Service fdd496
	  char const *lastbyte = linbuf1[i + 1] - 1;
Packit Service fdd496
	  char const *newline = lastbyte + (*lastbyte != '\n');
Packit Service fdd496
	  size_t len = newline - line;
Packit Service fdd496
	  char const *p = line;
Packit Service fdd496
	  if (skip_white_space)
Packit Service fdd496
	    for (; *p != '\n'; p++)
Packit Service fdd496
	      if (! isspace ((unsigned char) *p))
Packit Service fdd496
		{
Packit Service fdd496
		  if (! skip_leading_white_space)
Packit Service fdd496
		    p = line;
Packit Service fdd496
		  break;
Packit Service fdd496
		}
Packit Service fdd496
	  if (newline - p != trivial_length
Packit Service fdd496
	      && (! ignore_regexp.fastmap
Packit Service fdd496
		  || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
Packit Service fdd496
	    trivial = 0;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
  while ((next = next->link) != 0);
Packit Service fdd496
Packit Service fdd496
  *last0 = l0;
Packit Service fdd496
  *last1 = l1;
Packit Service fdd496
Packit Service fdd496
  /* If all inserted or deleted lines are ignorable,
Packit Service fdd496
     tell the caller to ignore this hunk.  */
Packit Service fdd496
Packit Service fdd496
  if (trivial)
Packit Service fdd496
    return UNCHANGED;
Packit Service fdd496
Packit Service fdd496
  return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED);
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Concatenate three strings, returning a newly malloc'd string.  */
Packit Service fdd496
Packit Service fdd496
char *
Packit Service fdd496
concat (char const *s1, char const *s2, char const *s3)
Packit Service fdd496
{
Packit Service fdd496
  char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
Packit Service fdd496
  sprintf (new, "%s%s%s", s1, s2, s3);
Packit Service fdd496
  return new;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Yield a new block of SIZE bytes, initialized to zero.  */
Packit Service fdd496
Packit Service fdd496
void *
Packit Service fdd496
zalloc (size_t size)
Packit Service fdd496
{
Packit Service fdd496
  void *p = xmalloc (size);
Packit Service fdd496
  memset (p, 0, size);
Packit Service fdd496
  return p;
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
void
Packit Service fdd496
debug_script (struct change *sp)
Packit Service fdd496
{
Packit Service fdd496
  fflush (stdout);
Packit Service fdd496
Packit Service fdd496
  for (; sp; sp = sp->link)
Packit Service fdd496
    {
Packit Service fdd496
      printint line0 = sp->line0;
Packit Service fdd496
      printint line1 = sp->line1;
Packit Service fdd496
      printint deleted = sp->deleted;
Packit Service fdd496
      printint inserted = sp->inserted;
Packit Service fdd496
      fprintf (stderr, "%3"pI"d %3"pI"d delete %"pI"d insert %"pI"d\n",
Packit Service fdd496
	       line0, line1, deleted, inserted);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  fflush (stderr);
Packit Service fdd496
}