From 82656bf5aa4edd668e1adc3faa8148251509b912 Mon Sep 17 00:00:00 2001 From: zlg Date: Thu, 16 Jun 2016 09:51:16 -0700 Subject: Solve Exercise 7-2: Format arbitrary input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- ch7/7-02_arb-input.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 ch7/7-02_arb-input.c (limited to 'ch7') 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 +#include +#include + +/* 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); + } +} -- cgit v1.2.3-54-g00ecf