aboutsummaryrefslogtreecommitdiff
path: root/src/cat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cat.c')
-rw-r--r--src/cat.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/cat.c b/src/cat.c
new file mode 100644
index 0000000..2370d29
--- /dev/null
+++ b/src/cat.c
@@ -0,0 +1,74 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CAT_USAGE "Usage: cat [-u] [file...]\n"
+#define STDIN_ARG "-"
+#define BUFFER_SIZE 20480
+
+static void close_file(int fd) {
+ if (fd != STDIN_FILENO) {
+ close(fd);
+ }
+}
+
+static bool print_file_content(const char *path) {
+ char buffer[BUFFER_SIZE];
+ int input = -1;
+ ssize_t ret = -1;
+
+ if (strcmp(path, STDIN_ARG) == 0) {
+ input = STDIN_FILENO;
+ } else {
+ if ((input = open(path, O_RDONLY)) == -1) {
+ fprintf(stderr,"Can't open file '%s': %s\n", path, strerror(errno));
+ return false;
+ }
+ }
+
+ do {
+ ret = read(input, buffer, BUFFER_SIZE);
+ if (ret > 0) {
+ write(STDOUT_FILENO, buffer, ret);
+ }
+ } while (ret > 0);
+
+ if (ret == -1) {
+ fprintf(stderr, "Failed to read file '%s': %s\n", path, strerror(errno));
+ }
+
+ close_file(input);
+
+ return ret == 0;
+}
+
+int cat_main(int argc, char *argv[]) {
+ int opt = 0;
+ bool ret = false;
+
+ while ((opt = getopt(argc, argv, "u")) != -1) {
+ if (opt != 'u') {
+ perror(CAT_USAGE);
+ return EXIT_FAILURE;
+ }
+ }
+
+ for (int i = optind; i < argc; i++) {
+ ret = print_file_content(argv[i]);
+ if (!ret) {
+ break;
+ }
+ }
+
+ /* If no argument was provided, we use stdin by default */
+ if (argc - optind == 0) {
+ ret = print_file_content(STDIN_ARG);
+ }
+
+ return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+}