lazysphere/command/cat.c

168 lines
4.6 KiB
C
Raw Normal View History

2023-05-16 23:15:01 +00:00
/**
* file: cat.c
* author: Tyler Murphy
*/
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-16 23:15:01 +00:00
/**
* Flags that are to be used with cat
*/
2023-05-01 22:43:32 +00:00
static struct {
2023-05-16 23:15:01 +00:00
bool number_lines; /* if to number the lines */
bool number_non_empty; /* if to number empty lines */
bool change_non_print; /* if to change non printable characters to be printable */
bool change_tabs; /* if to change tabs to ^I */
bool end_lines_dollar; /* if to print a $ at the end of lines */
2023-05-01 22:43:32 +00:00
} flags;
2023-04-27 18:38:16 +00:00
2023-05-16 23:15:01 +00:00
/**
* Help function for cat
*/
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-16 23:15:01 +00:00
/**
* Give a file pointer, cat all its contents
* @param file the file to cat
*/
2023-05-01 22:43:32 +00:00
static void cat_file(FILE* file) {
2023-05-16 23:15:01 +00:00
char c; /* current character read */
size_t read; /* amount read */
2023-04-27 18:38:16 +00:00
2023-05-16 23:15:01 +00:00
/* default arguments */
size_t line = 1; /* what line we are on, 1 indexed */
bool empty = true; /* if the current line is empty (nothing printed) */
bool newline = true; /* if we are on a new line */
2023-04-27 18:38:16 +00:00
2023-05-16 23:15:01 +00:00
/* read file a character at a time */
2023-04-27 18:38:16 +00:00
while ((read = fread(&c, 1, 1, file)) != 0) {
2023-05-16 23:15:01 +00:00
/* if its a new line, update the new line pointer */
2023-04-27 18:38:16 +00:00
if (c == '\n') {
2023-05-16 23:15:01 +00:00
if (empty && flags.number_lines) { /* print line number if set to */
2023-04-27 18:38:16 +00:00
printf("\t%ld ", line);
}
2023-05-16 23:15:01 +00:00
if (flags.end_lines_dollar) { /* pint $ if set to */
2023-04-27 18:38:16 +00:00
printf("$");
}
line++;
2023-05-16 23:15:01 +00:00
newline = true; /* tell that the new line number is set to be printed */
empty = true; /* set line to empty */
2023-04-27 18:38:16 +00:00
goto print;
} else {
empty = false;
}
2023-05-16 23:15:01 +00:00
/* skip next check if not newline */
2023-04-27 18:38:16 +00:00
if (!newline) {
goto print;
}
2023-05-16 23:15:01 +00:00
/* if on a new line and is a valid char, print line number */
2023-04-27 18:38:16 +00:00
if (!empty && (flags.number_non_empty || flags.number_lines)) {
printf("\t%ld ", line);
newline = false;
}
print:
2023-05-16 23:15:01 +00:00
/* print character */
if (!flags.change_non_print || printable_char(c)) {
2023-04-27 18:38:16 +00:00
if (flags.change_tabs && c == '\t') {
2023-05-16 23:15:01 +00:00
fwrite("^I", 1, 2, stdout); /* print ^I instead of tab */
2023-04-27 18:38:16 +00:00
} else {
2023-05-16 23:15:01 +00:00
fwrite(&c, 1, 1, stdout); /* print character to stdout */
2023-04-27 18:38:16 +00:00
}
2023-05-16 23:15:01 +00:00
} else { /* if set to change non print, fix char code */
2023-04-27 18:38:16 +00:00
c |= '@';
fwrite(&c, 1, 1, stdout);
}
}
}
2023-05-16 23:15:01 +00:00
/**
* Takes in each argument that has a single - and parses it
* @param c the character after the -
* @param next the next argument in argv that hasnt been parsed
* @reutrn if the next arg was used or if the arg was invalid
*/
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-16 23:15:01 +00:00
/**
* Output a files contents
*/
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-05-16 23:15:01 +00:00
/* set flag defaults */
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-16 23:15:01 +00:00
/* parse user arguments */
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-16 23:15:01 +00:00
/* get the number of arguments to cat */
2023-05-04 20:10:37 +00:00
arg_len = argc - start;
2023-04-27 18:38:16 +00:00
2023-05-16 23:15:01 +00:00
/* if not read from stdin */
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-16 23:15:01 +00:00
/* foreach file, try to open it, and then cat it */
2023-05-04 20:10:37 +00:00
for (i = start; i < argc; i++) {
2023-05-16 23:15:01 +00:00
FILE* in = get_file(argv[i], "r"); /* open file as read */
cat_file(in); /* print it out */
2023-04-30 06:12:02 +00:00
if (in != stdin)
fclose(in);
}
2023-05-16 23:15:01 +00:00
return EXIT_SUCCESS; /* success */
2023-04-27 18:38:16 +00:00
}