diff options
author | zlg <zlg@zlg.space> | 2016-06-16 09:51:16 -0700 |
---|---|---|
committer | zlg <zlg@zlg.space> | 2016-06-16 09:51:16 -0700 |
commit | 82656bf5aa4edd668e1adc3faa8148251509b912 (patch) | |
tree | b0ba0ff73b90c875298077fc2dda5098c9ed87cd /ch7 | |
parent | 1-16 solution code and comment style cleanup (diff) | |
download | knr-82656bf5aa4edd668e1adc3faa8148251509b912.tar.gz knr-82656bf5aa4edd668e1adc3faa8148251509b912.tar.bz2 knr-82656bf5aa4edd668e1adc3faa8148251509b912.tar.xz knr-82656bf5aa4edd668e1adc3faa8148251509b912.zip |
Solve Exercise 7-2: Format arbitrary input
The solution is technically not 100% correct, but good luck figuring out
a robust solution inside Category-0 restrictions. Unicode characters
like ¬ or ♥ show up as 64-bit hex codes and I couldn't find a way to
shorten them. Then again, UTF-8 supports characters up to 8 bytes long.
Use it with plain ASCII and it looks only minorly off.
Diffstat (limited to 'ch7')
-rw-r--r-- | ch7/7-02_arb-input.c | 101 |
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); + } +} |