lazysphere/src/commands/cat.c

153 lines
3.8 KiB
C
Raw Normal View History

2023-04-27 18:38:16 +00:00
#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");
2023-04-27 23:13:40 +00:00
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");
2023-04-27 18:38:16 +00:00
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;
}