summaryrefslogtreecommitdiff
path: root/src/cat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cat.c')
-rw-r--r--src/cat.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/cat.c b/src/cat.c
new file mode 100644
index 0000000..7901a89
--- /dev/null
+++ b/src/cat.c
@@ -0,0 +1,82 @@
+/*
+ * cat.c
+ * Implementation of SUSv3 XCU cat utility
+ * Copyright © 2007 Rich Felker
+ * Licensed under the terms of the GNU General Public License, v2 or later
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int my_write(int fd, const char *s, size_t l)
+{
+ while (l) {
+ ssize_t n = write(fd, s, l);
+ if (n<0) return -1;
+ s += n; l -= n;
+ }
+ return 0;
+}
+
+static void my_perror(char *prog, char *msg)
+{
+ char *err = strerror(errno);
+ write(2, prog, strlen(prog));
+ write(2, ": ", 2);
+ write(2, msg, strlen(msg));
+ write(2, ": ", 2);
+ write(2, err, strlen(err));
+ write(2, "\n", 1);
+}
+
+int main(int argc, char *argv[])
+{
+ char buf[4096];
+ char **v = argv+1;
+ int n = argc-1;
+ ssize_t i, k, l;
+ int err = 0;
+ int fd;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ for (; n && v[0][0] == '-' && v[0][1]; v++, n--) {
+ if (v[0][1]=='-' && !v[0][2]) { /* -- */
+ v++; n--;
+ break;
+ }
+ if (v[0][1]!='u' || v[0][2]) { /* not -u */
+ errno = EINVAL;
+ my_perror(argv[0], v[0]);
+ exit(1);
+ }
+ }
+ if (!n) {
+ n = 1;
+ v = (char *[]){ "-", NULL };
+ }
+ for (; n; v++, n--) {
+ if (v[0][0] == '-' && !v[0][1]) fd = 0;
+ else if ((fd = open(v[0], O_RDONLY)) < 0) {
+ my_perror(argv[0], v[0]);
+ err = 1;
+ continue;
+ }
+ while ((l = read(fd, buf, sizeof buf)) > 0) {
+ if (my_write(1, buf, l) < 0) {
+ my_perror(argv[0], "write error");
+ exit(1);
+ }
+ }
+ if (l) {
+ my_perror(argv[0], v[0]);
+ err = 1;
+ }
+ if (fd) close(fd);
+ }
+ return err;
+}