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