lazysphere/src/commands/cat.c

137 lines
3.2 KiB
C
Raw Normal View History

2023-04-27 18:38:16 +00:00
#include "../command.h"
#include <ctype.h>
2023-05-01 22:43:32 +00:00
static struct {
2023-04-27 18:38:16 +00:00
bool number_lines;
bool number_non_empty;
bool change_non_print;
bool change_tabs;
bool end_lines_dollar;
2023-05-01 22:43:32 +00:00
} flags;
2023-04-27 18:38:16 +00:00
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);
}
}
2023-05-01 22:43:32 +00:00
static void help(void) {
2023-04-27 18:38:16 +00:00
printf("Usage: cat [-nbvteA] [FILE]...\n\n");
printf("Print FILEs to stdout\n\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");
2023-04-27 18:38:16 +00:00
}
2023-05-01 22:43:32 +00:00
static void cat_file(FILE* file) {
2023-04-27 18:38:16 +00:00
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);
}
}
}
2023-05-01 22:43:32 +00:00
static int short_arg(char c, char* next) {
UNUSED(next);
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:
2023-05-03 16:17:56 +00:00
return ARG_INVALID;
2023-05-01 22:43:32 +00:00
}
return ARG_UNUSED;
}
2023-04-27 18:38:16 +00:00
COMMAND(cat) {
flags.number_lines = false;
flags.number_non_empty = false;
flags.change_non_print = false;
flags.change_tabs = false;
flags.end_lines_dollar = false;
2023-05-01 22:43:32 +00:00
int start = parse_args(argc, argv, help, short_arg, NULL);
2023-04-27 18:38:16 +00:00
2023-04-30 06:12:02 +00:00
int arg_len = argc - start;
2023-04-27 18:38:16 +00:00
2023-04-30 06:12:02 +00:00
if (arg_len < 1) {
2023-05-01 22:43:32 +00:00
cat_file(stdin);
2023-04-30 06:12:02 +00:00
return EXIT_SUCCESS;
2023-04-27 18:38:16 +00:00
}
2023-04-30 06:12:02 +00:00
for (int i = start; i < argc; i++) {
FILE* in = get_file(argv[i], "r");
2023-05-01 22:43:32 +00:00
cat_file(in);
2023-04-30 06:12:02 +00:00
if (in != stdin)
fclose(in);
}
2023-04-27 18:38:16 +00:00
return EXIT_SUCCESS;
}