summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe Scrivano <gscrivano@gnu.org>2015-03-08 22:45:11 +0100
committerJim Meyering <meyering@fb.com>2015-11-29 08:20:53 -0800
commitc0fa19fe92da71404f809aafb5f51cfd99b1bee2 (patch)
tree20f573743b7d02ce463eaa548f25f15b2a3e3213
parentb4efca9de418c0166f0b106fef068a594b4ab483 (diff)
downloaddiffutils-c0fa19fe92da71404f809aafb5f51cfd99b1bee2.tar.gz
diff: add support for --color
* doc/diffutils.texi (diff Options): Add documentation for --color. Copied from coreutils ls --color. * src/context.c (pr_unidiff_hunk): Set the color context. (print_context_header): Likewise. (pr_context_hunk): Likewise. * src/diff.h (enum colors_style): New enum to record when to use colors. (colors_style): New variable to memorize the argument value. (set_color_context): Add function definition. * src/diff.c: : Define COLOR_OPTION. (specify_colors_style): New function. (longopts): Add --color. (main): Handle --color argument. (option_help_msgid): Add usage string for --color. * src/normal.c (print_normal_hunk): Set the color context. * src/side.c (print_1sdiff_line): Likewise. * src/util.c (print_1_line_nl): New function. (print_1_line): Make it a wrapper of 'print_1_line_nl'. (colors_enabled): New boolean variable. (begin_output): Call check_color_output once the output file is configured. (output_1_line): Periodically call `process_signals'. (caught_signals): New sigset_t. (colors_enabled): New boolean variable. (interrupt_signal): New sig_atomic_t. (stop_signal_count): New sig_atomic_t. (check_color_output): New function. (install_signal_handlers): Likewise. Copied from coreutils ls. (process_signals): Likewise. Copied from coreutils ls. (set_color_context): New function. (sighandler): Likewise. Copied from coreutils ls. (stophandler): Likewise. Copied from coreutils ls.
-rw-r--r--doc/diffutils.texi21
-rw-r--r--src/context.c81
-rw-r--r--src/diff.c27
-rw-r--r--src/diff.h28
-rw-r--r--src/normal.c30
-rw-r--r--src/side.c15
-rw-r--r--src/util.c327
7 files changed, 471 insertions, 58 deletions
diff --git a/doc/diffutils.texi b/doc/diffutils.texi
index 091257f..b2c39da 100644
--- a/doc/diffutils.texi
+++ b/doc/diffutils.texi
@@ -3742,6 +3742,27 @@ Read and write data in binary mode. @xref{Binary}.
Use the context output format, showing three lines of context.
@xref{Context Format}.
+@item --color [=@var{when}]
+@cindex color, distinguishing different context
+Specify whether to use color for distinguishing different contexts,
+like header, added or removed lines. @var{when} may be omitted, or
+one of:
+@itemize @bullet
+@item none
+@vindex none @r{color option}
+Do not use color at all. This is the default when no --color option
+is specified.
+@item auto
+@vindex auto @r{color option}
+@cindex terminal, using color iff
+Use color only if standard output is a terminal.
+@item always
+@vindex always @r{color option}
+Always use color.
+@end itemize
+Specifying @option{--color} and no @var{when} is equivalent to
+@option{--color=auto}.
+
@item -C @var{lines}
@itemx --context@r{[}=@var{lines}@r{]}
Use the context output format, showing @var{lines} (an integer) lines of
diff --git a/src/context.c b/src/context.c
index e0f21c4..46b5b1f 100644
--- a/src/context.c
+++ b/src/context.c
@@ -80,6 +80,7 @@ print_context_label (char const *mark,
void
print_context_header (struct file_data inf[], char const *const *names, bool unidiff)
{
+ set_color_context (HEADER_CONTEXT);
if (unidiff)
{
print_context_label ("---", &inf[0], names[0], file_label[0]);
@@ -90,6 +91,7 @@ print_context_header (struct file_data inf[], char const *const *names, bool uni
print_context_label ("***", &inf[0], names[0], file_label[0]);
print_context_label ("---", &inf[1], names[1], file_label[1]);
}
+ set_color_context (RESET_CONTEXT);
}
/* Print an edit script in context format. */
@@ -205,14 +207,21 @@ pr_context_hunk (struct change *hunk)
if (function)
print_context_function (out, function);
- fputs ("\n*** ", out);
+ putc ('\n', out);
+ set_color_context (LINE_NUMBER_CONTEXT);
+ fputs ("*** ", out);
print_context_number_range (&files[0], first0, last0);
- fputs (" ****\n", out);
+ fputs (" ****", out);
+ set_color_context (RESET_CONTEXT);
+ putc ('\n', out);
if (changes & OLD)
{
struct change *next = hunk;
+ if (first0 <= last0)
+ set_color_context (DELETE_CONTEXT);
+
for (i = first0; i <= last0; i++)
{
/* Skip past changes that apply (in file 0)
@@ -225,23 +234,34 @@ pr_context_hunk (struct change *hunk)
prefix = " ";
if (next && next->line0 <= i)
- /* The change NEXT covers this line.
- If lines were inserted here in file 1, this is "changed".
- Otherwise it is "deleted". */
- prefix = (next->inserted > 0 ? "!" : "-");
-
- print_1_line (prefix, &files[0].linbuf[i]);
+ {
+ /* The change NEXT covers this line.
+ If lines were inserted here in file 1, this is "changed".
+ Otherwise it is "deleted". */
+ prefix = (next->inserted > 0 ? "!" : "-");
+ }
+ print_1_line_nl (prefix, &files[0].linbuf[i], true);
+ if (i == last0)
+ set_color_context (RESET_CONTEXT);
+ if (files[0].linbuf[i + 1][-1] == '\n')
+ putc ('\n', out);
}
}
+ set_color_context (LINE_NUMBER_CONTEXT);
fputs ("--- ", out);
print_context_number_range (&files[1], first1, last1);
- fputs (" ----\n", out);
+ fputs (" ----", out);
+ set_color_context (RESET_CONTEXT);
+ putc ('\n', out);
if (changes & NEW)
{
struct change *next = hunk;
+ if (first1 <= last1)
+ set_color_context (ADD_CONTEXT);
+
for (i = first1; i <= last1; i++)
{
/* Skip past changes that apply (in file 1)
@@ -254,12 +274,17 @@ pr_context_hunk (struct change *hunk)
prefix = " ";
if (next && next->line1 <= i)
- /* The change NEXT covers this line.
- If lines were deleted here in file 0, this is "changed".
- Otherwise it is "inserted". */
- prefix = (next->deleted > 0 ? "!" : "+");
-
- print_1_line (prefix, &files[1].linbuf[i]);
+ {
+ /* The change NEXT covers this line.
+ If lines were deleted here in file 0, this is "changed".
+ Otherwise it is "inserted". */
+ prefix = (next->deleted > 0 ? "!" : "+");
+ }
+ print_1_line_nl (prefix, &files[1].linbuf[i], true);
+ if (i == last1)
+ set_color_context (RESET_CONTEXT);
+ if (files[1].linbuf[i + 1][-1] == '\n')
+ putc ('\n', out);
}
}
}
@@ -330,11 +355,13 @@ pr_unidiff_hunk (struct change *hunk)
begin_output ();
out = outfile;
+ set_color_context (LINE_NUMBER_CONTEXT);
fputs ("@@ -", out);
print_unidiff_number_range (&files[0], first0, last0);
fputs (" +", out);
print_unidiff_number_range (&files[1], first1, last1);
fputs (" @@", out);
+ set_color_context (RESET_CONTEXT);
if (function)
print_context_function (out, function);
@@ -363,25 +390,43 @@ pr_unidiff_hunk (struct change *hunk)
/* For each difference, first output the deleted part. */
k = next->deleted;
+ if (k)
+ set_color_context (DELETE_CONTEXT);
+
while (k--)
{
char const * const *line = &files[0].linbuf[i++];
putc ('-', out);
if (initial_tab && ! (suppress_blank_empty && **line == '\n'))
putc ('\t', out);
- print_1_line (NULL, line);
+ print_1_line_nl (NULL, line, true);
+
+ if (!k)
+ set_color_context (RESET_CONTEXT);
+
+ if (line[1][-1] == '\n')
+ putc ('\n', out);
}
/* Then output the inserted part. */
k = next->inserted;
- while (k--)
+ if (k)
+ set_color_context (ADD_CONTEXT);
+
+ while (k--)
{
char const * const *line = &files[1].linbuf[j++];
putc ('+', out);
if (initial_tab && ! (suppress_blank_empty && **line == '\n'))
putc ('\t', out);
- print_1_line (NULL, line);
+ print_1_line_nl (NULL, line, true);
+
+ if (!k)
+ set_color_context (RESET_CONTEXT);
+
+ if (line[1][-1] == '\n')
+ putc ('\n', out);
}
/* We're done with this hunk, so on to the next! */
diff --git a/src/diff.c b/src/diff.c
index efd7e47..536f545 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -70,6 +70,7 @@ static void add_regexp (struct regexp_list *, char const *);
static void summarize_regexp_list (struct regexp_list *);
static void specify_style (enum output_style);
static void specify_value (char const **, char const *, char const *);
+static void specify_colors_style (char const *);
static void try_help (char const *, char const *) __attribute__((noreturn));
static void check_stdout (void);
static void usage (void);
@@ -136,7 +137,9 @@ enum
UNCHANGED_GROUP_FORMAT_OPTION,
OLD_GROUP_FORMAT_OPTION,
NEW_GROUP_FORMAT_OPTION,
- CHANGED_GROUP_FORMAT_OPTION
+ CHANGED_GROUP_FORMAT_OPTION,
+
+ COLOR_OPTION,
};
static char const group_format_option[][sizeof "--unchanged-group-format"] =
@@ -159,6 +162,7 @@ static struct option const longopts[] =
{"binary", 0, 0, BINARY_OPTION},
{"brief", 0, 0, 'q'},
{"changed-group-format", 1, 0, CHANGED_GROUP_FORMAT_OPTION},
+ {"color", 2, 0, COLOR_OPTION},
{"context", 2, 0, 'C'},
{"ed", 0, 0, 'e'},
{"exclude", 1, 0, 'x'},
@@ -627,6 +631,10 @@ main (int argc, char **argv)
specify_value (&group_format[c], optarg, group_format_option[c]);
break;
+ case COLOR_OPTION:
+ specify_colors_style (optarg);
+ break;
+
default:
try_help (NULL, NULL);
}
@@ -940,6 +948,8 @@ static char const * const option_help_msgid[] = {
N_("-d, --minimal try hard to find a smaller set of changes"),
N_(" --horizon-lines=NUM keep NUM lines of the common prefix and suffix"),
N_(" --speed-large-files assume large files and many scattered small changes"),
+ N_(" --color[=WHEN] colorize the output; WHEN can be 'never', 'always',"),
+ N_(" or 'auto' (the default)"),
"",
N_(" --help display this help and exit"),
N_("-v, --version output version information and exit"),
@@ -1008,6 +1018,21 @@ specify_style (enum output_style style)
output_style = style;
}
}
+
+/* Set the color mode. */
+static void
+specify_colors_style (char const *value)
+{
+ if (value == NULL || STREQ (value, "auto"))
+ colors_style = AUTO;
+ else if (STREQ (value, "always"))
+ colors_style = ALWAYS;
+ else if (STREQ (value, "never"))
+ colors_style = NEVER;
+ else
+ try_help ("invalid color '%s'", value);
+}
+
/* Set the last-modified time of *ST to be the current time. */
diff --git a/src/diff.h b/src/diff.h
index 465e4bc..7bf7344 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -38,6 +38,19 @@ enum changes
/* Both deletes and inserts: a hunk containing both old and new lines. */
CHANGED
};
+
+/* When colors should be used in the output. */
+enum colors_style
+{
+ /* Never output colors. */
+ NEVER,
+
+ /* Output colors if the output is a terminal. */
+ AUTO,
+
+ /* Always output colors. */
+ ALWAYS,
+};
/* Variables for command line options */
@@ -83,6 +96,9 @@ enum output_style
XTERN enum output_style output_style;
+/* Define the current color context used to print a line. */
+XTERN enum colors_style colors_style;
+
/* Nonzero if output cannot be generated for identical files. */
XTERN bool no_diff_means_no_output;
@@ -383,6 +399,7 @@ extern void output_1_line (char const *, char const *, char const *,
extern void perror_with_name (char const *);
extern void pfatal_with_name (char const *) __attribute__((noreturn));
extern void print_1_line (char const *, char const * const *);
+extern void print_1_line_nl (char const *, char const * const *, bool);
extern void print_message_queue (void);
extern void print_number_range (char, struct file_data *, lin, lin);
extern void print_script (struct change *, struct change * (*) (struct change *),
@@ -390,3 +407,14 @@ extern void print_script (struct change *, struct change * (*) (struct change *)
extern void setup_output (char const *, char const *, bool);
extern void translate_range (struct file_data const *, lin, lin,
long int *, long int *);
+
+enum color_context
+{
+ HEADER_CONTEXT,
+ ADD_CONTEXT,
+ DELETE_CONTEXT,
+ RESET_CONTEXT,
+ LINE_NUMBER_CONTEXT,
+};
+
+extern void set_color_context (enum color_context color_context);
diff --git a/src/normal.c b/src/normal.c
index 721fd1a..e78e8ba 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -49,21 +49,43 @@ print_normal_hunk (struct change *hunk)
begin_output ();
/* Print out the line number header for this hunk */
+ set_color_context (LINE_NUMBER_CONTEXT);
print_number_range (',', &files[0], first0, last0);
fputc (change_letter[changes], outfile);
print_number_range (',', &files[1], first1, last1);
+ set_color_context (RESET_CONTEXT);
fputc ('\n', outfile);
/* Print the lines that the first file has. */
if (changes & OLD)
- for (i = first0; i <= last0; i++)
- print_1_line ("<", &files[0].linbuf[i]);
+ {
+ if (first0 <= last0)
+ set_color_context (DELETE_CONTEXT);
+ for (i = first0; i <= last0; i++)
+ {
+ print_1_line_nl ("<", &files[0].linbuf[i], true);
+ if (i == last0)
+ set_color_context (RESET_CONTEXT);
+ if (files[0].linbuf[i + 1][-1] == '\n')
+ putc ('\n', outfile);
+ }
+ }
if (changes == CHANGED)
fputs ("---\n", outfile);
/* Print the lines that the second file has. */
if (changes & NEW)
- for (i = first1; i <= last1; i++)
- print_1_line (">", &files[1].linbuf[i]);
+ {
+ if (first1 <= last1)
+ set_color_context (ADD_CONTEXT);
+ for (i = first1; i <= last1; i++)
+ {
+ print_1_line_nl (">", &files[1].linbuf[i], true);
+ if (i == last1)
+ set_color_context (RESET_CONTEXT);
+ if (files[1].linbuf[i + 1][-1] == '\n')
+ putc ('\n', outfile);
+ }
+ }
}
diff --git a/src/side.c b/src/side.c
index 155512c..a0213c4 100644
--- a/src/side.c
+++ b/src/side.c
@@ -206,6 +206,18 @@ print_1sdiff_line (char const *const *left, char sep,
size_t c2o = sdiff_column2_offset;
size_t col = 0;
bool put_newline = false;
+ bool color_to_reset = false;
+
+ if (sep == '<')
+ {
+ set_color_context (DELETE_CONTEXT);
+ color_to_reset = true;
+ }
+ else if (sep == '>')
+ {
+ set_color_context (ADD_CONTEXT);
+ color_to_reset = true;
+ }
if (left)
{
@@ -233,6 +245,9 @@ print_1sdiff_line (char const *const *left, char sep,
if (put_newline)
putc ('\n', out);
+
+ if (color_to_reset)
+ set_color_context (RESET_CONTEXT);
}
/* Print lines common to both files in side-by-side format. */
diff --git a/src/util.c b/src/util.c
index 2d6d3fc..78b1a2d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -24,6 +24,22 @@
#include <system-quote.h>
#include <xalloc.h>
#include "xvasprintf.h"
+#include <signal.h>
+
+/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
+ present. */
+#ifndef SA_NOCLDSTOP
+# define SA_NOCLDSTOP 0
+# define sigprocmask(How, Set, Oset) /* empty */
+# define sigset_t int
+# if ! HAVE_SIGINTERRUPT
+# define siginterrupt(sig, flag) /* empty */
+# endif
+#endif
+
+#ifndef SA_RESTART
+# define SA_RESTART 0
+#endif
char const pr_program[] = PR_PROGRAM;
@@ -143,6 +159,174 @@ print_message_queue (void)
}
}
+/* The set of signals that are caught. */
+
+static sigset_t caught_signals;
+
+/* If nonzero, the value of the pending fatal signal. */
+
+static sig_atomic_t volatile interrupt_signal;
+
+/* A count of the number of pending stop signals that have been received. */
+
+static sig_atomic_t volatile stop_signal_count;
+
+/* An ordinary signal was received; arrange for the program to exit. */
+
+static void
+sighandler (int sig)
+{
+ if (! SA_NOCLDSTOP)
+ signal (sig, SIG_IGN);
+ if (! interrupt_signal)
+ interrupt_signal = sig;
+}
+
+/* A SIGTSTP was received; arrange for the program to suspend itself. */
+
+static void
+stophandler (int sig)
+{
+ if (! SA_NOCLDSTOP)
+ signal (sig, stophandler);
+ if (! interrupt_signal)
+ stop_signal_count++;
+}
+/* Process any pending signals. If signals are caught, this function
+ should be called periodically. Ideally there should never be an
+ unbounded amount of time when signals are not being processed.
+ Signal handling can restore the default colors, so callers must
+ immediately change colors after invoking this function. */
+
+static void
+process_signals (void)
+{
+ while (interrupt_signal || stop_signal_count)
+ {
+ int sig;
+ int stops;
+ sigset_t oldset;
+
+ set_color_context (RESET_CONTEXT);
+ fflush (stdout);
+
+ sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
+
+ /* Reload interrupt_signal and stop_signal_count, in case a new
+ signal was handled before sigprocmask took effect. */
+ sig = interrupt_signal;
+ stops = stop_signal_count;
+
+ /* SIGTSTP is special, since the application can receive that signal
+ more than once. In this case, don't set the signal handler to the
+ default. Instead, just raise the uncatchable SIGSTOP. */
+ if (stops)
+ {
+ stop_signal_count = stops - 1;
+ sig = SIGSTOP;
+ }
+ else
+ signal (sig, SIG_DFL);
+
+ /* Exit or suspend the program. */
+ raise (sig);
+ sigprocmask (SIG_SETMASK, &oldset, NULL);
+
+ /* If execution reaches here, then the program has been
+ continued (after being suspended). */
+ }
+}
+
+static void
+install_signal_handlers (void)
+{
+ /* The signals that are trapped, and the number of such signals. */
+ static int const sig[] =
+ {
+ /* This one is handled specially. */
+ SIGTSTP,
+
+ /* The usual suspects. */
+ SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
+#ifdef SIGPOLL
+ SIGPOLL,
+#endif
+#ifdef SIGPROF
+ SIGPROF,
+#endif
+#ifdef SIGVTALRM
+ SIGVTALRM,
+#endif
+#ifdef SIGXCPU
+ SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ SIGXFSZ,
+#endif
+ };
+ enum { nsigs = sizeof (sig) / sizeof *(sig) };
+
+#if ! SA_NOCLDSTOP
+ bool caught_sig[nsigs];
+#endif
+ {
+ int j;
+#if SA_NOCLDSTOP
+ struct sigaction act;
+
+ sigemptyset (&caught_signals);
+ for (j = 0; j < nsigs; j++)
+ {
+ sigaction (sig[j], NULL, &act);
+ if (act.sa_handler != SIG_IGN)
+ sigaddset (&caught_signals, sig[j]);
+ }
+
+ act.sa_mask = caught_signals;
+ act.sa_flags = SA_RESTART;
+
+ for (j = 0; j < nsigs; j++)
+ if (sigismember (&caught_signals, sig[j]))
+ {
+ act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler;
+ sigaction (sig[j], &act, NULL);
+ }
+#else
+ for (j = 0; j < nsigs; j++)
+ {
+ caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN);
+ if (caught_sig[j])
+ {
+ signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler);
+ siginterrupt (sig[j], 0);
+ }
+ }
+#endif
+ }
+}
+
+static char const *current_name0;
+static char const *current_name1;
+static bool currently_recursive;
+static bool colors_enabled;
+
+static void
+check_color_output (bool is_pipe)
+{
+ bool output_is_tty;
+
+ if (! outfile || colors_style == NEVER)
+ return;
+
+ output_is_tty = !is_pipe && isatty (fileno (outfile));
+
+ colors_enabled = (colors_style == ALWAYS
+ || (colors_style == AUTO && output_is_tty));
+
+ if (output_is_tty)
+ install_signal_handlers ();
+}
+
/* Call before outputting the results of comparing files NAME0 and NAME1
to set up OUTFILE, the stdio stream for the output to go to.
@@ -150,10 +334,6 @@ print_message_queue (void)
we fork off a 'pr' and make OUTFILE a pipe to it.
'pr' then outputs to our stdout. */
-static char const *current_name0;
-static char const *current_name1;
-static bool currently_recursive;
-
void
setup_output (char const *name0, char const *name1, bool recursive)
{
@@ -313,6 +493,7 @@ begin_output (void)
outfile = fdopen (pipes[1], "w");
if (!outfile)
pfatal_with_name ("fdopen");
+ check_color_output (true);
}
#else
char *command = system_quote_argv (SCI_SYSTEM, (char **) argv);
@@ -320,6 +501,7 @@ begin_output (void)
outfile = popen (command, "w");
if (!outfile)
pfatal_with_name (command);
+ check_color_output (true);
free (command);
#endif
}
@@ -330,6 +512,7 @@ begin_output (void)
/* If -l was not specified, output the diff straight to 'stdout'. */
outfile = stdout;
+ check_color_output (false);
/* If handling multiple files (because scanning a directory),
print which files the following output is about. */
@@ -630,6 +813,18 @@ print_script (struct change *script,
void
print_1_line (char const *line_flag, char const *const *line)
{
+ print_1_line_nl (line_flag, line, false);
+}
+
+/* Print the text of a single line LINE,
+ flagging it with the characters in LINE_FLAG (which say whether
+ the line is inserted, deleted, changed, etc.). LINE_FLAG must not
+ end in a blank, unless it is a single blank. If SKIP_NL is set, then
+ the final '\n' is not printed. */
+
+void
+print_1_line_nl (char const *line_flag, char const *const *line, bool skip_nl)
+{
char const *base = line[0], *limit = line[1]; /* Help the compiler. */
FILE *out = outfile; /* Help the compiler some more. */
char const *flag_format = 0;
@@ -657,10 +852,13 @@ print_1_line (char const *line_flag, char const *const *line)
fprintf (out, flag_format_1, line_flag_1);
}
- output_1_line (base, limit, flag_format, line_flag);
+ output_1_line (base, limit - (skip_nl && limit[-1] == '\n'), flag_format, line_flag);
if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
- fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
+ {
+ set_color_context (RESET_CONTEXT);
+ fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
+ }
}
/* Output a line from BASE up to LIMIT.
@@ -672,8 +870,21 @@ void
output_1_line (char const *base, char const *limit, char const *flag_format,
char const *line_flag)
{
+ const size_t MAX_CHUNK = 1024;
if (!expand_tabs)
- fwrite (base, sizeof (char), limit - base, outfile);
+ {
+ size_t left = limit - base;
+ while (left)
+ {
+ size_t to_write = MIN (left, MAX_CHUNK);
+ size_t written = fwrite (base, sizeof (char), to_write, outfile);
+ if (written < to_write)
+ return;
+ base += written;
+ left -= written;
+ process_signals ();
+ }
+ }
else
{
register FILE *out = outfile;
@@ -681,39 +892,85 @@ output_1_line (char const *base, char const *limit, char const *flag_format,
register char const *t = base;
register size_t column = 0;
size_t tab_size = tabsize;
+ size_t counter_proc_signals = 0;
while (t < limit)
- switch ((c = *t++))
- {
- case '\t':
- {
- size_t spaces = tab_size - column % tab_size;
- column += spaces;
- do
- putc (' ', out);
- while (--spaces);
- }
- break;
+ {
+ counter_proc_signals++;
+ if (counter_proc_signals == MAX_CHUNK)
+ {
+ process_signals ();
+ counter_proc_signals = 0;
+ }
+
+ switch ((c = *t++))
+ {
+ case '\t':
+ {
+ size_t spaces = tab_size - column % tab_size;
+ column += spaces;
+ do
+ putc (' ', out);
+ while (--spaces);
+ }
+ break;
+
+ case '\r':
+ putc (c, out);
+ if (flag_format && t < limit && *t != '\n')
+ fprintf (out, flag_format, line_flag);
+ column = 0;
+ break;
+
+ case '\b':
+ if (column == 0)
+ continue;
+ column--;
+ putc (c, out);
+ break;
+
+ default:
+ column += isprint (c) != 0;
+ putc (c, out);
+ break;
+ }
+ }
+ }
+}
- case '\r':
- putc (c, out);
- if (flag_format && t < limit && *t != '\n')
- fprintf (out, flag_format, line_flag);
- column = 0;
- break;
- case '\b':
- if (column == 0)
- continue;
- column--;
- putc (c, out);
- break;
+void
+set_color_context (enum color_context color_context)
+{
+ process_signals ();
+ if (colors_enabled)
+ {
+ switch (color_context)
+ {
+ case HEADER_CONTEXT:
+ fputs ("\x1B[1m", outfile);
+ break;
- default:
- column += isprint (c) != 0;
- putc (c, out);
- break;
- }
+ case LINE_NUMBER_CONTEXT:
+ fputs ("\x1B[36m", outfile);
+
+ break;
+
+ case ADD_CONTEXT:
+ fputs ("\x1B[32m", outfile);
+ break;
+
+ case DELETE_CONTEXT:
+ fputs ("\x1B[31m", outfile);
+ break;
+
+ case RESET_CONTEXT:
+ fputs ("\x1b[0m", outfile);
+ break;
+
+ default:
+ abort ();
+ }
}
}