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() {
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);
}

View file

@ -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);
}

View file

@ -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, &regex, 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, &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;
}
@ -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);

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