141 lines
3.5 KiB
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);
|
|
}
|