view rcg.c @ 20:dfafe7582bd6

update link to source in index.html
author paulo
date Tue, 12 Mar 2013 22:37:52 -0600
parents 74cf5cfa3ec1
children ebfc52615768
line source
1 // rcg.c -- regex colored grep
2 // Copyright (C) 2010 by Paulo Ang (pbba13@gmail.com)
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <regex.h>
22 #include <string.h>
24 #include <unistd.h>
26 #define _GNU_SOURCE
27 #include <getopt.h>
29 const size_t BUFSIZE = 5000;
31 const char *_CLR_START = "\x1B[";
32 const char *_CLR_BOLD = "1;";
33 char *CLR_START;
34 const char *CLR_END = "m";
35 const char *CLR_CLEAR = "\x1B[0m";
37 typedef struct _colors {
38 char *name;
39 char *fg;
40 char *bg;
41 } Colors;
43 const Colors COLORS[] = {
44 { "black", "30", "40" },
45 { "red", "31", "41" },
46 { "green", "32", "42" },
47 { "brown", "33", "43" },
48 { "blue", "34", "44" },
49 { "magenta", "35", "45" },
50 { "cyan", "36", "46" },
51 { "white", "37", "47" },
52 { "default", "39", "49" },
53 { NULL },
54 };
56 char *getFGColor(char *cname)
57 {
58 Colors *c;
59 for (c = COLORS; c->name; c++)
60 {
61 if (strncmp(cname, c->name, strlen(c->name)) == 0)
62 return c->fg;
63 }
64 return NULL;
65 }
67 char *getBGColor(char *cname)
68 {
69 Colors *c;
70 for (c = COLORS; c->name; c++)
71 {
72 if (strncmp(cname, c->name, strlen(c->name)) == 0)
73 return c->bg;
74 }
75 return NULL;
76 }
78 int colorLine = 0;
79 int embolden = 0;
80 char *g_fg = "";
81 char *g_bg = "";
83 typedef enum _exit_code {
84 EXIT_OK,
85 EXIT_REALLOC_ERROR,
86 EXIT_ARGS_ERROR,
87 } Exit_code;
89 int re_error(int errcode, const regex_t *re)
90 {
91 char *err_string = calloc(BUFSIZE, sizeof(char));
92 regerror(errcode, re, err_string, BUFSIZE*sizeof(char));
93 fprintf(stderr, "%s \n", err_string);
94 free(err_string);
95 return errcode;
96 }
98 Exit_code realloc_error()
99 {
100 fprintf(stderr, "realloc() failure \n");
101 return EXIT_REALLOC_ERROR;
102 }
104 Exit_code args_error()
105 {
106 char *usage = "\
107 Usage: rcg [options] <PATTERN> \n\
108 \n\
109 Options: \n\
110 -l, --line Highlight whole line \n\
111 -B, --bold Bold \n\
112 -b <color> Background color \n\
113 -f <color> Foreground color \n\
114 \n\
115 <color> can be one of the following: \n\
116 ";
118 fprintf(stdout, usage);
120 Colors *c;
121 for (c = COLORS; c->name; c++)
122 fprintf(stdout, " %s \n", c->name);
124 return EXIT_ARGS_ERROR;
125 }
127 // returns regular expression argument
128 char *parseArgs(int argc, char **argv)
129 {
130 static struct option long_options[] =
131 {
132 { "line", 0, 0, 'l' },
133 { "bold", 0, 0, 'B' },
134 { 0, 0, 0, 0 },
135 };
137 int c;
138 int l;
139 while ((c = getopt_long(argc, argv, "lBf:b:", long_options, &l)) >= 0)
140 {
141 if (c == 'l')
142 colorLine = 1;
143 else if (c == 'B')
144 embolden = 1;
145 else if (c == 'f')
146 g_fg = strdup(optarg);
147 else if (c == 'b')
148 g_bg = strdup(optarg);
149 }
151 if (optind >= argc)
152 exit(args_error());
154 return argv[optind];
155 }
157 int main(int argc, char **argv)
158 {
159 char *re_expression = parseArgs(argc, argv);
161 //fprintf(stderr, "re_expression = %s \n", re_expression); //d/ 20100405 PBA
163 char *buf = calloc(BUFSIZE, sizeof(char));
165 int re_err;
166 regex_t *re = calloc(1, sizeof(regex_t));
167 re_err = regcomp(re, re_expression, REG_EXTENDED | REG_NEWLINE);
168 if (re_err != 0)
169 exit(re_error(re_err, re));
171 regmatch_t *rem = calloc(1, sizeof(regmatch_t));
173 if (embolden)
174 {
175 CLR_START = calloc(strlen(_CLR_START) + strlen(_CLR_BOLD) + 1, sizeof(char));
176 strcpy(CLR_START, _CLR_START);
177 strcat(CLR_START, _CLR_BOLD);
178 }
179 else
180 CLR_START = strdup(_CLR_START);
182 if (strlen(g_fg) == 0 && strlen(g_bg) == 0)
183 g_fg = "red";
184 else if (strlen(g_fg) == 0 && strlen(g_bg) > 0)
185 g_fg = "default";
187 char *fgcolor = getFGColor(g_fg);
188 if (!fgcolor)
189 exit(args_error());
191 char *clr = strdup(fgcolor);
192 if (strlen(g_bg) > 0)
193 {
194 char *bgcolor = getBGColor(g_bg);
195 if (bgcolor)
196 {
197 size_t l = strlen(clr) + 1 + strlen(bgcolor);
198 clr = realloc(clr, (l + 1)*sizeof(char));
199 if (!clr)
200 exit(realloc_error());
201 strcat(clr, ";");
202 strcat(clr, bgcolor);
203 }
204 else
205 exit(args_error());
206 }
208 char *out = NULL;
210 while (fgets(buf, BUFSIZE, stdin))
211 {
212 int so = -1;
213 int eo = -1;
215 size_t out_len = strlen(buf) + 1;
216 unsigned int out_pos = 0;
217 unsigned int buf_pos = 0;
219 for (re_err = 0; re_err != REG_NOMATCH;)
220 {
221 re_err = regexec(re, &buf[buf_pos], 1, rem, 0);
223 //fprintf(stderr, "%s", &buf[buf_pos]); //d// 20100405 PBA
225 if (out_len >= (BUFSIZE - buf_pos))
226 out_len = (BUFSIZE - buf_pos) - 1;
228 out = realloc(out, out_len*sizeof(char));
229 if (!out)
230 exit(realloc_error());
232 so = rem[0].rm_so;
233 eo = rem[0].rm_eo;
235 int match_len = eo - so;
237 if (colorLine && match_len > 0)
238 {
239 so = 0;
240 eo = out_len - 2;
241 match_len = eo - so;
242 }
244 //fprintf(stderr, "%d %d \n", so, eo); //d// 20100327 PBA
246 if (re_err != REG_NOMATCH && so >= 0 && eo >= 0 && match_len > 0)
247 {
248 size_t CLR_STRING_len = strlen(CLR_START) + strlen(clr) + strlen(CLR_END) + strlen(CLR_CLEAR);
250 out_len += CLR_STRING_len;
251 out = realloc(out, out_len*sizeof(char));
252 if (!out)
253 exit(realloc_error());
255 snprintf(&out[out_pos], out_len, "%.*s%s%s%s%.*s%s", so, &buf[buf_pos], CLR_START, clr, CLR_END, match_len, &buf[buf_pos + so], CLR_CLEAR);
257 buf_pos += match_len + so;
258 out_pos += CLR_STRING_len + match_len + so;
259 }
260 else
261 {
262 strncpy(&out[out_pos], &buf[buf_pos], out_len - out_pos);
263 out[out_len - 1] = '\0';
264 re_err = REG_NOMATCH;
265 }
266 }
268 fputs(out, stdout);
269 fflush(stdout);
270 }
272 return EXIT_OK;
273 }