diff options
Diffstat (limited to 'src/commands')
-rw-r--r-- | src/commands/cat.c | 152 | ||||
-rw-r--r-- | src/commands/dd.c | 59 | ||||
-rw-r--r-- | src/commands/yes.c | 26 |
3 files changed, 237 insertions, 0 deletions
diff --git a/src/commands/cat.c b/src/commands/cat.c new file mode 100644 index 0000000..e2c471b --- /dev/null +++ b/src/commands/cat.c @@ -0,0 +1,152 @@ +#include "../command.h" + +#include <ctype.h> +#include <string.h> + +struct Flags { + bool number_lines; + bool number_non_empty; + bool change_non_print; + bool change_tabs; + bool end_lines_dollar; +}; + +static bool printable(char c) { + switch (c) { + case '\n': return true; + case '\r': return true; + case '\b': return true; + case '\t': return true; + default: return isprint(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"); + exit(EXIT_SUCCESS); +} + +static void cat_file(FILE* file, struct Flags flags) { + char c; + size_t read; + + size_t line = 1; + bool empty = true; + bool newline = true; + + while ((read = fread(&c, 1, 1, file)) != 0) { + if (c == '\n') { + if (empty && flags.number_lines) { + printf("\t%ld ", line); + } + if (flags.end_lines_dollar) { + printf("$"); + } + line++; + newline = true; + empty = true; + goto print; + } else { + empty = false; + } + + if (!newline) { + goto print; + } + + if (!empty && (flags.number_non_empty || flags.number_lines)) { + printf("\t%ld ", line); + newline = false; + } + print: + if (!flags.change_non_print || printable(c)) { + if (flags.change_tabs && c == '\t') { + fwrite("^I", 1, 2, stdout); + } else { + fwrite(&c, 1, 1, stdout); + } + } else { + c |= '@'; + fwrite(&c, 1, 1, stdout); + } + } +} + +COMMAND(cat) { + + struct Flags flags; + flags.number_lines = false; + flags.number_non_empty = false; + flags.change_non_print = false; + flags.change_tabs = false; + flags.end_lines_dollar = false; + + for (int i = 0; i < argc; i++) { + if (!prefix("-", argv[i])) { + continue; + } + + if (streql("--help", argv[i])) { + help(); + } + + size_t len = strlen(argv[i] + 1); + for (size_t j = 0; j < len; j++) { + char c = argv[i][j + 1]; + switch (c) { + case 'n': + flags.number_lines = true; + break; + case 'b': + flags.number_non_empty = true; + break; + case 'v': + flags.change_non_print = true; + break; + case 't': + flags.change_non_print = true; + flags.change_tabs = true; + break; + case 'e': + flags.change_non_print = true; + flags.end_lines_dollar = true; + break; + case 'A': + flags.change_non_print = true; + flags.change_tabs = true; + flags.end_lines_dollar = true; + break; + default: + error("error: unkown flag -%c", c); + } + } + } + + bool files = false; + for (int i = 0; i < argc; i++) { + if (streql("-", argv[i])) { + files = true; + cat_file(stdin, flags); + } else if (prefix("-", argv[i])) { + continue; + } else { + files = true; + FILE* in = get_file(argv[i], "r"); + cat_file(in, flags); + fclose(in); + } + } + + if (!files) { + cat_file(stdin, flags); + } + + return EXIT_SUCCESS; +} diff --git a/src/commands/dd.c b/src/commands/dd.c new file mode 100644 index 0000000..278dee3 --- /dev/null +++ b/src/commands/dd.c @@ -0,0 +1,59 @@ +#include "../command.h" +#include <stdio.h> + +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"); + exit(EXIT_SUCCESS); +} + +COMMAND(dd) { + + FILE* in_file = stdin; + FILE* out_file = stdout; + int bs = 1024; + int count = -1; + + for (int i = 0; i < argc; i++) { + if (prefix("if=", argv[i])) { + char* path = argv[i] + 3; + in_file = get_file(path, "rb"); + } else if (prefix("of=", argv[i])) { + char* path = argv[i] + 3; + out_file = get_file(path, "wb"); + } else if (prefix("bs=", argv[i])) { + char* str = argv[i] + 3; + bs = get_number(str); + if (bs < 1) { + error("error: block size must be greater than 0"); + } + } else if (prefix("count=", argv[i])) { + char* str = argv[i] + 6; + count = get_number(str); + if (count < 1) { + error("error: count must be greather than 0"); + } + } else if (streql("--help", argv[i])) { + help(); + } else { + error("error: unkown option %s", argv[i]); + } + } + + char* buffer = malloc(bs); + size_t read; + while ((read = fread(buffer, 1, bs, in_file)) != 0) { + fwrite(buffer, 1, read, out_file); + if (--count, count == 0) break; + } + + free(buffer); + fclose(in_file); + fclose(out_file); + + return EXIT_SUCCESS; +} diff --git a/src/commands/yes.c b/src/commands/yes.c new file mode 100644 index 0000000..c954810 --- /dev/null +++ b/src/commands/yes.c @@ -0,0 +1,26 @@ +#include "../command.h" + +static void help() { + printf("Usage: yes [STRING]\n\n"); + printf("Repeatedly output a line with all specified STRING(s), or 'y'.\n"); + exit(EXIT_SUCCESS); +} + +COMMAND(yes) { + const char* repeat; + if (argc == 0) { + repeat = "y"; + } else { + if (streql("--help", argv[0])) { + help(); + } + repeat = argv[0]; + for (int i = 1; i < argc; i++) { + *(argv[i]-1) = ' '; + } + } + + while (true) { + printf("%s\n", repeat); + } +} |