aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzlg <zlg@zlg.space>2017-05-20 01:13:28 -0700
committerzlg <zlg@zlg.space>2017-05-20 01:13:28 -0700
commit443c8b479d7ca0bf45f691ab2da6fb8d35045d1f (patch)
treec3fe6c39af9192baabb29501fedb35975f57732c
parentSolve Exercise 7-9: isupper, time, and space (diff)
downloadknr-443c8b479d7ca0bf45f691ab2da6fb8d35045d1f.tar.gz
knr-443c8b479d7ca0bf45f691ab2da6fb8d35045d1f.tar.bz2
knr-443c8b479d7ca0bf45f691ab2da6fb8d35045d1f.tar.xz
knr-443c8b479d7ca0bf45f691ab2da6fb8d35045d1f.zip
Solve Exercise 8-1: `cat` remastered
-rw-r--r--ch8/8-01_cat-remastered.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/ch8/8-01_cat-remastered.c b/ch8/8-01_cat-remastered.c
new file mode 100644
index 0000000..5e11ca8
--- /dev/null
+++ b/ch8/8-01_cat-remastered.c
@@ -0,0 +1,115 @@
+#include <stdio.h> /* printf and friends */
+#include <fcntl.h> /* open, creat, etc */
+#include <unistd.h> /* read, close */
+#include <stdarg.h> /* va_* */
+#include <stdlib.h> /* exit */
+
+/* The C Programming Language: 2nd Edition
+ *
+ * Exercise 8-1: Rewrite the program `cat` from Chapter 7 using read(),
+ * write(), open(), and close() instead of their standard library
+ * equivalents. Perferm experiments to determine the relative speeds of
+ * the two versions.
+ *
+ * Notes: The `cat` program can be found on pp 162-163 in the book.
+ */
+
+#define DEBUG 0
+
+char buf;
+/* Let's have fewer magic numbers */
+enum {
+ STDIN,
+ STDOUT,
+ STDERR
+};
+
+#if DEBUG == 1
+/* d_printf - output a debug message
+ * This was shamelessly taken from the book
+ */
+void d_printf(char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "debug: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+}
+#endif
+
+void in2out() {
+ int status;
+ while ((status = read(STDIN, &buf, 1))) {
+ if (status != -1) {
+ status = write(STDOUT, &buf, 1);
+ if (status == -1) {
+ fprintf(stderr, "error: Could not write to stdout; something is very wrong.\n");
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "error: Could not read stdin; something is very wrong.\n");
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ int fd;
+ /* Remember the name we were invoked as, for messages */
+ ssize_t fstatus;
+ argv++;
+#if DEBUG == 1
+ char *prog = *argv;
+ d_printf("Starting %s", prog);
+#endif
+ if (argc == 1) {
+#if DEBUG == 1
+ d_printf("No arguments specified; copying stdin to stdout");
+#endif
+ in2out();
+ argv++;
+ exit(0);
+ }
+ /* The trick to understanding this is "x--" will run one more time than
+ * expected, because it doesn't decrement until after it's been evaluated
+ * for use in the expression. You can also look at it as "we've already
+ * pushed argv ahead by one".
+ */
+ while (argc-- > 1) {
+#if DEBUG == 1
+ d_printf("Trying to open %s", *argv);
+#endif
+ fd = open(*argv, O_RDONLY, 0);
+ if (fd != -1) {
+#if DEBUG == 1
+ d_printf("It was successfully opened. Reading.");
+#endif
+ while ((fstatus = read(fd, &buf, 1))) {
+ if (fstatus == (-1)) {
+ /* Fail early, fail often */
+ fprintf(stderr, "error: Cannot read from '%s'. \n", *argv);
+ close(fd);
+ return 1;
+ }
+ if ((fstatus = write(STDOUT, &buf, 1)) == (-1)) {
+ fprintf(stderr, "error: Cannot write to stdout.\n");
+ close(fd);
+ return 1;
+ }
+ }
+#if DEBUG == 1
+ d_printf("%s read complete.", *argv);
+#endif
+ } else {
+ fprintf(stderr, "error: Could not open file '%s' for reading.\n", *argv);
+ close(fd);
+ return 1;
+ }
+#if DEBUG == 1
+ d_printf("Closing file %s.", *argv);
+#endif
+ close(fd);
+ argv++;
+ }
+ exit(0);
+}