[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Changes to grep/src/grep.c
From: |
Charles Levert |
Subject: |
Changes to grep/src/grep.c |
Date: |
Tue, 21 Jun 2005 10:58:53 -0400 |
Index: grep/src/grep.c
diff -u grep/src/grep.c:1.105 grep/src/grep.c:1.106
--- grep/src/grep.c:1.105 Tue Jun 21 14:18:04 2005
+++ grep/src/grep.c Tue Jun 21 14:58:50 2005
@@ -79,6 +79,9 @@
/* If nonzero, use grep_color marker. */
static int color_option;
+/* If nonzero, do pseudo-markup instead of actual colors. */
+static int pseudo_markup;
+
/* If nonzero, show only the part of a line matching the expression. */
static int only_matching;
@@ -125,9 +128,18 @@
This only leaves red, magenta, green, and cyan (and their bold
counterparts) and possibly bold blue. */
/* The color string used for matched text.
- The user can overwrite it using the environment variable GREP_COLOR. */
+ The user can overwrite it using the deprecated
+ environment variable GREP_COLOR or the new GREP_COLORS. */
static const char *grep_color = "01;31"; /* bold red */
+/* Other colors. Defaults look damn good. */
+static const char *filename_color = "35"; /* magenta */
+static const char *line_num_color = "32"; /* green */
+static const char *byte_num_color = "32"; /* green */
+static const char *sep_color = "36"; /* cyan */
+static const char *mlines_color = ""; /* default color pair */
+static const char *context_color = ""; /* default color pair */
+
/* Select Graphic Rendition (SGR, "\33[...m") strings. */
/* Also Erase in Line (EL) to Right ("\33[K") by default. */
/* Why have EL to Right after SGR?
@@ -185,8 +197,10 @@
It would be impractical for GNU grep to become a full-fledged
terminal program linked against ncurses or the like, so it will
not detect terminfo(5) capabilities. */
-#define SGR_START "\33[%sm\33[K"
-#define SGR_END "\33[m\33[K"
+static const char *sgr_start = "\33[%sm\33[K";
+#define SGR_START sgr_start
+static const char *sgr_end = "\33[m\33[K";
+#define SGR_END sgr_end
/* SGR utility macros. */
#define PR_SGR_FMT(fmt, s) do { if (*(s)) printf((fmt), (s)); } while (0)
@@ -197,6 +211,61 @@
#define PR_SGR_START_IF(s) PR_SGR_FMT_IF(SGR_START, (s))
#define PR_SGR_END_IF(s) PR_SGR_FMT_IF(SGR_END, (s))
+struct color_cap
+ {
+ const char *name;
+ const char **var;
+ const char *(*fct)(void);
+ };
+
+const char *
+color_cap_ne_fct(void)
+{
+ if (pseudo_markup)
+ return "makes no sense after the \"xm\" capability; ignored";
+
+ sgr_start = "\33[%sm";
+ sgr_end = "\33[m";
+
+ return NULL;
+}
+
+const char *
+color_cap_xm_fct(void)
+{
+ /* This experimental feature should stay undocumented for now. */
+ pseudo_markup = 1;
+
+ sgr_start = "<grep:%s>";
+ sgr_end = "</grep:%s>";
+
+ /* The user can just redefine them to the empty string afterwards. */
+ grep_color = "matched-text";
+ filename_color = "filename";
+ line_num_color = "line-number";
+ byte_num_color = "byte-offset";
+ sep_color = "separator";
+ mlines_color = "matching-line";
+ context_color = "context-line";
+
+ return NULL;
+}
+
+/* For GREP_COLORS. */
+static struct color_cap color_dict[] =
+ {
+ { "mt", &grep_color, NULL }, /* matched text */
+ { "fn", &filename_color, NULL }, /* filename */
+ { "ln", &line_num_color, NULL }, /* line number */
+ { "bn", &byte_num_color, NULL }, /* byte (sic) offset */
+ { "se", &sep_color, NULL }, /* separator */
+ { "ml", &mlines_color, NULL }, /* matching lines */
+ { "cx", &context_color, NULL }, /* context lines */
+ { "ne", NULL, color_cap_ne_fct }, /* no EL on SGR_* */
+ { "xm", NULL, color_cap_xm_fct }, /* pseudo-markup */
+ { NULL, NULL, NULL }
+ };
+
static struct exclude *excluded_patterns;
static struct exclude *included_patterns;
/* Short options. */
@@ -604,6 +673,24 @@
lastnl = lim;
}
+/* Print the current filename. */
+static void
+print_filename (void)
+{
+ PR_SGR_START_IF(filename_color);
+ fputs(filename, stdout);
+ PR_SGR_END_IF(filename_color);
+}
+
+/* Print a character separator. */
+static void
+print_sep (char sep)
+{
+ PR_SGR_START_IF(sep_color);
+ fputc(sep, stdout);
+ PR_SGR_END_IF(sep_color);
+}
+
/* Print a byte offset, followed by a character separator. */
static void
print_offset_sep (uintmax_t pos, char sep)
@@ -816,7 +903,12 @@
/* We print the SEP_STR_CHUNK separator only if our output is
discontiguous from the last output in the file. */
if ((out_before || out_after) && used && p != lastout)
- puts (SEP_STR_CHUNK);
+ {
+ PR_SGR_START_IF(sep_color);
+ fputs (SEP_STR_CHUNK, stdout);
+ PR_SGR_END_IF(sep_color);
+ fputc('\n', stdout);
+ }
while (p < beg)
{
@@ -1122,13 +1214,22 @@
if (count_matches)
{
if (out_file)
- printf ("%s%c", filename, SEP_CHAR_MATCH & filename_mask);
+ {
+ print_filename();
+ if (filename_mask)
+ print_sep(SEP_CHAR_MATCH);
+ else
+ fputc(0, stdout);
+ }
printf ("%d\n", count);
}
status = !count;
if (list_files == 1 - 2 * status)
- printf ("%s%c", filename, '\n' & filename_mask);
+ {
+ print_filename();
+ fputc('\n' & filename_mask, stdout);
+ }
if (! file)
{
@@ -1447,6 +1548,91 @@
return opt;
}
+/* Parse GREP_COLORS. The default would look like:
+ GREP_COLORS='mt=01;31:ml=:cx=:fn=35:ln=32:bn=32:se=36'
+ No character escaping is needed or supported. */
+static void
+parse_grep_colors (void)
+{
+ const char *p;
+ char *q;
+ char *name;
+ char *val;
+
+ p = getenv("GREP_COLORS"); /* Plural! */
+ if (p == NULL || *p == '\0')
+ return;
+
+ /* Work off a writable copy. */
+ q = xmalloc(strlen(p) + 1);
+ if (q == NULL)
+ return;
+ strcpy(q, p);
+
+ name = q;
+ val = NULL;
+ /* From now on, be well-formed or you're gone. */
+ for (;;)
+ if (*q == ':' || *q == '\0')
+ {
+ char c = *q;
+ struct color_cap *cap;
+
+ *q++ = '\0'; /* Terminate name or val. */
+ /* Empty name without val (empty cap)
+ * won't match and will be ignored. */
+ for (cap = color_dict; cap->name; cap++)
+ if (strcmp(cap->name, name) == 0)
+ break;
+ /* If name unknown, go on for forward compatibility. */
+ if (cap->name)
+ if (cap->var)
+ {
+ if (val)
+ *(cap->var) = val;
+ else
+ fprintf(stderr,
+ _("%s: In GREP_COLORS=\"%s\", the \"%s\" capacity needs
a value (\"=...\"); skipped.\n"),
+ program_name, p, name);
+ }
+ else if (val)
+ fprintf(stderr,
+ _("%s: In GREP_COLORS=\"%s\", the \"%s\" capacity is
boolean and cannot take a value (\"=%s\"); skipped.\n"),
+ program_name, p, name, val);
+ if (cap->fct)
+ {
+ const char *err_str = cap->fct();
+
+ if (err_str)
+ fprintf(stderr,
+ _("%s: In GREP_COLORS=\"%s\", the \"%s\" capacity %s.\n"),
+ program_name, p, name, err_str);
+ }
+ if (c == '\0')
+ return;
+ name = q;
+ val = NULL;
+ }
+ else if (*q == '=')
+ {
+ if (q == name || val)
+ goto ill_formed;
+ *q++ = '\0'; /* Terminate name. */
+ val = q; /* Can be the empty string. */
+ }
+ else if (val == NULL)
+ q++; /* Accumulate name. */
+ else if (*q == ';' || (*q >= '0' && *q <= '9'))
+ q++; /* Accumulate val. Protect the terminal from being sent crap. */
+ else
+ goto ill_formed;
+
+ ill_formed:
+ fprintf(stderr,
+ _("%s: Stopped processing of ill-formed GREP_COLORS=\"%s\" at
remaining substring \"%s\".\n"),
+ program_name, p, q);
+}
+
int
main (int argc, char **argv)
{
@@ -1827,9 +2013,13 @@
if (color_option)
{
+ /* Legacy. */
char *userval = getenv ("GREP_COLOR");
if (userval != NULL && *userval != '\0')
grep_color = userval;
+
+ /* New GREP_COLORS has priority. */
+ parse_grep_colors();
}
if (! matcher)
- Changes to grep/src/grep.c, Charles Levert, 2005/06/14
- Changes to grep/src/grep.c, Charles Levert, 2005/06/20
- Changes to grep/src/grep.c, Charles Levert, 2005/06/20
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c,
Charles Levert <=
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21
- Changes to grep/src/grep.c, Charles Levert, 2005/06/21