#ifndef lint static char *rcs = "$Header: cati.c,v 1.1 88/01/15 13:03:12 simpson Rel $"; #endif /* $Log: cati.c,v $ * Revision 1.1 88/01/15 13:03:12 simpson * initial release * * Revision 0.1 87/12/11 18:30:41 simpson * beta test * */ #include /* mask for high order 4 bits of byte */ #define CAT_HIGH_NIBBLE 0xf0 #define CAT_MAX_BYTE 0xff #define CAT_ESCAPE_CODE 0x80 #define CAT_ESCAPE_MASK 0x7f #define CAT_MAX_ESCAPE 0x7f /* nonzero if escape command and zero otherwise */ #define CAT_IS_ESCAPE(x) (((x) & (CAT_HIGH_NIBBLE << 3)) == CAT_ESCAPE_CODE) /* magnitude of escape */ #define CAT_ESCAPE(x) (~(x) & CAT_ESCAPE_MASK) #define CAT_ENCODE_ESCAPE(n) (CAT_ESCAPE_CODE | (~(n) & CAT_ESCAPE_MASK)) #define CAT_LEAD_CODE 0x60 #define CAT_LEAD_MASK 0x1f #define CAT_MAX_LEAD 0x1f /* nonzero if leading command and zero otherwise */ #define CAT_IS_LEADING(x) (((x) & (CAT_HIGH_NIBBLE << 1)) == CAT_LEAD_CODE) /* magnitude of leading */ #define CAT_LEAD(x) (~(x) & CAT_MAX_LEAD) #define CAT_ENCODE_LEAD(n) (CAT_LEAD_CODE | (~(n) & CAT_LEAD_MASK)) #define CAT_SIZE_CHANGE_CODE 0x50 /* nonzero if point size change command and zero otherwise */ #define CAT_IS_SIZE_CHANGE(x) (((x) & CAT_HIGH_NIBBLE) == CAT_SIZE_CHANGE_CODE) /* translates from the weird CAT point size change codes into something sane */ #define CAT_SIZE_CHANGE(x) \ ((x) == 0x50 ? 7 : \ (x) == 0x51 ? 8 : \ (x) == 0x52 ? 10 : \ (x) == 0x53 ? 11 : \ (x) == 0x54 ? 12 : \ (x) == 0x55 ? 14 : \ (x) == 0x56 ? 18 : \ (x) == 0x57 ? 9 : \ (x) == 0x58 ? 6 : \ (x) == 0x59 ? 16 : \ (x) == 0x5a ? 20 : \ (x) == 0x5b ? 22 : \ (x) == 0x5c ? 24 : \ (x) == 0x5d ? 28 : \ (x) == 0x5e ? 36 : 0) /* translates from sane point sizes into the weird CAT encodings */ #define CAT_ENCODE_SIZE(x) \ ((x) == 6 ? 0x58 : \ (x) == 7 ? 0x50 : \ (x) == 8 ? 0x51 : \ (x) == 9 ? 0x57 : \ (x) == 10 ? 0x52 : \ (x) == 11 ? 0x53 : \ (x) == 12 ? 0x54 : \ (x) == 14 ? 0x55 : \ (x) == 16 ? 0x59 : \ (x) == 18 ? 0x56 : \ (x) == 20 ? 0x5a : \ (x) == 22 ? 0x5b : \ (x) == 24 ? 0x5c : \ (x) == 28 ? 0x5d : \ (x) == 36 ? 0x5e : 0) #define CAT_FLASH_CODE 0x00 #define CAT_FLASH_MASK 0x3f #define CAT_MAX_FLASH 0x3f /* nonzero if printable character and zero otherwise */ #define CAT_IS_FLASH(x) (((x) & (CAT_HIGH_NIBBLE << 2)) == CAT_FLASH_CODE) #define CAT_FLASH(x) ((x) & CAT_MAX_FLASH) #define CAT_ENCODE_FLASH(n) (CAT_FLASH_CODE | ((n) & CAT_FLASH_MASK)) #define CAT_CONTROL_CODE 0x40 /* nonzero if control command and zero otherwise */ #define CAT_IS_CONTROL(x) (((x) & CAT_HIGH_NIBBLE) == CAT_CONTROL_CODE) /* CAT-8 control commands */ #define CAT_INITIALIZE 0x40 #define CAT_LOWER_RAIL 0x41 #define CAT_UPPER_RAIL 0x42 #define CAT_UPPER_MAGAZINE 0x43 #define CAT_LOWER_MAGAZINE 0x44 #define CAT_LOWER_FONT 0x45 #define CAT_UPPER_FONT 0x46 #define CAT_ESCAPE_FORWARD 0x47 #define CAT_ESCAPE_BACKWARD 0x48 #define CAT_STOP 0x49 #define CAT_LEAD_FORWARD 0x4a #define CAT_LEAD_BACKWARD 0x4c #define CAT_TILT_UP 0x4e #define CAT_TILT_DOWN 0x4f #define CAT_NOOP 0x00 /* trapdoor for CAT extensions */ #define CAT_EXTENSION 0x4b /* CAT_BIG_LEAD means take the next byte * 64 to obtain leading */ #define CAT_BIG_LEAD 0x01 #define CAT_BIG_LEAD_MULTIPLIER 64 #define CAT_MIN_BIG_LEAD (CAT_BIG_LEAD_MULTIPLIER * 0x01) #define CAT_MAX_BIG_LEAD (CAT_BIG_LEAD_MULTIPLIER * 0xff) /* CAT_BIG_ESCAPE means take the next byte * 128 to obtain escape */ #define CAT_BIG_ESCAPE 0x02 #define CAT_BIG_ESCAPE_MULTIPLIER 128 #define CAT_MIN_BIG_ESCAPE (CAT_BIG_ESCAPE_MULTIPLIER * 0x01) #define CAT_MAX_BIG_ESCAPE (CAT_BIG_ESCAPE_MULTIPLIER * 0xff) /* * CAT_FORMFEED means advance to next page resetting current row * and column to <0,0>. */ #define CAT_FORMFEED 0x03 /* * Returns nonzero if a single point size and zero otherwise. * The parameter is the `sane' point size and NOT the weird CAT encoding. */ #define CAT_IS_SINGLE(p) ((6 <= (p) && (p) <= 14) || (p) == 18) /* * Returns nonzero is a double point size and zero otherwise. * The parmeter is the `sane' point size and NOT the weird CAT encoding. */ #define CAT_IS_DOUBLE(p) ((p) == 16 || (p) >= 20) /* * Returns nonzero if the old to new point size transition is a * single to double transition and zero otherwise. * The parameters are the `sane' point sizes NOT the weird CAT encodings. */ #define CAT_IS_SINGLE_TO_DOUBLE(old, new) \ (CAT_IS_SINGLE(old) && CAT_IS_DOUBLE(new)) /* * Returns nonzero if the old to new point size transition is a * double to single transition and zero otherwise. * The parameters are the `sane' point sizes NOT the weird CAT encodings. */ #define CAT_IS_DOUBLE_TO_SINGLE(old, new) \ (CAT_IS_DOUBLE(old) && CAT_IS_SINGLE(new)) typedef struct CAT { char escape_where; /* BACKWARD or FORWARD */ char lead_where; /* BACKWARD or FORWARD */ char font; /* bit 0 => tilt, bit 1 => rail, bit 2 => magazine */ char font_half; /* LOWER or UPPER */ char point_size; /* current point size */ } CAT; #define CAT_FORWARD 0 #define CAT_BACKWARD 1 #define CAT_UPPER 0 #define CAT_LOWER 1 /* vertical resolution per inch */ #define CAT_VERTICAL_UNITS 144.0 /* horizontal resolution per inch */ #define CAT_HORIZONTAL_UNITS 432.0 /* compensatory escape for single/double point size transitions */ #define CAT_LENSE_COMPENSATION 55 #define CAT_TILT 01 #define CAT_RAIL 02 #define CAT_MAGAZINE 04 /* default troff and scribe font mountings for CAT-8 */ #define CAT_ROMAN_FONT 0 #define CAT_ITALIC_FONT 2 #define CAT_BOLD_FONT 4 #define CAT_SPECIAL_FONT 6 /* the maximum number of characters on a filmstrip */ #define CAT_MAX_FONT_INDEX 108 FILE *freopen(); typedef struct STATE { CAT cat; long escape; /* temporary escape accumulator */ long forward_escape; /* total forward escape to date */ long backward_escape; /* total backward escape to date */ long lead; /* temporary lead accumulator */ long forward_lead; /* total forward lead to date */ long backward_lead; /* total backward lead to date */ long row; /* current row */ long column; /* current column */ } STATE; char *regular[128]; char *special[128]; char *Whoami; main (argc, argv) int argc; char *argv[]; { int lead_only_flag = 0; int verbose_flag = 0; STATE s; int i; Whoami = argv[0]; for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) switch (argv[0][1]) { case 'l': lead_only_flag++; continue; case 'v': verbose_flag++; continue; default: fprintf(stderr, "%s: unknown option %s\n", Whoami, argv[0]); exit(1); } if (argc > 0) if (freopen(argv[0], "r", stdin) == NULL) { fprintf(stderr, "%s: cannot open %s\n", Whoami, argv[0]); exit(1); } s.escape = s.forward_escape = s.backward_escape = 0; s.lead = s.forward_lead = s.backward_lead = 0; s.row = s.column = 0; while ((i = getchar()) != EOF) interpret(i, &s, !lead_only_flag, verbose_flag); printf("Total lead %d\n", s.forward_lead + s.backward_lead); exit(0); } interpret (c, s, noisy, verbose) int c; STATE *s; int noisy; int verbose; { int point_size; int index; /* temporary for computing filmstrip index */ int lead; int escape; if (c == 0) { if (noisy) printf("No-op\n"); return; /* ascii null is a no-op for the CAT */ } if (CAT_IS_ESCAPE(c)) { s->escape += CAT_ESCAPE(c); if (noisy & verbose) printf("%c %d\n", s->cat.escape_where == CAT_FORWARD ? '>' : '<', CAT_ESCAPE(c)); return; } if (s->escape) { if (s->cat.escape_where == CAT_FORWARD) { s->forward_escape += s->escape; s->column += s->escape; if (noisy) printf("> %d %d %d %d\n", s->escape, s->forward_escape, s->backward_escape, s->forward_escape + s->backward_escape); } else { s->backward_escape += s->escape; s->column -= s->escape; if (noisy) printf("< %d %d %d %d\n", s->escape, s->forward_escape, s->backward_escape, s->forward_escape + s->backward_escape); } s->escape = 0; } if (CAT_IS_LEADING(c)) { s->lead += CAT_LEAD(c); if (noisy & verbose) printf("%c %d\n", s->cat.lead_where == CAT_FORWARD ? '+' : '-', CAT_LEAD(c)); return; } if (s->lead) { if (s->cat.lead_where == CAT_FORWARD) { s->forward_lead += s->lead; s->row += s->lead; if (noisy) printf("+ %d %d %d %d\n", s->lead, s->forward_lead, s->backward_lead, s->forward_lead + s->backward_lead); } else { s->backward_lead += s->lead; s->row -= s->lead; if (noisy) printf("- %d %d %d %d\n", s->lead, s->forward_lead, s->backward_lead, s->forward_lead + s->backward_lead); } s->lead = 0; } if (CAT_IS_SIZE_CHANGE(c)) { point_size = CAT_SIZE_CHANGE(c); if (noisy) { printf("Size %d", point_size); if (CAT_IS_SINGLE_TO_DOUBLE(s->cat.point_size, point_size)) printf(" (double)"); else if (CAT_IS_DOUBLE_TO_SINGLE(s->cat.point_size, point_size)) printf(" (single)"); putchar('\n'); } s->cat.point_size = point_size; return; } if (CAT_IS_FLASH(c)) { c = CAT_FLASH(c); if (noisy) { index = c + (s->cat.font_half == CAT_LOWER ? 0 : 63); if (index > CAT_MAX_FONT_INDEX) { printf("Flash !!ILLEGAL!! (%d)\n", index); return; } printf("Flash %s (font %d %d%c size %d <%d,%d>)\n", s->cat.font == CAT_SPECIAL_FONT ? special[index] : regular[index], s->cat.font + 1, c, s->cat.font_half == CAT_LOWER ? 'L' : 'U', s->cat.point_size, s->row, s->column); } return; } switch (c) { case CAT_INITIALIZE: s->cat.escape_where = s->cat.lead_where = CAT_FORWARD; s->cat.font = 0; /* tilt up, lower rail and lower magazine */ s->cat.font_half = CAT_LOWER; s->column = 0; if (noisy) printf("Initialize\n"); return; case CAT_LOWER_RAIL: s->cat.font &= ~CAT_RAIL; if (noisy) printf("Lower rail (font %d)\n", s->cat.font + 1); return; case CAT_UPPER_RAIL: s->cat.font |= CAT_RAIL; if (noisy) printf("Upper rail (font %d)\n", s->cat.font + 1); return; case CAT_UPPER_MAGAZINE: s->cat.font |= CAT_MAGAZINE; if (noisy) printf("Upper magazine (font %d)\n", s->cat.font + 1); return; case CAT_LOWER_MAGAZINE: s->cat.font &= ~CAT_MAGAZINE; if (noisy) printf("Lower magazine (font %d)\n", s->cat.font + 1); return; case CAT_LOWER_FONT: s->cat.font_half = CAT_LOWER; if (noisy) printf("Font half lower\n"); return; case CAT_UPPER_FONT: s->cat.font_half = CAT_UPPER; if (noisy) printf("Font half upper\n"); return; case CAT_ESCAPE_FORWARD: s->cat.escape_where = CAT_FORWARD; if (noisy) printf("> mode, %d %d %d\n", s->forward_escape, s->backward_escape, s->forward_escape + s->backward_escape); return; case CAT_ESCAPE_BACKWARD: s->cat.escape_where = CAT_BACKWARD; if (noisy) printf("< mode %d %d %d\n", s->forward_escape, s->backward_escape, s->forward_escape + s->backward_escape); return; case CAT_STOP: if (noisy) printf("STOP\n"); return; case CAT_LEAD_FORWARD: s->cat.lead_where = CAT_FORWARD; if (noisy) printf("+ mode %d %d %d\n", s->forward_lead, s->backward_lead, s->forward_lead + s->backward_lead); return; case CAT_LEAD_BACKWARD: s->cat.lead_where = CAT_BACKWARD; if (noisy) printf("- mode %d %d %d\n", s->forward_lead, s->backward_lead, s->forward_lead + s->backward_lead); return; case CAT_EXTENSION: switch (getchar()) { case CAT_BIG_LEAD: lead = getchar() * CAT_BIG_LEAD_MULTIPLIER; if (noisy & verbose) printf("%s %d\n", s->cat.lead_where == CAT_FORWARD ? "++" : "--", lead); s->lead += lead; return; case CAT_BIG_ESCAPE: escape = getchar() * CAT_BIG_ESCAPE_MULTIPLIER; if (noisy & verbose) printf("%s %d\n", s->cat.escape_where == CAT_FORWARD ? ">>" : "<<", escape); s->escape += escape; return; case CAT_FORMFEED: s->row = s->column = 0; if (noisy) printf("Formfeed\n"); return; default: if (noisy) printf("Undefined extension\n"); return; } case CAT_TILT_UP: s->cat.font &= ~CAT_TILT; if (noisy) printf("Tilt up (font %d)\n", s->cat.font + 1); return; case CAT_TILT_DOWN: s->cat.font |= CAT_TILT; if (noisy) printf("Tilt down (font %d)\n", s->cat.font + 1); return; } } char *regular[128] = { "", /* garbage slot */ "h", /* h */ "t", /* t */ "n", /* n */ "m", /* m */ "l", /* l */ "i", /* i */ "z", /* z */ "s", /* s */ "d", /* d */ "b", /* b */ "x", /* x */ "f", /* f */ "j", /* j */ "u", /* u */ "k", /* k */ "-blank-", /* blank */ "p", /* p */ "-", /* _ 3/4 em dash */ ";", /* ; */ "-blank-", /* blank */ "a", /* a */ "_", /* rule */ "c", /* c */ "`", /* ` open */ "e", /* e */ "'", /* ' close */ "o", /* o */ "-1/4-", /* 1/4 */ "r", /* r */ "-1/2-", /* 1/2 */ "v", /* v */ "-", /* - hyphen */ "w", /* w */ "q", /* q */ "/", /* / */ ".", /* . */ "g", /* g */ "-3/4-", /* 3/4 */ ",", /* , */ "&", /* & */ "y", /* y */ "-blank-", /* blank */ "%", /* % */ "-blank-", /* blank */ "Q", /* Q */ "T", /* T */ "O", /* O */ "H", /* H */ "N", /* N */ "M", /* M */ "L", /* L */ "R", /* R */ "G", /* G */ "I", /* I */ "P", /* P */ "C", /* C */ "V", /* V */ "E", /* E */ "Z", /* Z */ "D", /* D */ "B", /* B */ "S", /* S */ "Y", /* Y */ "F", /* F */ "X", /* X */ "A", /* A */ "W", /* W */ "J", /* J */ "U", /* U */ "K", /* K */ "0", /* 0 */ "1", /* 1 */ "2", /* 2 */ "3", /* 3 */ "4", /* 4 */ "5", /* 5 */ "6", /* 6 */ "7", /* 7 */ "8", /* 8 */ "9", /* 9 */ "*", /* * */ "-", /* minus */ "-fi-", /* fi */ "-fl-", /* fl */ "-ff-", /* ff */ "-cent mark-", /* cent mark */ "-ffl-", /* ffl */ "-ffi-", /* ffi */ "(", /* ( */ ")", /* ) */ "[", /* [ */ "]", /* ] */ "-degree-", /* degree */ "-dagger-", /* dagger */ "=", /* = */ "-registered-", /* registered */ ":", /* : */ "+", /* + */ "-blank-", /* blank */ "!", /* ! */ "-bullet-", /* bullet */ "?", /* ? */ "'", /* foot mark */ "|", /* | */ "-blank-", /* blank */ "-copyright-", /* copyright */ "-square-", /* square */ "$" /* $ */ }; char *special[128] = { "", /* garbage slot */ "-psi-", /* psi */ "-theta-", /* theta */ "-nu-", /* nu */ "-mu-", /* mu */ "-lambda-", /* lambda */ "-iota-", /* iota */ "-zeta-", /* zeta */ "-sigma-", /* sigma */ "-delta-", /* delta */ "-beta-", /* beta */ "-xi-", /* xi */ "-eta-", /* eta */ "-phi", /* phi */ "-upsilon-", /* upsilon */ "-kappa-", /* kappa */ "-blank-", /* blank */ "-pi-", /* pi */ "@", /* at sign @ */ "-down arrow-", /* down arrow */ "-blank-", /* blank */ "-alpha-", /* alpha */ "|", /* or */ "-chi-", /* chi */ "\"", /* " */ "-epsilon-", /* epsilon */ "=", /* equals */ "-omicron-", /* omicron */ "-left arrow-", /* left arrow */ "-rho-", /* rho */ "-up arrow-", /* up arrow */ "-tau-", /* tau */ "_", /* underrule */ "\\", /* \ */ "-Psi-", /* Psi */ "-bell system sign-", /* bell system sign */ "-infinity-", /* infinity */ "-gamma-", /* gamma */ "-improper subset-", /* improper superset */ "-proportional to-", /* proportional to */ "-right hand-", /* right hand */ "-omega-", /* omega */ "-blank-", /* blank */ "-gradient-", /* gradient */ "-blank-", /* blank */ "-Phi-", /* Phi */ "-Theta-", /* Theta */ "-Omega-", /* Omega */ "-union-", /* cup (union) */ "-root en-", /* root en */ "-terminal sigma-", /* terminal sigma */ "-Lambda-", /* Lambda */ "-", /* some horizontal line */ "-Gamma-", /* Gamma */ "-integral sign-", /* integral sign */ "-Pi-", /* Pi */ "-subset of-", /* subset of */ "-superset of-", /* superset of */ "-approximates-", /* approximates */ "-partial derivative-", /* partial derivative */ "-Delta-", /* Delta */ "-square root-", /* square root */ "-Sigma-", /* Sigma */ "-approximates-", /* approximates */ ">", /* > */ "-Xi-", /* Xi */ "<", /* < */ "/", /* slash (longer) */ "-cap-", /* cap (intersection) */ "-Upsilon-", /* Upsilon */ "-not-", /* not */ "-right ceiling-", /* right ceiling */ "-left curly top-", /* left top of big curly bracket */ "-bold vertical-", /* bold vertical */ "-left curly center-", /* left center of big curly bracket */ "-left curly bottom-", /* left bottom of big curly bracket */ "-right curly top-", /* right top of big curly bracket */ "-right curly center-", /* right center of big curly bracket */ "-right floor-", /* right floor */ "-right floor-", /* right floor */ "-left floor-", /* left floor */ "-left ceiling-", /* left ceiling */ "-multiply-", /* multiply */ "-divide-", /* divide */ "-plus/minus-", /* plus-minus */ "-less than or equal-", /* <= */ "-greater than or equal-", /* >= */ "-identical-", /* identically equal */ "-not equal-", /* not equal */ "{", /* { */ "}", /* } */ "'", /* ' acute accent */ "`", /* ` grave accent */ "^", /* ^ */ "#", /* sharp */ "-left hand-", /* left hand */ "-member of-", /* member of */ "~", /* ~ */ "-empty set-", /* empty set */ "-blank-", /* blank */ "-double dagger-", /* double dagger */ "-box vertical rule-", /* box rule */ "*", /* telephone asterisk? */ "-improper subset-", /* improper subset */ "-circle-", /* circle */ "-blank-", /* blank */ "+", /* equation plus sign */ "-right arrow-", /* right arrow */ "-section mark-" /* section mark */ };