view rcg.c @ 22:b18d74b37e9e

add runtime bufsize parameter; fix compile-time warnings about discarding qualifiers
author paulo
date Wed, 30 Jul 2014 01:13:50 -0700
parents ebfc52615768
children ce077dec4459
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 size_t bufsize;
30 const size_t BUFSIZE_MIN = 1024;
31 const size_t ERRBUFSIZE = 512;
33 const char *_CLR_START = "\x1B[";
34 const char *_CLR_BOLD = "1;";
35 char *CLR_START;
36 const char *CLR_END = "m";
37 const char *CLR_CLEAR = "\x1B[0m";
39 typedef struct _colors {
40 char *name;
41 char *fg;
42 char *bg;
43 } Colors;
45 const Colors COLORS[] = {
46 { "black", "30", "40" },
47 { "red", "31", "41" },
48 { "green", "32", "42" },
49 { "brown", "33", "43" },
50 { "blue", "34", "44" },
51 { "magenta", "35", "45" },
52 { "cyan", "36", "46" },
53 { "white", "37", "47" },
54 { "default", "39", "49" },
55 { NULL },
56 };
58 char *getFGColor(char *cname)
59 {
60 Colors *c;
61 for (c = (Colors *)COLORS; c->name; c++)
62 {
63 if (strncmp(cname, c->name, strlen(c->name)) == 0)
64 return c->fg;
65 }
66 return NULL;
67 }
69 char *getBGColor(char *cname)
70 {
71 Colors *c;
72 for (c = (Colors *)COLORS; c->name; c++)
73 {
74 if (strncmp(cname, c->name, strlen(c->name)) == 0)
75 return c->bg;
76 }
77 return NULL;
78 }
80 int colorLine = 0;
81 int embolden = 0;
82 char *g_fg = "";
83 char *g_bg = "";
85 typedef enum _exit_code {
86 EXIT_OK,
87 EXIT_REALLOC_ERROR,
88 EXIT_ARGS_ERROR,
89 } Exit_code;
91 int re_error(int errcode, const regex_t *re)
92 {
93 char *err_string = calloc(ERRBUFSIZE, sizeof(char));
94 regerror(errcode, re, err_string, ERRBUFSIZE*sizeof(char));
95 fprintf(stderr, "%s \n", err_string);
96 free(err_string);
97 return errcode;
98 }
100 Exit_code realloc_error()
101 {
102 fprintf(stderr, "realloc() failure \n");
103 return EXIT_REALLOC_ERROR;
104 }
106 void *realloc_buffer(void *buffer, size_t buffer_len)
107 {
108 void *new_buffer = realloc(buffer, buffer_len);
109 if (!new_buffer)
110 exit(realloc_error());
111 return new_buffer;
112 }
114 Exit_code args_error()
115 {
116 char *usage = "\
117 Usage: rcg [options] <PATTERN> \n\
118 \n\
119 Options: \n\
120 -z, --bufsize <size> Buffer size \n\
121 -l, --line Highlight whole line \n\
122 -B, --bold Bold \n\
123 -b <color> Background color \n\
124 -f <color> Foreground color \n\
125 \n\
126 <color> can be one of the following: \n\
127 ";
129 fprintf(stdout, usage);
131 Colors *c;
132 for (c = (Colors *)COLORS; c->name; c++)
133 fprintf(stdout, " %s \n", c->name);
135 return EXIT_ARGS_ERROR;
136 }
138 Exit_code bufsize_args_error()
139 {
140 fprintf(stdout, "bufsize has to be a minimum of %d \n", (int)BUFSIZE_MIN);
141 return EXIT_ARGS_ERROR;
142 }
144 // returns regular expression argument
145 char *parseArgs(int argc, char **argv)
146 {
147 static struct option long_options[] =
148 {
149 { "line", 0, NULL, 'l' },
150 { "bold", 0, NULL, 'B' },
151 { "bufsize", required_argument, NULL, 'z' },
152 { NULL, 0, NULL, 0 },
153 };
155 int c;
156 while ((c = getopt_long(argc, argv, "lBz:f:b:", long_options, NULL)) >= 0)
157 {
158 if (c == 'l')
159 colorLine = 1;
160 else if (c == 'B')
161 embolden = 1;
162 else if (c == 'z')
163 bufsize = (size_t)atoi(optarg);
164 else if (c == 'f')
165 g_fg = strdup(optarg);
166 else if (c == 'b')
167 g_bg = strdup(optarg);
168 }
170 if (optind >= argc)
171 exit(args_error());
173 if (bufsize < BUFSIZE_MIN)
174 exit(bufsize_args_error());
176 return argv[optind];
177 }
179 int main(int argc, char **argv)
180 {
181 bufsize = BUFSIZE_MIN;
183 char *re_expression = parseArgs(argc, argv);
184 char *buf = calloc(bufsize, sizeof(char));
186 int re_err;
187 regex_t *re = calloc(1, sizeof(regex_t));
188 re_err = regcomp(re, re_expression, REG_EXTENDED | REG_NEWLINE);
189 if (re_err != 0)
190 exit(re_error(re_err, re));
192 regmatch_t *rem = calloc(1, sizeof(regmatch_t));
194 if (embolden)
195 {
196 CLR_START = calloc(strlen(_CLR_START) + strlen(_CLR_BOLD) + 1, sizeof(char));
197 strcpy(CLR_START, _CLR_START);
198 strcat(CLR_START, _CLR_BOLD);
199 }
200 else
201 CLR_START = strdup(_CLR_START);
203 if (strlen(g_fg) == 0 && strlen(g_bg) == 0)
204 g_fg = "red";
205 else if (strlen(g_fg) == 0 && strlen(g_bg) > 0)
206 g_fg = "default";
208 char *fgcolor = getFGColor(g_fg);
209 if (!fgcolor)
210 exit(args_error());
212 char *clr = strdup(fgcolor);
213 if (strlen(g_bg) > 0)
214 {
215 char *bgcolor = getBGColor(g_bg);
216 if (bgcolor)
217 {
218 size_t l = strlen(clr) + 1 + strlen(bgcolor);
219 clr = realloc_buffer(clr, (l + 1)*sizeof(char));
220 strcat(clr, ";");
221 strcat(clr, bgcolor);
222 }
223 else
224 exit(args_error());
225 }
227 char *out = NULL;
229 while (fgets(buf, bufsize, stdin))
230 {
231 int so = -1;
232 int eo = -1;
234 size_t out_len = strlen(buf) + 1;
235 unsigned int out_pos = 0;
236 unsigned int buf_pos = 0;
238 for (re_err = 0; re_err != REG_NOMATCH;)
239 {
240 re_err = regexec(re, &buf[buf_pos], 1, rem, 0);
242 so = rem[0].rm_so;
243 eo = rem[0].rm_eo;
245 int match_len = eo - so;
247 if (colorLine && match_len > 0)
248 {
249 so = 0;
250 eo = out_len - 1;
251 match_len = eo - so;
252 }
254 if (re_err != REG_NOMATCH && so >= 0 && eo >= 0 && match_len > 0)
255 {
256 size_t CLR_STRING_len = strlen(CLR_START) + strlen(clr) + strlen(CLR_END) + strlen(CLR_CLEAR);
258 out_len += CLR_STRING_len;
259 out = realloc_buffer(out, out_len*sizeof(char));
261 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);
263 buf_pos += match_len + so;
264 out_pos += CLR_STRING_len + match_len + so;
265 }
266 else
267 {
268 out = realloc_buffer(out, out_len*sizeof(char));
269 strncpy(&out[out_pos], &buf[buf_pos], out_len - out_pos);
270 out[out_len - 1] = '\0';
271 re_err = REG_NOMATCH;
272 }
273 }
275 fputs(out, stdout);
276 fflush(stdout);
277 }
279 return EXIT_OK;
280 }