diff options
Diffstat (limited to '')
-rw-r--r-- | src/commands/ed.c | 198 |
1 files changed, 139 insertions, 59 deletions
diff --git a/src/commands/ed.c b/src/commands/ed.c index 379da3c..d7e8881 100644 --- a/src/commands/ed.c +++ b/src/commands/ed.c @@ -66,14 +66,17 @@ static bool read_regex(char** end, re_t* regex, enum RegexDirection dir) { static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirection dir) { re_t regex; + unsigned long cap, siz, i, until; + long int* buf; + if (!read_regex(end, ®ex, dir)) return false; - unsigned long cap = 8; - unsigned long siz = 0; - long int* buf = malloc(cap * sizeof(long int)); + cap = 8; + siz = 0; + buf = malloc(cap * sizeof(long int)); - unsigned long i = (dir == ALL ? 0 : line_current); - unsigned long until = (dir == BEFORE ? 0 : line_count - 1); + i = (dir == ALL ? 0 : line_current); + until = (dir == BEFORE ? 0 : line_count - 1); for (; (dir == BEFORE ? i >= until : i < until); dir == BEFORE ? i-- : i++) { int len; if (re_matchp(regex, lines[i], &len) == -1) { @@ -112,28 +115,34 @@ static void expand_buffer(long int** buf, unsigned long* cap, unsigned long* siz static bool parse_regex_lines(char** end, struct LineAddress* address) { re_t regex; + unsigned long cap, siz; + long int* buf; + int len; + struct LineAddress addr; + 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; + cap = 8; + siz = 0; + buf = malloc(cap * sizeof(long int)); - struct LineAddress addr = *address; + 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++) { + long int i; + for (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++) { + unsigned long i; + for (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]; @@ -153,6 +162,11 @@ static bool parse_regex_lines(char** end, struct LineAddress* address) { static bool read_address(char** command, bool whitespace, struct LineAddress* a) { char* index = *command; struct LineAddress address; + + char* end_pre; + long int n_pre; + char pre; + memset(&address, 0, sizeof(struct LineAddress)); address.empty = false; @@ -164,8 +178,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) return true; } - char* end_pre; - long int n_pre = strtol(index, &end_pre, 10) - 1; + n_pre = strtol(index, &end_pre, 10) - 1; if (end_pre == index) { n_pre = -1; } else { @@ -176,7 +189,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) index = end_pre; } - char pre = *(index++); + pre = *(index++); switch (pre) { case '.': address.type = INDEX; @@ -188,28 +201,37 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) break; case '-': case '^': { - address.type = INDEX; char* end; - long int n = strtol(index, &end, 10) - 1; + long int n; + + address.type = INDEX; + n = strtol(index, &end, 10) - 1; + if (n < 0) { error_s("input cannot be negative\n"); return false; } + if (index == end) { address.data.index.i = line_current - 1; } else { address.data.index.i = line_current - n; } + if (address.data.index.i < 0) { error_s("line number %ld does not exist\n", address.data.index.i + 1); return false; } + break; } case '+': { - address.type = INDEX; char* end; - long int n = strtol(index, &end, 10) - 1; + long int n; + + address.type = INDEX; + n = strtol(index, &end, 10) - 1; + if (n < 0) { error_s("input cannot be negative\n"); return false; @@ -268,7 +290,8 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) static void free_data(bool all) { if (lines != NULL) { - for (unsigned long i = 0; i < line_count; i++) { + unsigned long i; + for (i = 0; i < line_count; i++) { free(lines[i]); } free(lines); @@ -321,11 +344,11 @@ int ed_getline(char *buf, size_t size) { size_t i = 0; int ch; clearerr(stdin); - while ((ch = getchar()) != EOF) { // Read until EOF ... + while ((ch = getchar()) != EOF) { /* Read until EOF ... */ if (i + 1 < size) { buf[i++] = ch; } - if (ch == '\n') { // ... or end of line + if (ch == '\n') { /* ... or end of line */ break; } } @@ -346,6 +369,8 @@ static void load_file(FILE* file) { } static bool check_if_sure(char* prompt) { + char buf[INPUT_LEN]; + if (!pending_writes) { return true; } @@ -353,7 +378,6 @@ static bool check_if_sure(char* prompt) { printf("%s", prompt); fflush(stdout); - char buf[INPUT_LEN]; if (ed_getline(buf, INPUT_LEN) == EOF) { putchar('\n'); return false; @@ -387,9 +411,12 @@ static void append_lines(unsigned long index, char** new, unsigned long new_len) } static void delete_lines(unsigned long a, unsigned long b) { + unsigned long i; + if (b < a) return; pending_writes = true; - for (unsigned long i = a; i <= b; i++) { + + for (i = a; i <= b; i++) { free(lines[i]); } if (b == line_count - 1) { @@ -403,20 +430,25 @@ static void delete_lines(unsigned long a, unsigned long b) { } static bool handle_append(struct LineAddress* address) { + char** buf; + unsigned long cap, size; + if (address->type != INDEX) { error_s("append command requires index addressing\n"); return false; } + if (line_count == 0) { address->data.index.i = -1; } - char** buf; - unsigned long cap, size; + get_input(stdin, &buf, &cap, &size); + if (size > 0) { append_lines(address->data.index.i + 1, buf, size); printf("ed: appened %lu lines\n", size); } + line_current += size; free(buf); return true; @@ -427,6 +459,7 @@ static bool handle_delete(struct LineAddress* address) { error_s("line number %ld does not exist\n", address->data.index.i + 1); return false; } + if (address->type == INDEX) { delete_lines(address->data.index.i, address->data.index.i); output("deleted line %ld\n", address->data.index.i+1); @@ -434,16 +467,19 @@ static bool handle_delete(struct LineAddress* address) { delete_lines(address->data.range.a, address->data.range.b); output("deleted lines %ld-%ld\n", address->data.range.a+1, address->data.range.b+1); } else if (address->type == SET) { - for (unsigned long i = 0; i < address->data.set.s; i++) { + unsigned long i; + for (i = 0; i < address->data.set.s; i++) { delete_lines(address->data.set.b[i], address->data.set.b[i]); } output("deleted %lu lines\n", address->data.set.s); } + return true; } static bool get_file_name(char** filename) { size_t len = strlen(*filename); + if (len < 1 || (len == 1 && **filename == '\n')) { if (default_filename == NULL) { error_s("no default filename specified\n"); @@ -467,16 +503,23 @@ static bool get_file_name(char** filename) { } static void write_file(char* filename, struct LineAddress* address, char* type) { + FILE* file; + int wrote; + if (line_count < 1) { error_s("cannot write empty file\n"); return; } + if (!get_file_name(&filename)) return; - FILE* file = get_file_s(filename, type); + file = get_file_s(filename, type); if (file == NULL) return; - int wrote = 0; + + wrote = 0; + if (address->empty) { - for (unsigned long i = 0; i < line_count; i++) { + unsigned long i; + for (i = 0; i < line_count; i++) { fprintf(file, "%s", lines[i]); wrote++; } @@ -485,30 +528,38 @@ static void write_file(char* filename, struct LineAddress* address, char* type) fprintf(file, "%s", lines[i]); wrote++; } else if (address->type == RANGE) { - for (long int i = address->data.range.a; i < address->data.range.b; i++) { + long int i; + for (i = address->data.range.a; i < address->data.range.b; i++) { fprintf(file, "%s", lines[i]); wrote++; } } else if (address->type == SET) { - for (unsigned long i = 0; i < address->data.set.s; i++) { + unsigned long i; + for (i = 0; i < address->data.set.s; i++) { fprintf(file, "%s", lines[address->data.set.b[i]]); wrote++; } } + pending_writes = false; fclose(file); output("wrote %d lines from %s\n", wrote, filename); } static void read_file(char* filename) { + FILE* file; + char** buf; + long int line; + unsigned long capacity, size; + if (!get_file_name(&filename)) return; - FILE* file = get_file_s(filename, "r"); + file = get_file_s(filename, "r"); if (file == NULL) return; - unsigned long capacty = 8; - unsigned long size = 0; - char** buf = malloc(capacty * sizeof(char*)); - get_input(file, &buf, &capacty, &size); + capacity = 8; + size = 0; + buf = malloc(capacity * sizeof(char*)); + get_input(file, &buf, &capacity, &size); if (size < 1) { free(buf); @@ -516,10 +567,11 @@ static void read_file(char* filename) { return; } - long int line = -1; + line = -1; if (line_count > 0) { line = line_count - 1; } + append_lines(line, buf, size); free(buf); output("read and appended %lu lines from %s\n", size, filename); @@ -539,24 +591,31 @@ static int substute_string(long int index, long int matches, re_t regex, char* s int capacity = 8; int size = 0; char* buf = malloc(sizeof(char) * capacity); + long int left; int offset = 0; int matches_found = 0; while(true) { + int distance, len; + if (lines[index][offset] == '\0') break; + if (matches_found >= matches && matches > 0) break; - int distance, len; + if ((distance = re_matchp(regex, &lines[index][offset], &len)) == -1) { break; } - if (distance > 0) + + if (distance > 0) { expand_string(&buf, &capacity, &size, &lines[index][offset], distance); + } + expand_string(&buf, &capacity, &size, sub, sub_len); offset += len + distance; matches_found++; } - long int left = strlen(lines[index] + offset); + left = strlen(lines[index] + offset); expand_string(&buf, &capacity, &size, &lines[index][offset], left + 1); free(lines[index]); @@ -565,41 +624,50 @@ static int substute_string(long int index, long int matches, re_t regex, char* s } static void prompt(void) { + char buf[INPUT_LEN]; + char* index; + char cmd; + bool whitespace, linenumbers; + struct LineAddress address; + printf(": "); fflush(stdout); - char buf[INPUT_LEN]; if (ed_getline(buf, INPUT_LEN) == EOF) { putchar('\n'); return; } if (buf[0] == '\0') { putchar('\n'); return; } - char* index = &buf[0]; - bool whitespace = skip_whitespace(&index); + index = &buf[0]; + whitespace = skip_whitespace(&index); - struct LineAddress address; if (!read_address(&index, whitespace, &address)) return; - char cmd = *(index++); + cmd = *(index++); if (cmd == ',') { + struct LineAddress address2; + if (address.type != INDEX) { error_s("comma range addressing requires two index addresses\n"); free_address(address); return; } - struct LineAddress address2; + whitespace = skip_whitespace(&index); + if (!read_address(&index, whitespace, &address2)) { free_address(address); return; } + if (address2.type != INDEX) { error_s("comma range addressing requires two index addresses\n"); free_address(address); free_address(address2); return; } + address.type = RANGE; - address.data.range.a = address.data.index.i; // cursed + address.data.range.a = address.data.index.i; /* cursed */ address.data.range.b = address2.data.index.i; cmd = *(index++); @@ -611,7 +679,8 @@ static void prompt(void) { return; } - bool linenumbers = false; + linenumbers = false; + test: switch (cmd) { case '\0': @@ -663,12 +732,14 @@ test: if (linenumbers) printf("%ld\t", address.data.index.i + 1); printf("%s", lines[address.data.index.i]); } else if (address.type == RANGE) { - for (long int i = address.data.range.a; i <= address.data.range.b; i++) { + long int i; + for (i = address.data.range.a; i <= address.data.range.b; i++) { if (linenumbers) printf("%ld\t", i + 1); printf("%s", lines[i]); } } else if (address.type == SET) { - for (unsigned long i = 0; i < address.data.set.s; i++) { + unsigned long i; + for (i = 0; i < address.data.set.s; i++) { if (linenumbers) printf("%ld\t", address.data.set.b[i] +1); printf("%s", lines[address.data.set.b[i]]); } @@ -698,14 +769,17 @@ test: } goto test; break; - case 's': + case 's': { + char* replace = index; + long int matches, sub_len, matches_found; + unsigned long i; + skip_whitespace(&index); if (*(index++) != '/') { error_s("unexpected character at start of regex\n"); break; } if (!parse_regex_lines(&index, &address)) { return; } - char* replace = index; while(*index != '\0' && *index != '/') index++; if (*index != '/') { error_s("/ missing after %c\n", *index); @@ -716,7 +790,6 @@ test: break; } *(index++) = '\0'; - long int matches; if (*index == '\0' || *index == '\n') { matches = 1; } else if (*index == 'g') { @@ -733,15 +806,16 @@ test: break; } } - long int sub_len = strlen(replace); - long int matches_found = 0; + sub_len = strlen(replace); + matches_found = 0; - for (unsigned long i = 0; i < address.data.set.s; i++) { + for (i = 0; i < address.data.set.s; i++) { matches_found += substute_string(address.data.set.b[i], matches, last_regex, replace, sub_len); } output("replaced %ld matches over %ld lines\n", matches_found, address.data.set.s); pending_writes = true; break; + } case 'w': { bool quit = false; if (*index == 'q') { @@ -766,11 +840,17 @@ test: if (!check_if_sure("Load new file for sure? ")) break; __attribute__((fallthrough)); case 'E': { + char* filename; + FILE* file; + skip_whitespace(&index); - char* filename = index; + + filename = index; if(!get_file_name(&filename)) break; - FILE* file = get_file_s(filename, "r"); + + file = get_file_s(filename, "r"); if (file == NULL) break; + load_file(file); break; } |