txtutils/src/grep.c

141 lines
3.5 KiB
C

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <regex.h>
struct file {
FILE *file;
char *filename;
} file_t;
bool show_filenames = false;
bool invert_match = false;
bool line_number = false;
bool ignore_case = false;
bool extended_regex = false;
int usage() {
printf("Usage: %s [OPTION]... PATTERNS [FILE]...\n", "grep");
printf("Try '%s --help' for more information.\n", "grep");
return 2;
}
int main(int argc, char *argv[]) {
struct file **infiles = malloc(sizeof(FILE));
infiles[0] = malloc(sizeof(FILE));
infiles[0]->file = stdin;
int files_index = 0;
char **regex = malloc(sizeof(char*));
regex[0] = NULL;
int regex_index = 0;
int opt;
char line[256];
if (argc < 2) {
return usage();
} else {
while ((opt = getopt(argc, argv, "::e:vniyE")) != -1) {
switch (opt) {
case 'v':
invert_match = true;
break;
case 'n':
line_number = true;
break;
case 'i':
case 'y':
ignore_case = true;
break;
case 'E':
extended_regex = true;
break;
case 'e':
regex[regex_index] = malloc(strlen(optarg));
regex[regex_index] = optarg;
regex_index++;
break;
case '?':
printf("%s: invalid option -- '%c'\n", "grep", optopt);
return usage();
}
}
for (; optind < argc; optind++) {
if (regex[0] == NULL) {
regex[0] = malloc(strlen(argv[optind]));
regex[0] = argv[optind];
regex_index++;
} else {
if (strcmp(argv[optind], "-")) {
infiles[files_index] = malloc(sizeof(FILE) + strlen(argv[optind]));
infiles[files_index]->file = fopen(argv[optind], "r");
infiles[files_index]->filename = argv[optind];
if (infiles[files_index]->file == NULL) {
perror(argv[optind]);
return -1;
}
} else {
infiles[files_index] = malloc(sizeof(FILE) + strlen("(standard input)"));
infiles[files_index]->file = stdin;
infiles[files_index]->filename = "(standard input)";
}
files_index++;
}
}
}
if (files_index > 1) {
show_filenames = true;
}
int curline = 1;
int i = 0;
int j = 0;
int cur_line_has_regex = 1;
int regflags = 0;
if (extended_regex) {
regflags |= REG_EXTENDED;
}
if (ignore_case) {
regflags |= REG_ICASE;
}
regex_t exp;
regmatch_t matches[1];
do {
while (fgets(line, sizeof line, infiles[i]->file) != NULL) {
do {
regcomp(&exp, regex[j], regflags);
cur_line_has_regex = regexec(&exp, line, 1, matches, 0);
if (cur_line_has_regex == 0 && !invert_match) {
curline++;
if (line_number) printf("%d:", curline);
if (show_filenames) {
printf("%s:%s", infiles[i]->filename, line);
} else {
printf("%s", line);
}
} else if (cur_line_has_regex != 0 && invert_match) {
curline++;
if (line_number) printf("%d:", curline);
if (show_filenames) {
printf("%s:%s", infiles[i]->filename, line);
} else {
printf("%s", line);
}
}
j++;
regfree(&exp);
} while (j < regex_index);
j = 0;
}
i++;
} while (i < files_index);
free(infiles);
}