aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Cabergs <me@cacharle.xyz>2020-08-08 17:16:08 +0200
committerCharles Cabergs <me@cacharle.xyz>2020-08-08 17:16:08 +0200
commit2c513e352142d1e19340ca2c12beb54657e9254a (patch)
treef0d92a28a9e27616321facda970ceed5ff994a37
parent284e1b7a5c4b1b0b0f38d16ecb1507ea4ac964f4 (diff)
downloadcoreutils-2c513e352142d1e19340ca2c12beb54657e9254a.tar.gz
coreutils-2c513e352142d1e19340ca2c12beb54657e9254a.tar.bz2
coreutils-2c513e352142d1e19340ca2c12beb54657e9254a.zip
Added tee
-rw-r--r--README.md15
-rw-r--r--tee.c68
2 files changed, 76 insertions, 7 deletions
diff --git a/README.md b/README.md
index 2d090f0..0e0f3b9 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,11 @@
Rewrite of some core utilities for educational purposes.
-| Name | Description |
-|------------|-------------------------------------------|
-| `mkdir` | make directories |
-| `basename` | strip directory and suffix from filenames |
-| `cut` | remove sections from each line of files |
-| `rm` | remove files or directories |
-| `seq` | print a sequence of numbers |
+| Name | Description |
+|------------|-----------------------------------------------------------------|
+| `mkdir` | make directories |
+| `basename` | strip directory and suffix from filenames |
+| `cut` | remove sections from each line of files |
+| `rm` | remove files or directories |
+| `seq` | print a sequence of numbers |
+| `tee` | read from standard input and write to standard output and files |
diff --git a/tee.c b/tee.c
new file mode 100644
index 0000000..4df5074
--- /dev/null
+++ b/tee.c
@@ -0,0 +1,68 @@
+#define _POSIX_C_SOURCE 2 // getopt
+#define _XOPEN_SOURCE 500 // sigaction
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+
+#define BUFFER_SIZE 2048
+
+char *g_name = "tee";
+
+int main(int argc, char **argv)
+{
+ int option;
+ bool append = false;
+
+ g_name = argv[0];
+
+ struct sigaction action;
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = SA_NODEFER;
+
+ while ((option = getopt(argc, argv, "ai")) != -1)
+ {
+ switch (option)
+ {
+ case 'a':
+ append = true;
+ break;
+ case 'i':
+ sigaction(SIGINT, &action, NULL);
+ break;
+ }
+ }
+
+ size_t files_num = argc - optind;
+ FILE **files = calloc(files_num, sizeof(FILE*));
+ if (files == NULL)
+ return EXIT_FAILURE;
+
+ for (size_t i = 0; i < files_num; i++)
+ {
+ files[i] = fopen(argv[optind + i], append ? "a" : "w");
+ if (files[i] == NULL)
+ {
+ fprintf(stderr, "%s: %s: %s\n", g_name, argv[optind + i], strerror(errno));
+ i--;
+ files_num--;
+ }
+ }
+
+ char buf[BUFFER_SIZE + 1] = {0};
+ size_t read_size = 0;
+ while ((read_size = fread(buf, 1, BUFFER_SIZE, stdin)) > 0)
+ {
+ fwrite(buf, 1, read_size, stdout);
+ for (size_t i = 0; i < files_num; i++)
+ fwrite(buf, 1, read_size, files[i]);
+ }
+
+ for (size_t i = 0; i < files_num; i++)
+ fclose(files[i]);
+ free(files);
+ return EXIT_SUCCESS;
+}