aboutsummaryrefslogtreecommitdiff
path: root/ch7/7-02_arb-input.c
diff options
context:
space:
mode:
Diffstat (limited to 'ch7/7-02_arb-input.c')
-rw-r--r--ch7/7-02_arb-input.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/ch7/7-02_arb-input.c b/ch7/7-02_arb-input.c
new file mode 100644
index 0000000..2c8fbc9
--- /dev/null
+++ b/ch7/7-02_arb-input.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/* The C Programming Language: 2nd Edition
+ *
+ * Exercise 7-2: Write a program that will print arbitrary input in a sensible
+ * way. As a minimum, it should print non-graphic characters in octal or
+ * hexadecimal according to local custom, and break long text lines.
+ *
+ * Notes: I spent some time thinking about this one. I'm somewhat picky in how
+ * I expect text to be handled, but the requirements are Spartan. Therefore, I
+ * will provide a Spartan solution. :)
+ *
+ * Linux printf formats don't seem to allow for truncation of hex or octal,
+ * so there wasn't an (easy, cat-zero friendly) way to work with the widths
+ * produced by the format strings. However, the program compiles, it has
+ * argument switches, it smartly breaks lines, and expands non-printable
+ * characters. It does exactly what it's supposed to. :)
+ */
+
+#define MAXLINELEN 81
+#define MAXBUF 102400
+
+#define HEX 16
+#define OCT 8
+
+int fmt;
+
+int mygetline(char s[], int max) {
+ int c, i;
+ i = 0;
+ while (max-- > 0 && (c = getchar()) != EOF && c != '\n') {
+ s[i++] = c;
+ }
+ if (c == '\n') {
+ s[i++] = c;
+ }
+ s[i] = '\0';
+ return i;
+}
+
+void fmt_print(char *s) {
+ int i = 0;
+ while (s[i] != '\0') {
+ if (isprint(s[i]) || s[i] == '\n') {
+ putchar(s[i]);
+ } else {
+ if (fmt == HEX) {
+ printf("%4X", s[i]);
+ } else {
+ printf("%3o", s[i]);
+ }
+ }
+ i++;
+ }
+}
+
+void break_lines(char *s) {
+ int fmt = HEX;
+ int c, nl, space;
+ for (c = 0, nl = 0, space = 0; s[c] != '\0'; c++) {
+ /* The position of the last space */
+ if (isspace(s[c])) {
+ space = c;
+ }
+ /* Position of the last new line */
+ if (s[c] == '\n') {
+ nl = c;
+ }
+ if (c == (nl + MAXLINELEN - 1)) {
+ if (space > nl) {
+ s[space] = '\n';
+ nl = space;
+ }
+ }
+ }
+}
+
+void parse_args(int argc, char *argv[]) {
+ int i;
+ while (argc > 1) {
+ --argc;
+ if (argv[argc][0] == '-') {
+ if (argv[argc][1] == 'o' && argv[argc][1] != '\0') {
+ fmt = OCT;
+ } else if (argv[argc][1] == 'h') {
+ fmt = HEX;
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ char buffer[MAXBUF];
+ parse_args(argc, argv);
+ while (mygetline(buffer, MAXBUF)) {
+ break_lines(buffer);
+ fmt_print(buffer);
+ }
+}