paulo@17: // rcg.c -- regex colored grep
paulo@17: // Copyright (C) 2010 by Paulo Ang (pbba13@gmail.com)
paulo@17: //
paulo@17: // This program is free software: you can redistribute it and/or modify
paulo@17: // it under the terms of the GNU General Public License as published by
paulo@17: // the Free Software Foundation, either version 3 of the License, or
paulo@17: // (at your option) any later version.
paulo@17: //
paulo@17: // This program is distributed in the hope that it will be useful,
paulo@17: // but WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@17: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
paulo@17: // GNU General Public License for more details.
paulo@17: //
paulo@17: // You should have received a copy of the GNU General Public License
paulo@17: // along with this program. If not, see .
paulo@17:
paulo@17:
pang@1: #include
pang@1: #include
pang@1: #include
pang@1:
pang@1: #include
pang@1:
paulo@4: #include
paulo@4:
paulo@4: #define _GNU_SOURCE
paulo@4: #include
paulo@4:
pang@1: const size_t BUFSIZE = 5000;
pang@1:
paulo@9: const char *_CLR_START = "\x1B[";
paulo@9: const char *_CLR_BOLD = "1;";
paulo@9: char *CLR_START;
paulo@5: const char *CLR_END = "m";
paulo@5: const char *CLR_CLEAR = "\x1B[0m";
pang@1:
paulo@9: typedef struct _colors {
paulo@9: char *name;
paulo@9: char *fg;
paulo@9: char *bg;
paulo@9: } Colors;
paulo@9:
paulo@9: const Colors COLORS[] = {
paulo@9: { "black", "30", "40" },
paulo@9: { "red", "31", "41" },
paulo@9: { "green", "32", "42" },
paulo@9: { "brown", "33", "43" },
paulo@9: { "blue", "34", "44" },
paulo@9: { "magenta", "35", "45" },
paulo@9: { "cyan", "36", "46" },
paulo@9: { "white", "37", "47" },
paulo@9: { "default", "39", "49" },
paulo@9: { NULL },
paulo@9: };
paulo@9:
paulo@9: char *getFGColor(char *cname)
paulo@9: {
paulo@9: Colors *c;
paulo@9: for (c = COLORS; c->name; c++)
paulo@9: {
paulo@9: if (strncmp(cname, c->name, strlen(c->name)) == 0)
paulo@9: return c->fg;
paulo@9: }
paulo@9: return NULL;
paulo@9: }
paulo@9:
paulo@9: char *getBGColor(char *cname)
paulo@9: {
paulo@9: Colors *c;
paulo@9: for (c = COLORS; c->name; c++)
paulo@9: {
paulo@9: if (strncmp(cname, c->name, strlen(c->name)) == 0)
paulo@9: return c->bg;
paulo@9: }
paulo@9: return NULL;
paulo@9: }
paulo@9:
paulo@8: int colorLine = 0;
paulo@9: int embolden = 0;
paulo@12: char *g_fg = "";
paulo@9: char *g_bg = "";
paulo@8:
paulo@4: typedef enum _exit_code {
paulo@4: EXIT_OK,
paulo@4: EXIT_REALLOC_ERROR,
paulo@4: EXIT_ARGS_ERROR,
paulo@4: } Exit_code;
paulo@4:
paulo@3: int re_error(int errcode, const regex_t *re)
paulo@3: {
paulo@3: char *err_string = calloc(BUFSIZE, sizeof(char));
paulo@3: regerror(errcode, re, err_string, BUFSIZE*sizeof(char));
paulo@3: fprintf(stderr, "%s \n", err_string);
paulo@3: free(err_string);
paulo@3: return errcode;
paulo@3: }
paulo@3:
paulo@4: Exit_code realloc_error()
paulo@3: {
paulo@3: fprintf(stderr, "realloc() failure \n");
paulo@4: return EXIT_REALLOC_ERROR;
paulo@4: }
paulo@4:
paulo@21: void *realloc_buffer(void *buffer, size_t buffer_len)
paulo@21: {
paulo@21: void *new_buffer = realloc(buffer, buffer_len);
paulo@21: if (!new_buffer)
paulo@21: exit(realloc_error());
paulo@21: return new_buffer;
paulo@21: }
paulo@21:
paulo@4: Exit_code args_error()
paulo@4: {
paulo@16: char *usage = "\
paulo@16: Usage: rcg [options] \n\
paulo@16: \n\
paulo@16: Options: \n\
paulo@16: -l, --line Highlight whole line \n\
paulo@16: -B, --bold Bold \n\
paulo@16: -b Background color \n\
paulo@16: -f Foreground color \n\
paulo@16: \n\
paulo@16: can be one of the following: \n\
paulo@16: ";
paulo@16:
paulo@16: fprintf(stdout, usage);
paulo@16:
paulo@16: Colors *c;
paulo@16: for (c = COLORS; c->name; c++)
paulo@16: fprintf(stdout, " %s \n", c->name);
paulo@16:
paulo@4: return EXIT_ARGS_ERROR;
paulo@4: }
paulo@4:
paulo@4: // returns regular expression argument
paulo@4: char *parseArgs(int argc, char **argv)
paulo@4: {
paulo@4: static struct option long_options[] =
paulo@4: {
paulo@8: { "line", 0, 0, 'l' },
paulo@9: { "bold", 0, 0, 'B' },
paulo@4: { 0, 0, 0, 0 },
paulo@4: };
paulo@4:
paulo@4: int c;
paulo@4: int l;
paulo@9: while ((c = getopt_long(argc, argv, "lBf:b:", long_options, &l)) >= 0)
paulo@4: {
paulo@8: if (c == 'l')
paulo@8: colorLine = 1;
paulo@9: else if (c == 'B')
paulo@9: embolden = 1;
paulo@9: else if (c == 'f')
paulo@9: g_fg = strdup(optarg);
paulo@9: else if (c == 'b')
paulo@9: g_bg = strdup(optarg);
paulo@4: }
paulo@4:
paulo@4: if (optind >= argc)
paulo@4: exit(args_error());
paulo@4:
paulo@4: return argv[optind];
paulo@3: }
paulo@3:
pang@1: int main(int argc, char **argv)
pang@1: {
paulo@4: char *re_expression = parseArgs(argc, argv);
paulo@4:
paulo@5: //fprintf(stderr, "re_expression = %s \n", re_expression); //d/ 20100405 PBA
paulo@4:
pang@1: char *buf = calloc(BUFSIZE, sizeof(char));
pang@1:
paulo@3: int re_err;
pang@1: regex_t *re = calloc(1, sizeof(regex_t));
paulo@13: re_err = regcomp(re, re_expression, REG_EXTENDED | REG_NEWLINE);
paulo@3: if (re_err != 0)
paulo@3: exit(re_error(re_err, re));
pang@1:
pang@2: regmatch_t *rem = calloc(1, sizeof(regmatch_t));
pang@1:
paulo@9: if (embolden)
paulo@9: {
paulo@9: CLR_START = calloc(strlen(_CLR_START) + strlen(_CLR_BOLD) + 1, sizeof(char));
paulo@9: strcpy(CLR_START, _CLR_START);
paulo@9: strcat(CLR_START, _CLR_BOLD);
paulo@9: }
paulo@9: else
paulo@9: CLR_START = strdup(_CLR_START);
paulo@9:
paulo@12: if (strlen(g_fg) == 0 && strlen(g_bg) == 0)
paulo@12: g_fg = "red";
paulo@12: else if (strlen(g_fg) == 0 && strlen(g_bg) > 0)
paulo@12: g_fg = "default";
paulo@12:
paulo@12: char *fgcolor = getFGColor(g_fg);
paulo@12: if (!fgcolor)
paulo@9: exit(args_error());
paulo@12:
paulo@12: char *clr = strdup(fgcolor);
paulo@9: if (strlen(g_bg) > 0)
paulo@9: {
paulo@9: char *bgcolor = getBGColor(g_bg);
paulo@9: if (bgcolor)
paulo@9: {
paulo@12: size_t l = strlen(clr) + 1 + strlen(bgcolor);
paulo@21: clr = realloc_buffer(clr, (l + 1)*sizeof(char));
paulo@12: strcat(clr, ";");
paulo@12: strcat(clr, bgcolor);
paulo@9: }
paulo@9: else
paulo@9: exit(args_error());
paulo@9: }
paulo@9:
paulo@7: char *out = NULL;
paulo@7:
pang@1: while (fgets(buf, BUFSIZE, stdin))
pang@1: {
pang@2: int so = -1;
pang@2: int eo = -1;
pang@1:
paulo@6: size_t out_len = strlen(buf) + 1;
paulo@3: unsigned int out_pos = 0;
paulo@3: unsigned int buf_pos = 0;
paulo@3:
paulo@4: for (re_err = 0; re_err != REG_NOMATCH;)
pang@2: {
paulo@3: re_err = regexec(re, &buf[buf_pos], 1, rem, 0);
pang@1:
paulo@13: so = rem[0].rm_so;
paulo@13: eo = rem[0].rm_eo;
paulo@13:
paulo@13: int match_len = eo - so;
paulo@13:
paulo@13: if (colorLine && match_len > 0)
paulo@8: {
paulo@8: so = 0;
paulo@21: eo = out_len - 1;
paulo@13: match_len = eo - so;
paulo@8: }
pang@1:
paulo@7: if (re_err != REG_NOMATCH && so >= 0 && eo >= 0 && match_len > 0)
pang@1: {
paulo@14: size_t CLR_STRING_len = strlen(CLR_START) + strlen(clr) + strlen(CLR_END) + strlen(CLR_CLEAR);
paulo@14:
paulo@14: out_len += CLR_STRING_len;
paulo@21: out = realloc_buffer(out, out_len*sizeof(char));
pang@2:
paulo@15: 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:
paulo@14: buf_pos += match_len + so;
paulo@14: out_pos += CLR_STRING_len + match_len + so;
pang@1: }
pang@2: else
paulo@5: {
paulo@21: out = realloc_buffer(out, out_len*sizeof(char));
paulo@3: strncpy(&out[out_pos], &buf[buf_pos], out_len - out_pos);
paulo@7: out[out_len - 1] = '\0';
paulo@13: re_err = REG_NOMATCH;
paulo@5: }
pang@1: }
pang@1:
pang@1: fputs(out, stdout);
paulo@10: fflush(stdout);
pang@1: }
pang@1:
paulo@4: return EXIT_OK;
pang@1: }