update help messages and use addressing range for ed s command
This commit is contained in:
parent
91e701881e
commit
fa3b1ef748
4 changed files with 126 additions and 27 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, ®ex, 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, ®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;
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue