/* FACILITY: 'C' utility programs. ABSTRACT: Detects overstriking, as in RUNOFF output, and uses the VT100 bold and underscore character attributes to indicate these overstrikes. ENVIRONMENT: PDP-11 user mode, under RT-11 and VAX/VMS RSX-11 compatability. AUTHOR: Brian Hetrick, DATE WRITTEN: 17 August 1981 MODIFIED BY: */ /* INCLUDE FILES: */ #include /* MACROS: */ /* EQUATED SYMBOLS: */ #define MAX_OUT_REC 512 #define CHR_IGN 0 #define CHR_BS 1 #define CHR_HT 2 #define CHR_VER 3 #define CHR_CR 4 #define CHR_SP 5 #define CHR_PRN 6 #define CHR_UND 7 #define MASK_CHAR 0177 #define MASK_BOLD 0200 #define MASK_UNDR 0400 #define MASK_BLOB 01000 #define SI 017 #define SO 016 #define ESC 033 /* OWN STORAGE: */ static FILE * in_file, * out_file; static char chr_type [128] = { CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, /* NUL to BEL */ CHR_BS, CHR_HT, CHR_VER, CHR_VER, CHR_VER, CHR_CR, CHR_IGN, CHR_IGN, /* BS to SI */ CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, /* DLE to ETB */ CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, CHR_IGN, /* CAN to US */ CHR_SP, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* SP to ' */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* ( to / */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* 0 to 7 */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* 8 to ? */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* @ to G */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* H to O */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* P to W */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_UND, /* X to _ */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* ` to g */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* h to o */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, /* p to w */ CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_PRN, CHR_IGN }, /* x to DEL */ #ifdef rsx cr_needed, #endif memo_heading, old_attr_mask = 0, span_whitespace, term_commands [] = {1,4,5,7}; /* WEAK AND VALIDATION DECLARATIONS: */ main (argc, argv) int argc; char * argv []; /* FUNCTIONAL DESCRIPTION: Reads a file, detects overstrikes, and produces a file which repre- sents the input file but with VT100 bolding and underlining in place of overstrikes. On RSX, the input file must be variable sequential with maximum rec- ord size 512 and either carriage-return or no record attribute. On RT, the input file must be a standard RT stream file. On both RSX and RT, control characters other than BS, HT, LF, VT, FF, and CR (i.e., backspace, horizontal tab, line feed, vertical tab, form feed, and carriage return) are ignored. On RSX, the output file is variable sequential with maximum record size 512 and carriage-return record attribute; except if the output file is a terminal, the output file is variable sequential with max- imum record size 80 and no record attribute. On RT, the output file is a standard RT stream file. FORMAL PARAMETERS: Argument_count.rw.v - The number of arguments in the Argument_vector vector. This must be at least 1. Argument_vector.rt.aa - A list of addresses of ASCIZ strings, each of which is an argument. The first must be the name of this program. The second must be the name of the input file (which may contain overstrikes). The third must be the name of the output file (which is to contain VT100 escape sequences). The optional fourth parameter must start with a hyphen, and may con- tinue with any combination of the following in any order: m which indicates that a Digital logo and the words "interof- fice memo" are to be prefixed to the text of the output file. The default is not to prefix the logo and words. s which indicates that spaces separating two characters with identical bold/underline are not to be bolded and under- lined. The default is to bold and underline spaces separat- ing non-space characters with identical bold/underline at- tributes. ex which indicates that the first 'x' lines of the input file are not to appear in the output file. 'x' must be a single decimal digit. The default is 'x' of 0. IMPLICIT INPUTS: None. IMPLICIT OUTPUTS: None. COMPLETION CODES: None. SIDE EFFECTS: None. */ { char * this_arg; int cur_char, eat_lines, horiz_pos, i, line_map [MAX_OUT_REC], this_char; int * cur_map, * high_water_mark; #ifdef rsx extern int fd_cr; #endif if (argc < 3) fprintf (stderr, "Usage: %s infile outfile -mse9\n", argv [0]); else { #ifdef rt11 if (NULL == (in_file = fopen (argv [1], "rn"))) #else if (NULL == (in_file = fopen (argv [1], "r"))) #endif fprintf (stderr, "Cannot open %s, aborting\n", argv [1]); else { #ifdef rsx /* If the input file has recordattr none, then tell C about it. */ if (0 == ((in_file -> io_fdb [0]) & (((int) & fd_cr) << 8))) in_file -> io_flag |= IO_NOS; #endif if (NULL == (out_file = fopen (argv [2], "w"))) { fprintf (stderr, "Cannot open %s, aborting\n", argv [2]); fclose (in_file); } else { #ifdef rsx cr_needed = 0; if (ftty (out_file)) { out_file = freopen (argv [2], "wn", out_file); cr_needed = 1; } #endif memo_heading = 0; /* Argument default - no memo heading */ span_whitespace = 1; /* Argument default - span spaces. */ eat_lines = 0; /* Argument default - eat no lines of first page. */ for (i = 3; i < argc; i++) { this_arg = argv [i]; if ('-' != *this_arg++) fprintf (stderr, "Argument %s illegal, ignored.\n", argv [i]); else { while ('\0' != (this_char = *this_arg++)) { if (this_char == 'M') memo_heading = 1; else if (this_char == 'S') span_whitespace = 0; else if (this_char == 'E') { if ('0' == *this_arg) fprintf (stderr, "No argument for e, switch ignored.\n"); else eat_lines = *this_arg++ - '0'; } else fprintf (stderr, "Character %c unknown as switch, ignored.\n", this_char); } /* End of while */ } /* End of else */ } /* End of for */ /* Make ready to process the input file. */ line_initialize (line_map); cur_map = line_map; high_water_mark = cur_map; if (memo_heading) put_memo_heading (); while (eat_lines > 0) { this_char = getc (in_file); if (this_char == EOF) eat_lines = 0; else if (this_char == '\n') eat_lines --; } while (EOF != (this_char = getc (in_file))) { switch (this_char > 127 ? CHR_IGN : chr_type [this_char]) { case CHR_IGN : break; case CHR_BS : { cur_map --; break; } case CHR_HT : { cur_map = line_map + 8 * ((cur_map - line_map) / 8 + 1); break; } case CHR_VER : { put_line (line_map, high_water_mark); #ifdef rsx if (cr_needed) putc ('\r', out_file); #endif putc (this_char, out_file); line_initialize (line_map); cur_map = line_map; high_water_mark = cur_map; break; } case CHR_CR : { cur_map = line_map; break; } case CHR_SP : { cur_map ++; break; } case CHR_PRN : { if (cur_char = (*cur_map & MASK_CHAR)) { if (cur_char == this_char) *cur_map |= MASK_BOLD; else *cur_map |= MASK_BLOB; } else *cur_map = (*cur_map & ~ MASK_CHAR) | this_char; cur_map ++; if (cur_map > high_water_mark) high_water_mark = cur_map; break; } case CHR_UND : { *cur_map |= MASK_UNDR; cur_map ++; if (cur_map > high_water_mark) high_water_mark = cur_map; break; } } /* End of switch */ } /* End of while */ } /* End of else */ } /* End of else */ } /* End of else */ } /* End of main program */ line_initialize (line_map) int line_map [MAX_OUT_REC]; /* FUNCTIONAL DESCRIPTION: Initializes a line to all null/spaces. FORMAL PARAMETERS: Line_map.mw.ra - The map of the line contents. IMPLICIT INPUTS: None. IMPLICIT OUTPUTS: None. FUNCTION VALUE: None. SIDE EFFECTS: None. */ { int i; for (i = 0; i < MAX_OUT_REC; i++) line_map [i] = 0; } put_memo_heading () /* FUNCTIONAL DESCRIPTION: Writes the logo and the words "interoffice memo" to the output file. FORMAL PARAMETERS: None. IMPLICIT INPUTS: out_file - the FDB of the output file. cr_needed - the flag indicating whether the output file needs explicit carriage returns (RSX only). IMPLICIT OUTPUTS: None. FUNCTION VALUE: None. SIDE EFFECTS: None. */ { char * logo; putc (ESC, out_file); fputs ("(B", out_file); putc (ESC, out_file); fputs (")0", out_file); putc (SO, out_file); set_attr (MASK_BOLD); putc (ESC, out_file); fputs ("#6", out_file); fputs ("lqwqwqwqwqwqwqk", out_file); #ifdef rsx if (cr_needed) putc ('\r', out_file); #endif putc ('\n', out_file); logo = "digital"; putc (ESC, out_file); fputs ("#6", out_file); while (*logo != '\0') { putc ('x', out_file); putc (SI, out_file); putc (*logo++, out_file); putc (SO, out_file); } putc ('x', out_file); putc (SI, out_file); set_attr (0); fputs (" ", out_file); set_attr (MASK_BOLD); fputs ("INTEROFFICE MEMO", out_file); #ifdef rsx if (cr_needed) putc ('\r', out_file); #endif putc ('\n', out_file); putc (ESC, out_file); fputs ("#6", out_file); putc (SO, out_file); fputs ("mqvqvqvqvqvqvqj", out_file); putc (SI, out_file); set_attr (0); #ifdef rsx if (cr_needed) putc ('\r', out_file); #endif putc ('\n', out_file); } put_line (line_map, high_point) int * line_map, * high_point; /* FUNCTIONAL DESCRIPTION: Writes a single line to the output file. FORMAL PARAMETERS: Line_map.rw.ra - The map of the line to be written. High_point.ra.v - The address of the last element in Line_map which is to be written. IMPLICIT INPUTS: out_file - The FDB of the output file. span_whitespace - The flag indicating whether spaces separating two characters with identical bold/underline attributes are to bold- ed and underlined. IMPLICIT OUTPUTS: None. FUNCTION VALUE: None. SIDE EFFECTS: None. */ { int attr_to_carry, * last_ptr, this_char, * this_ptr; if (span_whitespace) { /* Start off with no attributes. Look for the first character with an attribute. */ this_ptr = line_map; /* Process the whole line, now. */ while (this_ptr < high_point) { while ((this_ptr < high_point) && (0 == (*this_ptr & ~MASK_CHAR))) this_ptr ++; /* Found something with attributes. Now, look for something without attributes. */ if (this_ptr < high_point) { while ((this_ptr < high_point) && (0 != (*this_ptr & ~MASK_CHAR))) this_ptr ++; /* Set the attribute mask to whatever the last attribute was, and look for the next non-blank. */ if (this_ptr < high_point) { last_ptr = this_ptr; attr_to_carry = *(this_ptr - 1) & ~ MASK_CHAR; while ((this_ptr < high_point) && (0 == *this_ptr)) this_ptr ++; /* If some subset of the attributes match, extend that subset through the intervening blanks. */ if (this_ptr < high_point) { attr_to_carry &= *this_ptr; if (attr_to_carry != 0) { while (last_ptr < this_ptr) *last_ptr ++ |= attr_to_carry; } } } } } } while (line_map < high_point) { this_char = *line_map; set_attr (this_char & ~ MASK_CHAR); this_char = this_char & MASK_CHAR; putc (0 != this_char ? this_char : ' ', out_file); line_map ++; } set_attr (0); } set_attr (new_attr_mask) int new_attr_mask; /* FUNCTIONAL DESCRIPTION: Outputs an escape sequence to change the character attributes. FORMAL PARAMETERS: New_attr_mask.rw.v - The mask indicating the attributes to be set. The bits MASK_BOLD and MASK_UNDR control bolding and underlining respectively. IMPLICIT INPUTS: out_file - The FDB of the output file. IMPLICIT OUTPUTS: None. FUNCTION VALUE: None. SIDE EFFECTS: None. */ { int attr_mask, clear_necessary, command_count, i; attr_mask = new_attr_mask; clear_necessary = 1; command_count = 0; if (attr_mask != old_attr_mask) { if (old_attr_mask == (old_attr_mask & attr_mask)) { attr_mask &= ~ old_attr_mask; clear_necessary = 0; } putc (ESC, out_file); putc ('[', out_file); if (clear_necessary) { putc ('0', out_file); command_count = 1; } if (attr_mask & MASK_BOLD) { if (command_count > 0) putc (';', out_file); putc ('1', out_file); command_count = 1; } if (attr_mask & MASK_UNDR) { if (command_count > 0) putc (';', out_file); putc ('4', out_file); } putc ('m', out_file); old_attr_mask = new_attr_mask; } }