fixed xargs, added grep
This commit is contained in:
parent
2980f205df
commit
c601693811
@ -6,6 +6,7 @@ https://trivial.technology/
|
||||
|
||||
Unportable:
|
||||
proc_parser.h
|
||||
|
||||
ps
|
||||
kill
|
||||
dmesg
|
||||
|
@ -93,4 +93,3 @@ mode_t mu_parse_mode(const char *s, mode_t cur_mode) {
|
||||
else
|
||||
return (cur_mode & ~mask) | (mode & mask);
|
||||
}
|
||||
|
||||
|
287
src/grep.c
287
src/grep.c
@ -2,79 +2,314 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
char *pattern;
|
||||
regex_t rgex;
|
||||
} PATTERN;
|
||||
static PATTERN *regexs;
|
||||
static size_t r_size;
|
||||
static struct pattern {
|
||||
char *str;
|
||||
|
||||
regex_t reg;
|
||||
char reg_set;
|
||||
} **ptrns;
|
||||
static size_t ptrns_size = 0;
|
||||
|
||||
static char i_flag;
|
||||
static char F_flag;
|
||||
static char H_flag;
|
||||
static char E_flag;
|
||||
static char v_flag;
|
||||
static char x_flag;
|
||||
static char w_flag;
|
||||
static char mode_flag;
|
||||
static int reg_flag;
|
||||
|
||||
static int addpattern(char *str) {
|
||||
if (regexs == NULL) {
|
||||
regexs = malloc(sizeof(PATTERN));
|
||||
if (regexs == NULL) {
|
||||
fprintf(stderr, "grep: malloc failed\n");
|
||||
static void free_patterns(void) {
|
||||
if (ptrns == NULL)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < ptrns_size; i++) {
|
||||
if (ptrns[i] == NULL)
|
||||
continue;
|
||||
|
||||
if (ptrns[i]->str != NULL)
|
||||
free(ptrns[i]->str);
|
||||
|
||||
if (ptrns[i]->reg_set)
|
||||
regfree(&ptrns[i]->reg);
|
||||
|
||||
free(ptrns[i]);
|
||||
}
|
||||
|
||||
free(ptrns);
|
||||
ptrns = NULL;
|
||||
}
|
||||
|
||||
static int addpattern(const char *str, const size_t size) {
|
||||
if (ptrns == NULL) {
|
||||
ptrns = malloc(sizeof(struct pattern *));
|
||||
if (ptrns == NULL) {
|
||||
fprintf(stderr, "grep: malloc: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
PATTERN *regexs_tmp = realloc(regexs, (r_size + 1) * sizeof(PATTERN));
|
||||
if (regexs_tmp == NULL) {
|
||||
free(regexs);
|
||||
struct pattern **bckp = realloc(ptrns, sizeof(struct pattern *) * (ptrns_size + 1));
|
||||
if (bckp == NULL)
|
||||
goto ADDP_ERROR;
|
||||
ptrns = bckp;
|
||||
|
||||
fprintf(stderr, "grep: realloc failed\n");
|
||||
return 1;
|
||||
ptrns[ptrns_size] = malloc(sizeof(struct pattern));
|
||||
if (ptrns[ptrns_size] == NULL)
|
||||
goto ADDP_ERROR;
|
||||
|
||||
ptrns[ptrns_size]->str = strdup(str);
|
||||
if (ptrns[ptrns_size]->str == NULL)
|
||||
goto ADDP_ERROR;
|
||||
|
||||
if (!F_flag) {
|
||||
char *reg_str = ptrns[ptrns_size]->str;
|
||||
size_t rs_size = size;
|
||||
|
||||
char bol = (ptrns[ptrns_size]->str[0] == '^');
|
||||
char eol = (ptrns[ptrns_size]->str[size - 1] == '^');
|
||||
|
||||
if (x_flag || w_flag) {
|
||||
if (w_flag)
|
||||
rs_size += 5 + ((E_flag) ? 2 : 4);
|
||||
|
||||
reg_str = malloc(rs_size + 4);
|
||||
if (reg_str == NULL)
|
||||
goto ADDP_ERROR;
|
||||
}
|
||||
regexs = regexs_tmp;
|
||||
|
||||
/* Add new pattern */
|
||||
regexs[r_size].pattern = str;
|
||||
if (x_flag)
|
||||
snprintf(reg_str, rs_size + 4, "%s%s%s", (bol) ? "" : "^", ptrns[ptrns_size]->str, (eol) ? "" : "$");
|
||||
|
||||
r_size++;
|
||||
else if (w_flag)
|
||||
snprintf(reg_str, rs_size + 4, "%s\\<%s%.*s%s\\>%s", (bol) ? "^" : "", (E_flag) ? "(" : "\\(", (int)size - bol - eol, ptrns[ptrns_size]->str + bol, (E_flag) ? ")" : "\\)", (eol) ? "$" : "");
|
||||
|
||||
if (regcomp(&ptrns[ptrns_size]->reg, reg_str, reg_flag) < 0)
|
||||
goto ADDP_ERROR;
|
||||
|
||||
ptrns[ptrns_size]->reg_set = 1;
|
||||
if (x_flag || w_flag)
|
||||
free(reg_str);
|
||||
}
|
||||
|
||||
ptrns_size++;
|
||||
return 0;
|
||||
|
||||
ADDP_ERROR:
|
||||
ptrns_size++;
|
||||
free_patterns();
|
||||
fprintf(stderr, "grep: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int addpattern_file(const char *file) {
|
||||
FILE *fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "grep: %s: %s\n", file, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
char *buf = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
ssize_t size = 0;
|
||||
while ((size = getline(&buf, &n, fp)) > 0) {
|
||||
if (size && buf[size - 1] == '\n')
|
||||
buf[size - 1] = '\0';
|
||||
|
||||
if (addpattern(buf, (size_t)size)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf != NULL)
|
||||
free(buf);
|
||||
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmp(const char *str1, const char *str2) {
|
||||
if (x_flag)
|
||||
return !((i_flag) ? strcasecmp : strcmp)(str1, str2);
|
||||
|
||||
else
|
||||
return ((i_flag) ? strcasestr : strstr)(str1, str2) != NULL;
|
||||
}
|
||||
|
||||
static int grep(FILE *fp, const char *file) {
|
||||
int ret = 1;
|
||||
size_t matched_files = 0;
|
||||
regmatch_t m;
|
||||
|
||||
char *buf = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
ssize_t size = 0;
|
||||
while ((size = getline(&buf, &n, fp)) > 0) {
|
||||
if (size && buf[size - 1] == '\n')
|
||||
buf[size - 1] = '\0';
|
||||
|
||||
char match = 0;
|
||||
size_t i = 0;
|
||||
for (; i < ptrns_size; i++) {
|
||||
if (F_flag && cmp(buf, ptrns[i]->str)) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (regexec(&ptrns[i]->reg, buf, 1, &m, 0) == 0) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match != v_flag) {
|
||||
ret = 0;
|
||||
switch (mode_flag) {
|
||||
case 'q':
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (ptrns[i]->reg_set) {
|
||||
unsigned int start = m.rm_so;
|
||||
unsigned int finish = m.rm_eo;
|
||||
printf("%.*s\n", finish - start, buf + start);
|
||||
}
|
||||
|
||||
else
|
||||
puts(ptrns[i]->str);
|
||||
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
matched_files++;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (H_flag)
|
||||
printf("%s: ", file);
|
||||
|
||||
puts(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode_flag == 'c')
|
||||
printf("%zu\n", matched_files);
|
||||
|
||||
if (buf != NULL)
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "e:iFH")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "e:f:iFHEvxwqoc")) != -1) {
|
||||
switch (opt) {
|
||||
case 'e':
|
||||
if (addpattern(optarg))
|
||||
if (addpattern(optarg, strlen(optarg)))
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (addpattern_file(optarg))
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
i_flag = 1;
|
||||
reg_flag |= REG_ICASE;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
F_flag = 1;
|
||||
E_flag = 0;
|
||||
reg_flag &= ~REG_EXTENDED;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
H_flag = 1;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
E_flag = 1;
|
||||
F_flag = 0;
|
||||
reg_flag |= REG_EXTENDED;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
v_flag = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
x_flag = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
w_flag = 1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
mode_flag = 'q';
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
mode_flag = 'o';
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
mode_flag = 'c';
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("grep [eiFH] [FILE]\n\t-e PTRN Pattern to match\n\t-i Ignore case\n\t-H Add 'filename:' prefix\n\t-F PATTERN is a literal (not regexp)\n");
|
||||
puts("grep [efiFHvxwqoc] [FILE]\n\t-e PTRN Pattern to match\n\t-f FILE Read pattern from file\n\t-i Ignore case\n\t-H Add 'filename:' prefix\n\t-F PATTERN is a literal (not regexp)\n\t-E PATTERN is an extended regexp\n\t-v Select non-matching lines\n\t-x Match whole lines only\n\t-w Match whole words only\n\t-q Quiet\n\t-o Show only the matching part of line\n\t-c Show only count of matching lines");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
if (r_size == 0) {
|
||||
if (ptrns_size == 0) {
|
||||
fprintf(stderr, "grep: no patterns specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(regexs);
|
||||
return 0;
|
||||
int ret = 0;
|
||||
if (argc == 0)
|
||||
ret = grep(stdin, "-");
|
||||
|
||||
else {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
FILE *fp = stdin;
|
||||
if (strcmp(argv[i], "-")) {
|
||||
fp = fopen(argv[i], "r");
|
||||
if (fp == NULL) {
|
||||
ret = 1;
|
||||
fprintf(stderr, "grep: %s: %s\n", argv[i], strerror(errno));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (grep(fp, argv[i]))
|
||||
ret = 1;
|
||||
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
free_patterns();
|
||||
return ret;
|
||||
}
|
||||
|
27
src/xargs.c
27
src/xargs.c
@ -82,17 +82,10 @@ static int add_arg(const char *str, size_t chars, int flag) {
|
||||
return ERROR;
|
||||
|
||||
if (!flag && I_flag) {
|
||||
for (int i = 0; i < args; i++) {
|
||||
while (1) {
|
||||
if (strstr(cmd[i], I_flag)) {
|
||||
for (int i = 0; i < args; i++)
|
||||
if (strstr(cmd[i], I_flag))
|
||||
if (Iflag_push(str, &cmd[i]))
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return I_FLAG;
|
||||
}
|
||||
@ -290,23 +283,18 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("xargs [tnsrP0Idt] [cmd [arg1] [arg2...]\n\t-t Print the command before start\n\t-n Pass no more than N args\n\t-r Don't run command if input is empty\n\t-s Pass command line of no more than N bytes\n\t-0 NUL terminated input\n\t-I STR Replace STR within PROG ARGS with input line\n\t-d CHR Use char as delimeter\n\t-i Ignore quotes");
|
||||
puts("xargs [tnsrP0Idti] [cmd [arg1] [arg2...]\n\t-t Print the command before start\n\t-n Pass no more than N args\n\t-r Don't run command if input is empty\n\t-s Pass command line of no more than N bytes\n\t-0 NUL terminated input\n\t-I STR Replace STR within PROG ARGS with input line\n\t-d CHR Use char as delimeter\n\t-i Ignore quotes");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (d_flag)
|
||||
free(d_flag);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (ret)
|
||||
goto CLEAN_UP;
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Arg */
|
||||
if (argc) {
|
||||
for (int i = 0; i < argc; i++)
|
||||
@ -326,7 +314,9 @@ int main(int argc, char **argv) {
|
||||
if (cmd[i] == NULL) {
|
||||
fprintf(stderr, "xargs: strdup failed\n");
|
||||
clear_cmd();
|
||||
return 1;
|
||||
|
||||
ret = 1;
|
||||
goto CLEAN_UP;
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,6 +334,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
}
|
||||
|
||||
CLEAN_UP:
|
||||
if (d_flag)
|
||||
free(d_flag);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user