/* prints arbitrary input, converting non graphic characters to octal * or hex, at the users specification, and breaking long lines without * splitting words at a user specified width. */ #include #include #include #define MAXWORD 100 #define DEFWIDTH 80 /* default maximum line width */ #define VISSTART 32 /* beginning of graphic character range */ #define VISSTOP 126 /* end of graphic character range */ struct flags_t { unsigned int is_hex : 1; unsigned int is_octal : 1; } flags; enum { ON, OFF }; /* isgraphic: returns 1 if character can be printed */ int isgraphic(char c) { if ((c >= VISSTART && c <= VISSTOP) || isspace(c)) return 1; return 0; } /* print s, converting to octal or hex if necessary */ void write(char *s) { while (*s != '\0') { if (isgraphic(*s)) putchar(*s); else if (flags.is_hex) printf("\\0x%.2x", *s); else if (flags.is_octal) printf("\\0%.3o", *s); else /* default to decimal */ printf("\\%.3d", *s); s++; } } int main(int argc, char *argv[]) { char c, buf[MAXWORD]; int bufi, len; int width = DEFWIDTH; /* get arguments */ while (--argc && **++argv == '-') { while ((c = *++argv[0]) != '\0') { switch (c) { case 'o': flags.is_hex = OFF; flags.is_octal = ON; break; case 'h': flags.is_hex = ON; flags.is_octal = OFF; break; case 'c': argv++; argc--; if (argv[0] == NULL) { printf("error: expected numeric argument\n"); exit(1); } width = atoi(argv[0]); if (width == 0) { printf("error: invalid numeric argument: %s\n", argv[0]); exit(1); } /* now we cheat a bit to break out of the while loop and get on to processing any remaining arguments */ argv[0][1] = '\0'; break; default: printf("error: invalid option: -%s\n", argv[0]); exit(1); break; } } } if (argc != 0) { /* bad arguments! no soup for you! */ printf("error: invalid argument: %s\n", argv[0]); exit(1); } bufi = len = 0; while ((c=getchar()) != EOF) { if (isspace(c)) { buf[bufi] = '\0'; write(buf); bufi = 0; buf[bufi] = '\0'; if (c == '\n') len = 0; } if (bufi < MAXWORD - 1) /* truncate exceedingly large words */ buf[bufi++] = c; if (!isgraphic(c)) { /* non-graphic characters take more space to represent */ if (flags.is_hex || flags.is_octal) len += 5; else len += 4; /* decimal */ } else len++; if (len >= width) { putchar('\n'); len = 0; } } if (c != '\n') /* it's always nice to end with a newline */ putchar('\n'); return 0; }