51 |
#undef MAX |
#undef MAX |
52 |
#define MAX(A,B) ((A) > (B) ? (A) : (B)) |
#define MAX(A,B) ((A) > (B) ? (A) : (B)) |
53 |
|
|
54 |
#define SEP_CHAR_MATCH ':' |
#define SEP_CHAR_SELECTED ':' |
55 |
#define SEP_CHAR_CONTEXT '-' |
#define SEP_CHAR_REJECTED '-' |
56 |
#define SEP_STR_CHUNK "--" |
#define SEP_STR_GROUP "--" |
57 |
|
|
58 |
struct stats |
struct stats |
59 |
{ |
{ |
76 |
/* If nonzero, use mmap if possible. */ |
/* If nonzero, use mmap if possible. */ |
77 |
static int mmap_option; |
static int mmap_option; |
78 |
|
|
79 |
/* If nonzero, use grep_color marker. */ |
/* If nonzero, use color markers. */ |
80 |
static int color_option; |
static int color_option; |
81 |
|
|
82 |
/* If nonzero, show only the part of a line matching the expression. */ |
/* If nonzero, show only the part of a line matching the expression. */ |
127 |
terminal with either a black (dark) or white (light) background. |
terminal with either a black (dark) or white (light) background. |
128 |
This only leaves red, magenta, green, and cyan (and their bold |
This only leaves red, magenta, green, and cyan (and their bold |
129 |
counterparts) and possibly bold blue. */ |
counterparts) and possibly bold blue. */ |
130 |
/* The color string used for matched text. |
/* The color strings used for matched text. |
131 |
The user can overwrite it using the deprecated |
The user can overwrite them using the deprecated |
132 |
environment variable GREP_COLOR or the new GREP_COLORS. */ |
environment variable GREP_COLOR or the new GREP_COLORS. */ |
133 |
static const char *grep_color = "01;31"; /* bold red */ |
static const char *selected_match_color = "01;31"; /* bold red */ |
134 |
|
static const char *context_match_color = "01;31"; /* bold red */ |
135 |
|
|
136 |
/* Other colors. Defaults look damn good. */ |
/* Other colors. Defaults look damn good. */ |
137 |
static const char *filename_color = "35"; /* magenta */ |
static const char *filename_color = "35"; /* magenta */ |
138 |
static const char *line_num_color = "32"; /* green */ |
static const char *line_num_color = "32"; /* green */ |
139 |
static const char *byte_num_color = "32"; /* green */ |
static const char *byte_num_color = "32"; /* green */ |
140 |
static const char *sep_color = "36"; /* cyan */ |
static const char *sep_color = "36"; /* cyan */ |
141 |
static const char *mlines_color = ""; /* default color pair */ |
static const char *selected_line_color = ""; /* default color pair */ |
142 |
static const char *context_color = ""; /* default color pair */ |
static const char *context_line_color = ""; /* default color pair */ |
143 |
|
|
144 |
/* Select Graphic Rendition (SGR, "\33[...m") strings. */ |
/* Select Graphic Rendition (SGR, "\33[...m") strings. */ |
145 |
/* Also Erase in Line (EL) to Right ("\33[K") by default. */ |
/* Also Erase in Line (EL) to Right ("\33[K") by default. */ |
220 |
}; |
}; |
221 |
|
|
222 |
static const char * |
static const char * |
223 |
|
color_cap_mt_fct(void) |
224 |
|
{ |
225 |
|
/* Our caller just set selected_match_color. */ |
226 |
|
context_match_color = selected_match_color; |
227 |
|
|
228 |
|
return NULL; |
229 |
|
} |
230 |
|
|
231 |
|
static const char * |
232 |
|
color_cap_rv_fct(void) |
233 |
|
{ |
234 |
|
/* By this point, it was 1 (or already -1). */ |
235 |
|
color_option = -1; /* That's still != 0. */ |
236 |
|
|
237 |
|
return NULL; |
238 |
|
} |
239 |
|
|
240 |
|
static const char * |
241 |
color_cap_ne_fct(void) |
color_cap_ne_fct(void) |
242 |
{ |
{ |
243 |
sgr_start = "\33[%sm"; |
sgr_start = "\33[%sm"; |
249 |
/* For GREP_COLORS. */ |
/* For GREP_COLORS. */ |
250 |
static struct color_cap color_dict[] = |
static struct color_cap color_dict[] = |
251 |
{ |
{ |
252 |
{ "mt", &grep_color, NULL }, /* matched text */ |
{ "mt", &selected_match_color, color_cap_mt_fct }, /* both ms/mc */ |
253 |
{ "fn", &filename_color, NULL }, /* filename */ |
{ "ms", &selected_match_color, NULL }, /* selected matched text */ |
254 |
{ "ln", &line_num_color, NULL }, /* line number */ |
{ "mc", &context_match_color, NULL }, /* context matched text */ |
255 |
{ "bn", &byte_num_color, NULL }, /* byte (sic) offset */ |
{ "fn", &filename_color, NULL }, /* filename */ |
256 |
{ "se", &sep_color, NULL }, /* separator */ |
{ "ln", &line_num_color, NULL }, /* line number */ |
257 |
{ "ml", &mlines_color, NULL }, /* matching lines */ |
{ "bn", &byte_num_color, NULL }, /* byte (sic) offset */ |
258 |
{ "cx", &context_color, NULL }, /* context lines */ |
{ "se", &sep_color, NULL }, /* separator */ |
259 |
{ "ne", NULL, color_cap_ne_fct }, /* no EL on SGR_* */ |
{ "sl", &selected_line_color, NULL }, /* selected lines */ |
260 |
{ NULL, NULL, NULL } |
{ "cx", &context_line_color, NULL }, /* context lines */ |
261 |
|
{ "rv", NULL, color_cap_rv_fct }, /* -v reverses sl/cx */ |
262 |
|
{ "ne", NULL, color_cap_ne_fct }, /* no EL on SGR_* */ |
263 |
|
{ NULL, NULL, NULL } |
264 |
}; |
}; |
265 |
|
|
266 |
static struct exclude *excluded_patterns; |
static struct exclude *excluded_patterns; |
779 |
} |
} |
780 |
|
|
781 |
static const char * |
static const char * |
782 |
print_line_middle (const char *beg, const char *lim) |
print_line_middle (const char *beg, const char *lim, |
783 |
|
const char *line_color, const char *match_color) |
784 |
{ |
{ |
785 |
size_t match_size; |
size_t match_size; |
786 |
size_t match_offset; |
size_t match_offset; |
826 |
} |
} |
827 |
else |
else |
828 |
{ |
{ |
829 |
|
/* This function is called on a matching line only, |
830 |
|
but is it selected or rejected/context? */ |
831 |
if (only_matching) |
if (only_matching) |
832 |
print_line_head(b, lim, SEP_CHAR_MATCH); |
print_line_head(b, lim, out_invert ? SEP_CHAR_REJECTED |
833 |
|
: SEP_CHAR_SELECTED); |
834 |
else |
else |
835 |
{ |
{ |
836 |
PR_SGR_START(mlines_color); |
PR_SGR_START(line_color); |
837 |
if (mid) |
if (mid) |
838 |
{ |
{ |
839 |
cur = mid; |
cur = mid; |
842 |
fwrite (cur, sizeof (char), b - cur, stdout); |
fwrite (cur, sizeof (char), b - cur, stdout); |
843 |
} |
} |
844 |
|
|
845 |
PR_SGR_START_IF(grep_color); |
PR_SGR_START_IF(match_color); |
846 |
fwrite (b, sizeof (char), match_size, stdout); |
fwrite (b, sizeof (char), match_size, stdout); |
847 |
PR_SGR_END_IF(grep_color); |
PR_SGR_END_IF(match_color); |
848 |
if (only_matching) |
if (only_matching) |
849 |
fputs("\n", stdout); |
fputs("\n", stdout); |
850 |
} |
} |
863 |
} |
} |
864 |
|
|
865 |
static const char * |
static const char * |
866 |
print_line_tail (const char *beg, const char *lim, const char *color) |
print_line_tail (const char *beg, const char *lim, const char *line_color) |
867 |
{ |
{ |
868 |
size_t eol_size; |
size_t eol_size; |
869 |
size_t tail_size; |
size_t tail_size; |
874 |
|
|
875 |
if (tail_size > 0) |
if (tail_size > 0) |
876 |
{ |
{ |
877 |
PR_SGR_START(color); |
PR_SGR_START(line_color); |
878 |
fwrite(beg, 1, tail_size, stdout); |
fwrite(beg, 1, tail_size, stdout); |
879 |
beg += tail_size; |
beg += tail_size; |
880 |
PR_SGR_END(color); |
PR_SGR_END(line_color); |
881 |
} |
} |
882 |
|
|
883 |
return beg; |
return beg; |
886 |
static void |
static void |
887 |
prline (char const *beg, char const *lim, int sep) |
prline (char const *beg, char const *lim, int sep) |
888 |
{ |
{ |
889 |
|
int matching; |
890 |
const char *line_color; |
const char *line_color; |
891 |
|
const char *match_color; |
892 |
|
|
893 |
if (!only_matching) |
if (!only_matching) |
894 |
print_line_head(beg, lim, sep); |
print_line_head(beg, lim, sep); |
895 |
|
|
896 |
|
matching = (sep == SEP_CHAR_SELECTED) ^ !!out_invert; |
897 |
|
|
898 |
if (color_option) |
if (color_option) |
899 |
line_color = ((sep == SEP_CHAR_MATCH) ? mlines_color : context_color); |
{ |
900 |
|
line_color = ( (sep == SEP_CHAR_SELECTED) |
901 |
|
^ (out_invert && (color_option < 0))) |
902 |
|
? selected_line_color : context_line_color; |
903 |
|
match_color = (sep == SEP_CHAR_SELECTED) |
904 |
|
? selected_match_color : context_match_color; |
905 |
|
} |
906 |
|
else |
907 |
|
line_color = match_color = NULL; /* Shouldn't be used. */ |
908 |
|
|
909 |
if (only_matching || (color_option && (*grep_color || *line_color))) |
if ( (only_matching && matching) |
910 |
|
|| (color_option && (*line_color || *match_color))) |
911 |
{ |
{ |
912 |
/* We already know that context lines have no match (to colorize). */ |
/* We already know that non-matching lines have no match (to colorize). */ |
913 |
if (only_matching || (*grep_color && sep == SEP_CHAR_MATCH)) |
if (matching && (only_matching || *match_color)) |
914 |
beg = print_line_middle(beg, lim); |
beg = print_line_middle(beg, lim, line_color, match_color); |
915 |
|
|
916 |
if (!only_matching && *line_color); |
if (!only_matching && *line_color); |
917 |
beg = print_line_tail(beg, lim, line_color); |
beg = print_line_tail(beg, lim, line_color); |
945 |
|| ((execute(lastout, nl + 1 - lastout, |
|| ((execute(lastout, nl + 1 - lastout, |
946 |
&match_size, NULL) == (size_t) -1) |
&match_size, NULL) == (size_t) -1) |
947 |
== !out_invert)) |
== !out_invert)) |
948 |
prline (lastout, nl + 1, SEP_CHAR_CONTEXT); |
prline (lastout, nl + 1, SEP_CHAR_REJECTED); |
949 |
else |
else |
950 |
pending = 0; |
pending = 0; |
951 |
} |
} |
956 |
static void |
static void |
957 |
prtext (char const *beg, char const *lim, int *nlinesp) |
prtext (char const *beg, char const *lim, int *nlinesp) |
958 |
{ |
{ |
959 |
static int used; /* avoid printing SEP_STR_CHUNK before any output */ |
static int used; /* avoid printing SEP_STR_GROUP before any output */ |
960 |
char const *bp, *p; |
char const *bp, *p; |
961 |
char eol = eolbyte; |
char eol = eolbyte; |
962 |
int i, n; |
int i, n; |
977 |
--p; |
--p; |
978 |
while (p[-1] != eol); |
while (p[-1] != eol); |
979 |
|
|
980 |
/* We print the SEP_STR_CHUNK separator only if our output is |
/* We print the SEP_STR_GROUP separator only if our output is |
981 |
discontiguous from the last output in the file. */ |
discontiguous from the last output in the file. */ |
982 |
if ((out_before || out_after) && used && p != lastout) |
if ((out_before || out_after) && used && p != lastout) |
983 |
{ |
{ |
984 |
PR_SGR_START_IF(sep_color); |
PR_SGR_START_IF(sep_color); |
985 |
fputs (SEP_STR_CHUNK, stdout); |
fputs (SEP_STR_GROUP, stdout); |
986 |
PR_SGR_END_IF(sep_color); |
PR_SGR_END_IF(sep_color); |
987 |
fputc('\n', stdout); |
fputc('\n', stdout); |
988 |
} |
} |
991 |
{ |
{ |
992 |
char const *nl = memchr (p, eol, beg - p); |
char const *nl = memchr (p, eol, beg - p); |
993 |
nl++; |
nl++; |
994 |
prline (p, nl, SEP_CHAR_CONTEXT); |
prline (p, nl, SEP_CHAR_REJECTED); |
995 |
p = nl; |
p = nl; |
996 |
} |
} |
997 |
} |
} |
1004 |
char const *nl = memchr (p, eol, lim - p); |
char const *nl = memchr (p, eol, lim - p); |
1005 |
nl++; |
nl++; |
1006 |
if (!out_quiet) |
if (!out_quiet) |
1007 |
prline (p, nl, SEP_CHAR_MATCH); |
prline (p, nl, SEP_CHAR_SELECTED); |
1008 |
p = nl; |
p = nl; |
1009 |
} |
} |
1010 |
*nlinesp = n; |
*nlinesp = n; |
1014 |
} |
} |
1015 |
else |
else |
1016 |
if (!out_quiet) |
if (!out_quiet) |
1017 |
prline (beg, lim, SEP_CHAR_MATCH); |
prline (beg, lim, SEP_CHAR_SELECTED); |
1018 |
|
|
1019 |
pending = out_quiet ? 0 : out_after; |
pending = out_quiet ? 0 : out_after; |
1020 |
used = 1; |
used = 1; |
1295 |
{ |
{ |
1296 |
print_filename(); |
print_filename(); |
1297 |
if (filename_mask) |
if (filename_mask) |
1298 |
print_sep(SEP_CHAR_MATCH); |
print_sep(SEP_CHAR_SELECTED); |
1299 |
else |
else |
1300 |
fputc(0, stdout); |
fputc(0, stdout); |
1301 |
} |
} |
1659 |
return opt; |
return opt; |
1660 |
} |
} |
1661 |
|
|
1662 |
/* Parse GREP_COLORS. The default would look like: |
/* Parse GREP_COLORS. The default would look like: |
1663 |
GREP_COLORS='mt=01;31:ml=:cx=:fn=35:ln=32:bn=32:se=36' |
GREP_COLORS='ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36' |
1664 |
|
with boolean capabilities (ne and rv) unset (i.e., omitted). |
1665 |
No character escaping is needed or supported. */ |
No character escaping is needed or supported. */ |
1666 |
static void |
static void |
1667 |
parse_grep_colors (void) |
parse_grep_colors (void) |
2160 |
/* Legacy. */ |
/* Legacy. */ |
2161 |
char *userval = getenv ("GREP_COLOR"); |
char *userval = getenv ("GREP_COLOR"); |
2162 |
if (userval != NULL && *userval != '\0') |
if (userval != NULL && *userval != '\0') |
2163 |
grep_color = userval; |
selected_match_color = context_match_color = userval; |
2164 |
|
|
2165 |
/* New GREP_COLORS has priority. */ |
/* New GREP_COLORS has priority. */ |
2166 |
parse_grep_colors(); |
parse_grep_colors(); |