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