diff --git a/src/commands/cat.c b/src/commands/cat.c index dd1a732..b862c13 100644 --- a/src/commands/cat.c +++ b/src/commands/cat.c @@ -27,12 +27,12 @@ static bool printable(char c) { static void help() { printf("Usage: cat [-nbvteA] [FILE]...\n\n"); printf("Print FILEs to stdout\n\n"); - printf("-n Number output lines\n"); - printf("-b Number nonempty lines\n"); - printf("-v Show nonprinting characters as ^x or M-x\n"); - printf("-t ...and tabs as ^I\n"); - printf("-e ...and end lines with $\n"); - printf("-A Same as -vte\n"); + printf("\t-n Number output lines\n"); + printf("\t-b Number nonempty lines\n"); + printf("\t-v Show nonprinting characters as ^x or M-x\n"); + printf("\t-t ...and tabs as ^I\n"); + printf("\t-e ...and end lines with $\n"); + printf("\t-A Same as -vte\n"); exit(EXIT_SUCCESS); } diff --git a/src/commands/dd.c b/src/commands/dd.c index 8acde7d..87c9eb8 100644 --- a/src/commands/dd.c +++ b/src/commands/dd.c @@ -4,10 +4,10 @@ static void help() { printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n"); printf("Copy a file with converting and formatting\n\n"); - printf("if=FILE\t\tRead from FILE instead of stdin\n"); - printf("of=FILE\t\tWrite to FILE instead of stdout\n"); - printf("bs=N\t\tRead and write N bytes at a time\n"); - printf("count=N\t\tCopy only N input blocks\n"); + printf("\tif=FILE\t\tRead from FILE instead of stdin\n"); + printf("\tof=FILE\t\tWrite to FILE instead of stdout\n"); + printf("\tbs=N\t\tRead and write N bytes at a time\n"); + printf("\tcount=N\t\tCopy only N input blocks\n"); exit(EXIT_SUCCESS); } diff --git a/src/commands/ed.c b/src/commands/ed.c index 7c55ce0..87dd580 100644 --- a/src/commands/ed.c +++ b/src/commands/ed.c @@ -48,7 +48,7 @@ enum RegexDirection { ALL }; -static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirection dir) { +static bool read_regex(char** end, re_t* regex, enum RegexDirection dir) { char c; char* index = *end; char* regex_str = index; @@ -63,12 +63,19 @@ static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirec break; } } + *regex = re_compile(regex_str); + last_regex = *regex; + *end = index; + return true; +} + +static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirection dir) { + re_t regex; + if (!read_regex(end, ®ex, dir)) return false; + unsigned long cap = 8; unsigned long siz = 0; - long int* buf = malloc(cap * sizeof(unsigned long)); - - re_t regex = re_compile(regex_str); - last_regex = regex; + long int* buf = malloc(cap * sizeof(long int)); unsigned long i = (dir == ALL ? 0 : line_current); unsigned long until = (dir == BEFORE ? 0 : line_count - 1); @@ -80,7 +87,7 @@ static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirec } if (cap == siz) { cap *= 2; - buf = realloc(buf, cap * sizeof(unsigned long)); + buf = realloc(buf, cap * sizeof(long int)); } buf[siz] = i; siz++; @@ -92,7 +99,74 @@ static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirec address->data.set.s = siz; address->data.set.c = cap; address->data.set.b = buf; - *end = index; + return true; +} + +static void free_address (struct LineAddress address) { + if (address.type != SET) return; + address.type = FREE; + free(address.data.set.b); +} + +static void expand_buffer(long int** buf, unsigned long* cap, unsigned long* size) { + if (*cap == *size) { + *cap *= 2; + *buf = realloc(*buf, sizeof(long int) * *cap); + } +} + +static bool parse_regex_lines(char** end, struct LineAddress* address) { + re_t regex; + if (!read_regex(end, ®ex, ALL)) return false; + + unsigned long cap = 8; + unsigned long siz = 0; + long int* buf = malloc(cap * sizeof(long int)); + int len; + + struct LineAddress addr = *address; + if (addr.type == INDEX) { + if (re_matchp(regex, lines[addr.data.index.i], &len) != -1) { + buf[0] = addr.data.index.i; + siz = 1; + } + } else if (addr.type == RANGE) { + for (long int i = addr.data.range.a; i < addr.data.range.b; i++) { + if (re_matchp(regex, lines[i], &len) == -1) continue; + expand_buffer(&buf, &cap, &siz); + buf[siz] = i; + siz++; + } + } else if (addr.type == SET) { + for (unsigned long i = 0; i < addr.data.set.s; i++) { + if (re_matchp(regex, lines[addr.data.set.b[i]], &len) == -1) continue; + expand_buffer(&buf, &cap, &siz); + buf[siz] = addr.data.set.b[i]; + siz++; + } + } + + // for (; (dir == BEFORE ? i >= until : i < until); dir == BEFORE ? i-- : i++) { + // int len; + // if (re_matchp(regex, lines[i], &len) == -1) { + // if (dir == BEFORE && i == 0) break; + // continue; + // } + // if (cap == siz) { + // cap *= 2; + // buf = realloc(buf, cap * sizeof(unsigned long)); + // } + // buf[siz] = i; + // siz++; + // if (dir == BEFORE && i == 0) break; + // } + + free_address(*address); + address->empty = false; + address->type = SET; + address->data.set.s = siz; + address->data.set.c = cap; + address->data.set.b = buf; return true; } @@ -212,12 +286,6 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) return true; } -static void free_address (struct LineAddress address) { - if (address.type != SET) return; - address.type = FREE; - free(address.data.set.b); -} - static void free_data(bool all) { if (lines != NULL) { for (unsigned long i = 0; i < line_count; i++) { @@ -621,7 +689,7 @@ test: } } else if (address.type == SET) { for (unsigned long i = 0; i < address.data.set.s; i++) { - if (linenumbers) printf("%ld\t", i +1); + if (linenumbers) printf("%ld\t", address.data.set.b[i] +1); printf("%s", lines[address.data.set.b[i]]); } } @@ -652,12 +720,11 @@ test: break; case 's': skip_whitespace(&index); - free_address(address); if (*(index++) != '/') { fprintf(stderr, "error: unexpected character at start of regex\n"); break; } - if (!parse_regex(&index, &address, ALL)) { return; } + if (!parse_regex_lines(&index, &address)) { return; } char* replace = index; while(*index != '\0' && *index != '/') index++; if (*index != '/') { @@ -670,7 +737,7 @@ test: } *(index++) = '\0'; long int matches; - if (*index == '\0') { + if (*index == '\0' || *index == '\n') { matches = 1; } else if (*index == 'g') { matches = -1; @@ -745,10 +812,34 @@ static void prompt_loop() { } } +static void help() { + printf("Usage: ed [FILE]\n\n"); + printf("Edit a given [FILE] or create a new text file\n\n"); + printf("\t(.,.)\tnewline\t\tgo to address line and print\n"); + printf("\t(.)\ta\t\tappend new data after given line\n"); + printf("\t(.,.)\tc\t\treplace given lines with new data\n"); + printf("\t(.,.)\td\t\tdelete given lines\n"); + printf("\t\te file\t\tdelete current buffer and edit file\n"); + printf("\t\tE file\t\tdelete current buffer and edit file unconditionally\n"); + printf("\t\tg/re/command\tgrep all lines with regex and run command on matches\n"); + printf("\t(.,.)\tn\t\tprint given lines along with their line numbers\n"); + printf("\t(.,.)\tp\t\tprint given lines\n"); + printf("\t\tq\t\tquit file\n"); + printf("\t\tQ\t\tquit file unconditionally\n"); + printf("\t($)\tr file\t\tread file and append to end of buffer\n"); + printf("\t(.,.)\ts/re/replace/\treplace text at matching regex\n"); + printf("\t(.,.)\tw file\t\twrite contents of lines to file\n"); + printf("\t(.,.)\twq file\t\twrite contents of lines to file then quit\n"); + printf("\t(.,.)\tW file\t\tappend contents of line to file\n"); + exit(EXIT_SUCCESS); +} + COMMAND(ed) { if (argc < 1) { load_empty(); prompt_loop(); + } else if (streql(argv[0], "--help")) { + help(); } else { FILE* file = get_file(argv[0], "r"); load_file(file); diff --git a/src/commands/printf.c b/src/commands/printf.c index 7539316..ce1631c 100644 --- a/src/commands/printf.c +++ b/src/commands/printf.c @@ -79,11 +79,19 @@ static void handle_slash(char n) { } } +static void help() { + printf("Usage printf FORMAT [ARG]...\n\n"); + printf("Format and print ARG(s) according to FORMAT (a-la C prinf)\n"); + exit(EXIT_SUCCESS); +} + COMMAND(print) { if (argc < 1) { error("usage: printf FORMAT [ARG]...\n"); } + if (streql("--help", argv[0])) help(); + size_t index = 0; int arg_index = 0;