update help messages and use addressing range for ed s command

This commit is contained in:
Murphy 2023-04-30 15:51:58 -04:00
parent 91e701881e
commit fa3b1ef748
4 changed files with 126 additions and 27 deletions

View file

@ -27,12 +27,12 @@ static bool printable(char c) {
static void help() { static void help() {
printf("Usage: cat [-nbvteA] [FILE]...\n\n"); printf("Usage: cat [-nbvteA] [FILE]...\n\n");
printf("Print FILEs to stdout\n\n"); printf("Print FILEs to stdout\n\n");
printf("-n Number output lines\n"); printf("\t-n Number output lines\n");
printf("-b Number nonempty lines\n"); printf("\t-b Number nonempty lines\n");
printf("-v Show nonprinting characters as ^x or M-x\n"); printf("\t-v Show nonprinting characters as ^x or M-x\n");
printf("-t ...and tabs as ^I\n"); printf("\t-t ...and tabs as ^I\n");
printf("-e ...and end lines with $\n"); printf("\t-e ...and end lines with $\n");
printf("-A Same as -vte\n"); printf("\t-A Same as -vte\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View file

@ -4,10 +4,10 @@
static void help() { static void help() {
printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n"); printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n");
printf("Copy a file with converting and formatting\n\n"); printf("Copy a file with converting and formatting\n\n");
printf("if=FILE\t\tRead from FILE instead of stdin\n"); printf("\tif=FILE\t\tRead from FILE instead of stdin\n");
printf("of=FILE\t\tWrite to FILE instead of stdout\n"); printf("\tof=FILE\t\tWrite to FILE instead of stdout\n");
printf("bs=N\t\tRead and write N bytes at a time\n"); printf("\tbs=N\t\tRead and write N bytes at a time\n");
printf("count=N\t\tCopy only N input blocks\n"); printf("\tcount=N\t\tCopy only N input blocks\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View file

@ -48,7 +48,7 @@ enum RegexDirection {
ALL 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 c;
char* index = *end; char* index = *end;
char* regex_str = index; char* regex_str = index;
@ -63,12 +63,19 @@ static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirec
break; 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, &regex, dir)) return false;
unsigned long cap = 8; unsigned long cap = 8;
unsigned long siz = 0; unsigned long siz = 0;
long int* buf = malloc(cap * sizeof(unsigned long)); long int* buf = malloc(cap * sizeof(long int));
re_t regex = re_compile(regex_str);
last_regex = regex;
unsigned long i = (dir == ALL ? 0 : line_current); unsigned long i = (dir == ALL ? 0 : line_current);
unsigned long until = (dir == BEFORE ? 0 : line_count - 1); 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) { if (cap == siz) {
cap *= 2; cap *= 2;
buf = realloc(buf, cap * sizeof(unsigned long)); buf = realloc(buf, cap * sizeof(long int));
} }
buf[siz] = i; buf[siz] = i;
siz++; siz++;
@ -92,7 +99,74 @@ static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirec
address->data.set.s = siz; address->data.set.s = siz;
address->data.set.c = cap; address->data.set.c = cap;
address->data.set.b = buf; 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, &regex, 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; return true;
} }
@ -212,12 +286,6 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
return true; 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) { static void free_data(bool all) {
if (lines != NULL) { if (lines != NULL) {
for (unsigned long i = 0; i < line_count; i++) { for (unsigned long i = 0; i < line_count; i++) {
@ -621,7 +689,7 @@ test:
} }
} else if (address.type == SET) { } else if (address.type == SET) {
for (unsigned long i = 0; i < address.data.set.s; i++) { 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]]); printf("%s", lines[address.data.set.b[i]]);
} }
} }
@ -652,12 +720,11 @@ test:
break; break;
case 's': case 's':
skip_whitespace(&index); skip_whitespace(&index);
free_address(address);
if (*(index++) != '/') { if (*(index++) != '/') {
fprintf(stderr, "error: unexpected character at start of regex\n"); fprintf(stderr, "error: unexpected character at start of regex\n");
break; break;
} }
if (!parse_regex(&index, &address, ALL)) { return; } if (!parse_regex_lines(&index, &address)) { return; }
char* replace = index; char* replace = index;
while(*index != '\0' && *index != '/') index++; while(*index != '\0' && *index != '/') index++;
if (*index != '/') { if (*index != '/') {
@ -670,7 +737,7 @@ test:
} }
*(index++) = '\0'; *(index++) = '\0';
long int matches; long int matches;
if (*index == '\0') { if (*index == '\0' || *index == '\n') {
matches = 1; matches = 1;
} else if (*index == 'g') { } else if (*index == 'g') {
matches = -1; 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) { COMMAND(ed) {
if (argc < 1) { if (argc < 1) {
load_empty(); load_empty();
prompt_loop(); prompt_loop();
} else if (streql(argv[0], "--help")) {
help();
} else { } else {
FILE* file = get_file(argv[0], "r"); FILE* file = get_file(argv[0], "r");
load_file(file); load_file(file);

View file

@ -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) { COMMAND(print) {
if (argc < 1) { if (argc < 1) {
error("usage: printf FORMAT [ARG]...\n"); error("usage: printf FORMAT [ARG]...\n");
} }
if (streql("--help", argv[0])) help();
size_t index = 0; size_t index = 0;
int arg_index = 0; int arg_index = 0;