Log in Register Dashboard Temp Share Shortlinks Frames API

HTMLify

main.c
Views: 8 | Author: abh
/* grep */

#include <stdio.h>
#include <regex.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <dirent.h>
#include <malloc.h>
#include <argp.h>

struct csf { // Current Search File
    char *name;
} csf;

struct arguments {
    bool recursive;
    bool print_file_name;
    char *regex_string;
    char **files;
    int file_count;
    char *rdir;
} arguments;

void change_color(char c) {
    if (!isatty(fileno(stdout))) return;
    switch (c) { 
        case 'r': printf("\e[1;31m"); break;
        case 'p': printf("\e[0;35m"); break;
        case 'c': printf("\e[36m"); break;
        case 'n': printf("\e[0;97m"); break;
    }
}

void print_csf() {
    change_color('p');
    printf("%s", csf.name);
    change_color('c');
    printf(":");
    change_color('n');
}

void search_in_line(const regex_t *regex, const char *line) {
    regmatch_t regmatch;
    int error;
    error = regexec(regex, line, 1, &regmatch, 0);
    if (!error) {
        int i = 0;
        if (arguments.print_file_name)
            print_csf();
        for (i=0; line[i] != '\0'; i++) {
            if (i == regmatch.rm_so)
                change_color('r');
            if (i == regmatch.rm_eo)
                change_color('n');
            printf("%c", line[i]);
        }
    }
}

void search_in_file(const regex_t *regex, const char *filename) {
    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        fprintf(stderr, "Unable to open file %s \n", filename);
        return;
    }
    if (arguments.print_file_name)
        csf.name = strdup(filename);

    char line[10240];
    while (fgets(line, 10240, f) != NULL) {
        search_in_line(regex, line);
    }
}

void search_in_dir(const regex_t *regex, const char *dpath) {
    char *dirpath = strdup(dpath);
    if (strlen(dirpath) > 1 && dirpath[strlen(dirpath)] == '\0')
        dirpath[strlen(dirpath)] = '\0';

    DIR *dir = opendir(dirpath);
    if (dir == NULL)
        return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
            continue;

        int len = strlen(dirpath) + strlen(entry->d_name) + 2;
        char *fullpath = malloc(len);
        sprintf(fullpath, "%s/%s", dirpath, entry->d_name);
        
        if (entry->d_type == DT_DIR) {
            search_in_dir(regex, fullpath);
        } else {
            search_in_file(regex, fullpath);
        }
    }
}

void search_in_stdin(const regex_t *regex) {
    char line[10240];
    while (fgets(line, 10240, stdin) != NULL)
        search_in_line(regex, line);
}

int parse_opt(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;

    switch (key) {
        case 'r': {
            arguments->recursive = true;
            if (arg) {
                arguments->rdir = strdup(arg);
            } else if (state->argv[state->next]) {
                arguments->rdir = state->argv[state->next];
                state->next++;
            } else {
                arguments->rdir = strdup(".");
            }
            break;
        }
        case ARGP_KEY_ARG: {
            if (!arguments->regex_string) {
                arguments->regex_string = arg;
            } else {
                arguments->files = &state->argv[state->next - 1];
                arguments->file_count = state->argc - (state->next - 1);
                state->next = state->argc;
            }
            break;
        }
    }
    return 0;
}

int main(int argc, char *argv[]) {

    struct argp_option options[] = {
        { "recursive", 'r', "DIR", OPTION_ARG_OPTIONAL, "Search recursivly in directory" },
        { 0 }
    };
    struct argp argp = { options, parse_opt, 0, 0 };

    argp_parse(&argp, argc, argv, 0, 0, &arguments);

    if (arguments.regex_string == NULL) {
        fprintf(stderr, "RegEx is required");
        return 1;
    }

    regex_t regex;
    if (regcomp(&regex, arguments.regex_string, 0) != 0) {
        fprintf(stderr, "Faild to compile the regex");
        return 1;
    }

    if (arguments.recursive) {
        arguments.print_file_name = true;
        search_in_dir(&regex, arguments.rdir);
        return 0;
    }

    if (!arguments.file_count) {
        search_in_stdin(&regex);
        return 0;
    }

    if (arguments.file_count > 1)
        arguments.print_file_name = true;

    for (int i = 0; i < arguments.file_count; i++)
        search_in_file(&regex, arguments.files[i]);

    return 0;
}

Comments