diff options
Diffstat (limited to 'src/commands/cat.c')
-rw-r--r-- | src/commands/cat.c | 152 |
1 files changed, 152 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; +} |