#include #include /* * Lit Text Utility - Filter a file to stdout showing all characters in * an unambiguous format. See Lit Text Utility Manual for specification. * * Version 2.0 - 11/16/86, Copyright (C) 1986 Donald J Irving * * Author: Donald J. Irving * 9812 Gardenwood Way * Sacramento, CA 96827 * (916) 366-3225 * CIS: 73547,1335 * PLINK: ops158 * * Lit may be freely distributed for personal use. * Lit may not be sold or placed on a disk offered for sale without written * permission from the author. Written permission will normally be granted * at no charge for inclusion on so called "public domain disks" which are * sold for nominal medium and handling fees. Lit may be modified for * personal use, and trivial modifications such as changing defaults or * specifying include files may be made for distribution, but lit is not to * be modified substantially for distribution without written consent of the * author. The lit.c source, lit manual file , and this copyright notice must * be included on all distributions. * * Here is the overall algorithm, minus some of the details: * * if unable to interpret command line arguments * print an error message and a Usage line; * else * set options and open files; * if line specified to start on is not the first line * throw out input file lines until the line specified; * while read next char from input file * if the char is printable * print it; * else * represent it in a special format; * if the char is a line feed * output a linefeed; * if there was a number of lines to print specified * and ++line count equals that number * return; * * Functions not returning values are not typed. Functions returning values * are explicitly typed. * */ /* The four possible settings for representation mode. */ #define BSLASH 1 /* use backslash rep else numeric */ #define CONTROL 2 /* use control char reps else numeric */ #define ALLREPS 3 /* use backslash else control else numeric */ #define NUMERIC 4 /* use numeric value reps only */ /* The three possible settings for numeric number base */ #define OCT 1 /* use octal representations as in \033 */ #define HEX 2 /* use hex representations as in \1B */ #define DEC 3 /* use decimal representations as in \027 */ /* The most likely setting for how many lines to print */ #define ALL_LINES 32767 /* print all the lines in the file */ /* * Here are the default option settings. If you don't like them, please * change them here. The comments on the define lines show the the default * settings chosen by the author and upon which the manual is based. Please * leave the comments as they are. */ /* original */ #define DEFAULT_START 1 /* 1 */ #define DEFAULT_PRINT ALL_LINES /* ALL_LINES */ #define DEFAULT_OUTMODE BSLASH /* BSLASH */ #define DEFAULT_BASE OCT /* OCT */ /* Non-printing characters which require special handling in the code */ #define DEL '\177' struct opt { short start; short print; short outmode; short base; }; typedef struct opt opt_t; main(argc, argv) int argc; char *argv[]; { FILE *ifp = NULL; register short c; static opt_t opt = { DEFAULT_START, DEFAULT_PRINT, DEFAULT_OUTMODE, DEFAULT_BASE }; if (! process_args(argc, argv, &ifp, &opt)) printf("Usage: lit [] [-s] [-p] [-[bcan][ohd]]\n"); else { if (opt.start != 1 && ! find_start_line(ifp, opt.start)) return; while ((c = getc(ifp)) != EOF) { if (! print_char(c, opt.outmode)) represent_char(c, opt.outmode, opt.base); if (c == '\n') { putchar('\n'); if (opt.print != ALL_LINES && last_line(opt.print)) break; } } if (c != '\n') putchar('\n'); } } /* * process_args -- Process all the command line arguments. Each argument is * expected to be either a minus sign option or an input file name. If an * input file is already open, a subsequent input file name argument is an * error. */ BOOL process_args(argc, argv, ifp, opt) int argc; char *argv[]; FILE **ifp; opt_t *opt; { register short i; for (i = 1; i < argc; i++) { if (*argv[i] == '-') { if (! process_opt(argv[i]+1, opt)) return (FALSE); } else if (*ifp != NULL) { printf("Invalid argument %s, Input file already specified\n", argv[i]); return (FALSE); } else if ((*ifp = fopen(argv[i], "r")) == NULL) { printf("Unable to open input file %s\n", argv[i]); return (FALSE); } } if (*ifp == NULL) *ifp = stdin; return (TRUE); } /* * process_opt -- Process a minus-sign command line argument. The options * s and p must stand alone with their own minus signs; * The options b,c,a,n,o,h,d may be stacked after a single minus sign. */ BOOL process_opt(arg, opt) char *arg; opt_t *opt; { switch (*arg) { case 's': opt->start = atoi(arg+1); /* set starting linenum */ break; case 'p': opt->print = atoi(arg+1); /* set linenums to print */ break; default: for (; *arg; arg++) { switch (*arg) { case 'b': opt->outmode = BSLASH; /* use backslash rep else */ break; /* numeric rep */ case 'c': opt->outmode = CONTROL; /* use control char rep */ break; /* else numeric rep */ case 'a': opt->outmode = ALLREPS; /* use backslash else */ break; /* control else numeric */ case 'n': opt->outmode = NUMERIC; /* use numeric rep only */ break; case 'o': opt->base = OCT; /* numeric rep base is octal */ break; case 'h': opt->base = HEX; /* numeric rep base is hex */ break; case 'd': opt->base = DEC; /* numeric rep base is decimal */ break; default: printf("Unknown option: %c\n", *arg); return (FALSE); } } } return (TRUE); } /* * find_start_line -- Find the first line to start printing on, throwing * out all the lines along the way. */ BOOL find_start_line(ifp, start) FILE *ifp; short start; { register short c, lineno = 1; while (lineno < start) { while ((c = getc(ifp)) != EOF && c != '\n') ; if (c == EOF) return (FALSE); lineno++; } return (TRUE); } /* * last_line -- Return true if the line just printed was the last line * to print. */ BOOL last_line(print) short print; { static short printed = 0; if (++printed == print) return (TRUE); return (FALSE); } /* * print_char -- Print a printable character. If it's a \, or if * it's a ^ and control codes are enabled, then preface it with a \. */ BOOL print_char(c, outmode) short c, outmode; { if (c < ' ' || c > '~') return (FALSE); if (c == '\\' || (c == '^' && (outmode == CONTROL || outmode == ALLREPS))) putchar('\\'); putchar(c); return (TRUE); } /* * represent_char -- Represent a non-printable character using whichever * representation format is appropriate for the outmode selected. The * rep_xxx functions called try to represent the char in a particular * format, and return false if the the character is not applicable. */ represent_char(c, outmode, base) short c, outmode, base; { switch (outmode) { case BSLASH: if (rep_bslash(c)) return; break; case CONTROL: if (rep_control(c)) return; break; case ALLREPS: if (rep_bslash(c) || rep_control(c)) return; break; case NUMERIC: break; } rep_numeric(c, base); } /* * rep_bslash - Represent a non-printable char if possible using its * C Language backslash construct, else return false. '\0' is not included. */ BOOL rep_bslash(c) short c; { switch (c) { case '\n': putchar('\\'); putchar('n'); break; case '\t': putchar('\\'); putchar('t'); break; case '\b': putchar('\\'); putchar('b'); break; case '\r': putchar('\\'); putchar('r'); break; case '\f': putchar('\\'); putchar('f'); break; default : return (FALSE); } return (TRUE); } /* * rep_control -- represent a non-printable char if possible using its * control character representation, else return false. All non-printing * ascii chars are representable as control chars (with DEL arbitrarily * assigned the representation ^?). Characters rejected are those outside * the range of ascii (ie, left most bit on). */ BOOL rep_control(c) short c; { if (c < '\0' || c > '\177') return (FALSE); putchar('^'); switch (c) { case DEL: putchar('?'); break; default: putchar(c | 0x40); break; } return (TRUE); } /* * rep_numeric - Unconditionally represent a character as a numeric value * using the number base specified. */ rep_numeric(c, base) short c, base; { char buf[4]; switch (base) { case OCT: printf("\\%03o", c); break; case HEX: sprintf(buf, "\\%02x\0", c); /* make it upper case, %X */ if (buf[1] >= 'a') /* doesn't seem to work on */ buf[1] &= 0x5F; /* my compiler. */ if (buf[2] >= 'a') buf[2] &= 0x5F; printf("%s", buf); break; case DEC: printf("\\%03d", c); break; } }