2023-05-06 04:39:44 +00:00
|
|
|
#include "command.h"
|
|
|
|
#include "lslib.h"
|
2023-04-27 18:38:16 +00:00
|
|
|
|
|
|
|
#include <ctype.h>
|
2023-05-06 04:39:44 +00:00
|
|
|
#include <stdlib.h>
|
2023-04-27 18:38:16 +00:00
|
|
|
|
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;
|
2023-05-04 20:10:37 +00:00
|
|
|
default: return isprint(c) == 0;
|
2023-04-27 18:38:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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");
|
2023-04-30 19:51:58 +00:00
|
|
|
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-05-15 14:57:33 +00:00
|
|
|
COMMAND(cat_main) {
|
2023-04-27 18:38:16 +00:00
|
|
|
|
2023-05-04 20:10:37 +00:00
|
|
|
int start;
|
|
|
|
int arg_len;
|
|
|
|
int i;
|
|
|
|
|
2023-04-27 18:38:16 +00:00
|
|
|
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-04 20:10:37 +00:00
|
|
|
start = parse_args(argc, argv, help, short_arg, NULL);
|
2023-04-27 18:38:16 +00:00
|
|
|
|
2023-05-04 20:10:37 +00:00
|
|
|
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
|
|
|
|
2023-05-04 20:10:37 +00:00
|
|
|
for (i = start; i < argc; i++) {
|
2023-04-30 06:12:02 +00:00
|
|
|
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;
|
|
|
|
}
|