/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 4-Dec-85 | [1.106] Created * 6-Dec-85 | [1.144] Recognize new escapes \W,\G,\S,\R,\Q,\D * 7-Dec-85 | [1.151] Flush listing file * 28-Dec-85 | [1.260] Changed to 1401.cfg from 1401.prn so FWF output file * | doesn't clobber us. * 25-Feb-86 | [1.379] include <> => include "" * 31-Jul-86 | [1.405] Made chars unsigned * 6-Aug-86 | [1.410] cast malloc args to unsigned * 17-Nov-91 | [1.428] converted for Microsoft C 6.0 * 20-Nov-91 | [1.429] configured for new virtual printer code * 23-Nov-91 | [1.455] added .sf for screen font * 23-Nov-91 | [1.455] accept two hex digits following \x * 23-Nov-91 | [1.455] created generic_printer_init * 25-Nov-91 | [1.182] added NOMAP conditional for autocoder inclusion * 7-Dec-91 | [1.481] added CHAR_NE * 21-Dec-91 | [1.493] added CHAR_PERF * 22-Dec-91 | [1.505] use unsigned chars for write_translated * 23-Dec-91 | [1.527] added CHAR_CORNER * 23-Dec-91 | [1.536] init_seq no longer emits the init string; this * | is done only when the printer is actually used * 23-Dec-91 | [1.547] save bitstrings in screen_xlat so we can reset * | after 132-column mode switch * 2-Jan-92 | [1.7] allow \" as escape * 2-Jan-92 | [1.9] handle multiple .in strings * 1-Mar-02 put include of "graph.h" inside conditional *****************************************************************************/ #include "stdio.h" #include "stdlib.h" #include "boolean.h" #include "string.h" #include "stdarg.h" #include "ctype.h" #ifndef __BORLANDC__ #include "graph.h" #endif #include "font.h" #include "pr.h" #include "prdev.h" #include "chars.h" #include "btypes.h" #include "diag.h" #include "rdy.h" #include "scdspmsg.h" #ifndef NOMAP extern struct videoconfig video; #endif typedef struct { int len; unsigned char * str; } string; static string * screen_xlat[256]; static string * xlat[256]; static string * final = NULL; static string * init = NULL; static string space = {1," "}; extern boolean pr64; char * cfgname = "1401.cfg"; static int lineno; #define debug_scan false #define debug_effects false /**************************************************************************** * printer_upline * Inputs: * printobj * pr: Print object * Result: void * * Effect: * Increments current_line and does page wrap ****************************************************************************/ void printer_upline(printobj * pr) { if(pr != NULL) pr->current_line = (pr->current_line + 1) % pr->form->pagelength; } /**************************************************************************** * set_screen_font * Inputs: * string * source: Source character * string * map: Mapped character * string * bits: Bitmap for screen * Result: void * * Effect: * Sets the screen font for the mappable characters. If bits are * supplied for an EGA/VGA, sets the font table for the display ****************************************************************************/ void set_screen_font(string * source, string * map, string * bits) { unsigned char * dest; unsigned char * maploc; unsigned char size; #ifndef NOMAP switch(video.adapter) { /* what size */ case SC_EGA: size = 14; break; case SC_VGA: size = 16; break; } /* what size */ if(source->len < 1) { /* source too short */ if(diagnostics_on) tell("set_screen_font: source length < 1"); return; } /* source too short */ if(map->len < 1) { /* map too short */ if(diagnostics_on) tell("set_screen_font: map length < 1"); return; } /* map too short */ switch(source->str[0]) { /* decode special */ case CHAR_GM: dest = &char_gm; break; case CHAR_WM: dest = &char_wm; break; case CHAR_RM: dest = &char_rm; break; case CHAR_SM: dest = &char_sm; break; case CHAR_DL: dest = &char_dl; break; case CHAR_SQ: dest = &char_sq; break; case CHAR_MI: dest = &char_mi; break; case CHAR_AMPERSAND: case CHAR_PLUS: dest = &char_plus; break; case CHAR_QUOTE: case CHAR_AT: dest = &char_quote; break; case CHAR_HASH: case CHAR_EQUAL: dest = &char_equal; break; case CHAR_LPAREN: case CHAR_PERCENT: dest = &char_lparen; break; case CHAR_NEX: dest = &char_ne; break; case CHAR_PERF: dest = &char_perf; break; /* case CHAR_LOZENGE: */ /* no such font character... */ case CHAR_RPAREN: dest = &char_rparen; break; case CHAR_CORNER1: dest = &char_corner1; break; case CHAR_CORNER2: dest = &char_corner2; break; default: /* unknown char */ if(diagnostics_on) { sprintf(diag_buffer,"%s(%d): Error: set_screen_font: Unknown character \"%c\"", cfgname, lineno, source->str[0]); tell(diag_buffer); } return; } /* decode special */ switch(video.adapter) { /* decode adapter */ case SC_EGA: case SC_VGA: if(bits->str != NULL) { /* has bits */ if(!fontset(map->str[0], bits->str, (unsigned char)(bits->len > size ? size : bits->len), size)) { /* fontset failed */ tell("font set failed"); return; } /* fontset failed */ } /* has bits */ break; } /* decode adapter */ *dest = map->str[0]; #endif } /**************************************************************************** * freestring * Inputs: * string * s: String object * Result: void * * Effect: * Frees the string space ****************************************************************************/ void freestring(string * s) { if(s->str != NULL) free(s->str); free(s); } /**************************************************************************** * physical_printer_open * Inputs: * printobj * pr: Printer object * Result: boolean * true if success * false if error * Effect: * Opens the physical printer ****************************************************************************/ boolean physical_printer_open(printobj * pr) { pr->prn = fopen(pr->lpt,"wb"); if(diagnostics_on) { /* report */ if(pr->prn == NULL) { /* failed */ sprintf(diag_buffer,"%s(%d): Error: physical_printer_open: %s open failed", cfgname, lineno, pr->lpt); tell(diag_buffer); } /* failed */ } /* report */ return (pr->prn != NULL); } /**************************************************************************** * physical_printer_printf * Inputs: * printobj * pr: Printer object for physical printer * char * fmt: Format string * ... : args * Result: void * * Effect: * Outputs to real or virtual printer ****************************************************************************/ int physical_printer_printf(printobj * pr, char * fmt, ...) { int ret; va_list marker; static char buf[512]; va_start(marker,fmt); ret = vfprintf(pr->prn, fmt, marker); va_end(marker); return ret; } /**************************************************************************** * physical_printer_flush * Inputs: * printobj * pr: Printer object * Result: int * result of fflush * Effect: * Flushes the output ****************************************************************************/ int physical_printer_flush(printobj * pr) { if(pr->prn == NULL) return -1; /* error */ return fflush(pr->prn); } /**************************************************************************** * physical_printer_newline * Inputs: * printobj * pr: Printer file descriptor * Result: void * * Effect: * Advances printer one line ****************************************************************************/ void physical_printer_newline(printobj * pr) { fprintf(pr->prn,"\r\n"); printer_upline(pr); } /**************************************************************************** * scan_string * Inputs: * char * * str: Pointer String to be scanned. May have leading spaces * before the open-quote. * * Result: string * * Scanned string with characters converted; explicit length allows * NUL characters. NULL if error. If there is no string to scan, * returns a string * with len==0 and str==NULL. * Effect: * Allocates heap string for result. Scan pointer is updated. * Syntax: * \n newline * \\ \ * \e escape * \f formfeed * \r return * \t tab * \v vertical tab * \G group mark * \M mouse icon * \W word mark * \R record mark * \S segment mark * \D delta * \Q radical * \_ perf * \c card corner1 * \C card corner2 ****************************************************************************/ static string * scan_string(char * * pstr) { char gstr[81]; int i; char *s; char *d; string * result; s = * pstr; d = gstr; *d = '\0'; while(*s != '\0' && *s != '\"') { /* scan to open quote */ #if debug_scan printf("pre-scanning string: 0x%x=='%c'\n",s,*s); #endif s++; *pstr = s; } /* scan to open quote */ if(*s == '\0') { /* nothing to scan */ result = (string *)malloc(sizeof(string)); if(result == NULL) return NULL; result->str = NULL; result->len = 0; return result; } /* nothing to scan */ if(*s=='"') { s++; *pstr = s; } while(*s != '\0' && *s != '\"') { /* scan it */ #if debug_scan printf("scanning string: 0x%x=='%c'\n",s,*s); #endif switch(*s) { /* char decode */ case '\\': s++; #if debug_scan printf("scanning \\: 0x%x=='%c'\n",s,*s); #endif switch(*s) { /* quote decode */ case '"': *d++ = '"'; break; case 'e': *d++ = '\33'; break; case 'n': *d++ = '\n'; break; case 'f': *d++ = '\f'; break; case 'r': *d++ = '\r'; break; case 't': *d++ = '\t'; break; case 'v': *d++ = '\v'; break; case '\b': *d++ = '\b'; break; case 'G': *d++ = CHAR_GM; break; case 'M': *d++ = CHAR_MI; break; case 'N': *d++ = CHAR_NEX; break; case 'R': *d++ = CHAR_RM; break; case 'S': *d++ = CHAR_SM; break; case 'D': *d++ = CHAR_DL; break; case 'Q': *d++ = CHAR_SQ; break; case 'W': *d++ = CHAR_WM; break; case '_': *d++ = CHAR_PERF; break; case 'C': *d++ = CHAR_CORNER1; break; case 'c': *d++ = CHAR_CORNER2; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': i = (*s) - '0'; s++; while(*s >= '0' && *s <= '7') { /* accum */ #if debug_scan printf("scanning octal: 0x%x=='%c'\n",s,*s); #endif i = i * 8 + (*s) - '0'; s++; } /* accum */ #if debug_scan printf("done scanning octal: 0x%x=='%c'\n",s,*s); #endif s--; /* back up so next incr leaves us where we were */ #if debug_scan printf("stored d (0x%x)= \\%03o\n",d,i); printf("reset s--: 0x%x=='%c'\n",s,*s); #endif *d++ = (unsigned char) i; break; case 'x': /* hex */ s++; /* skip 'x' */ if(isalpha(*s)) { /* alpha */ i = toupper(*s) - 'A' + 10; } /* alpha */ else { /* numeric */ i = (*s) - '0'; } /* numeric */ s++; if(isxdigit(*s)) { /* second hex digit */ i *= 16; if(isalpha(*s)) { /* alpha */ i += toupper(*s) - 'A' + 10; } /* alpha */ else { /* numeric */ i += (*s) - '0'; } /* numeric */ } /* second hex digit */ else { /* not hex digit */ s--; } /* not hex digit */ *d++ = (unsigned char) i; break; default: { sprintf(diag_buffer, "%s(%d): Error: scan_string: unknown escape \"%c\"", cfgname, lineno, *s); tell(diag_buffer); } #if debug_scan printf("stored d (0x%x)= \\%03o\n",d,i); #endif *d++ = *s; break; } /* quote decode */ break; default: #if debug_scan printf("stored d (0x%x)= \\%03o\n",d,i); #endif *d++ = *s; break; } /* char decode */ #if debug_scan printf("end of scanning \\: 0x%x=='%c'\n",s,*s); #endif s++; } /* scan it */ *pstr = s; result = (string *) malloc((unsigned) sizeof(string)); if(result == NULL) return NULL; result->len = d - gstr; #if debug_scan printf("result->len = %d (0x%x - 0x%x + 1)\n",result->len,d,gstr); #endif result->str = malloc((unsigned) (result->len + 1)); for(i=0;ilen;i++) { /* copy chars */ result->str[i] = gstr[i]; result->str[i+1] = '\0'; /* force to be always NUL */ } /* copy chars */ if(*s == '"') { /* skip terminator */ s++; *pstr = s; } /* skip terminator */ return result; } /**************************************************************************** * check_string * Inputs: * string * s: String to check * Effect: * Checks the string for the presence of a 'newline' character, and * issues a warning message if one is found ****************************************************************************/ void check_string(string * s) { return; } /**************************************************************************** * outstring * Inputs: * string * s: String, containing embedded NUL characters * printobj * pr: Output device * Effect: * Writes the string to the output device * Note that we output it one character at a time because it may * have embedded NUL characters ****************************************************************************/ static void outstring(string * s, printobj * pr) { short i; for(i=0;ilen;i++) { /* print it */ (*pr->print)(pr,"%c",s->str[i]); } /* print it */ (*pr->flush)(pr); } /**************************************************************************** * init_seq * Inputs: * char * text: Text line, scanned just past command * printobj * pr: Printer device * Result: boolean * true if success * false if error * Effect: * Extracts the initialization string and stores it for * later transmission to the printer. If the string in * 'init' is not NULL, a new string is created which is * the catenation of the existing string and the new * string. ****************************************************************************/ static boolean init_seq(char * text, printobj * pr) { string * s; s = scan_string(&text); #if debug_effects printf("init string:"); dump_string(s); printf("\n"); if(pr64) printf("pr64 true\n"); #endif if(init == NULL) { /* simple */ /* This is the first init string */ init = s; } /* simple */ else { /* complicated */ string n; n.len = init->len + s->len; n.str = malloc(n.len); if(n.str == NULL) return false; memcpy(n.str,init->str,init->len); memcpy(&n.str[init->len],s->str,s->len); free(init->str); *init = n; freestring(s); } /* complicated */ return true; } /**************************************************************************** * fin_seq * Inputs: * char * text: Text line, scanned just past command * Result: boolean * true if success * false if error * Effect: * Extracts the finalization string and stores it ****************************************************************************/ static void fin_seq(char * text) { final = scan_string(&text); } /**************************************************************************** * dump_string * Inputs: * string * s: String to dump * Effect: * Dumps the string ****************************************************************************/ void dump_string(string * s) { short i; printf("0x%x: string { len %d, str \"", s,s->len); for(i=0;ilen;i++) printf("\\%03o",s->str[i]); printf("\"}"); } /**************************************************************************** * screen_char * Inputs: * char * textline: Input line to be scanned * Result: boolean * true if valid * false if error * Effect: * Sets up the screen bitmaps for the special characters * Syntax: * 1401-char font-char [bits...] * Example: * ........ 0000 0000 00 * ........ 0000 0000 00 * ...*.... 0001 0000 10 * ...*.... 0001 0000 10 * *******. 1111 1110 FE * ...*.... 0001 0000 10 * *******. 1111 1110 FE * ...*.... 0001 0000 10 * *******. 1111 1110 FE * ...*.... 0001 0000 10 * ...*.... 0001 0000 10 * ........ 0000 0000 00 * ........ 0000 0000 00 * ........ 0000 0000 00 * * .sf "\G" "å" "\x00\x00\x10\x10\xFE\x10\xFE\x10\xFE\x10\x10\x00\x00" ****************************************************************************/ boolean screen_char(char * textline) { string * source; string * map; string * bits; source = scan_string(&textline); map = scan_string(&textline); bits = scan_string(&textline); set_screen_font(source,map,bits); /* Save the string for later initialization */ screen_xlat[map->str[0]] = bits; freestring(source); freestring(map); } /**************************************************************************** * spec_char * Inputs: * char * textline: Line containing two strings of the form * "chr" "conversion" * Result: boolean * true if valid * false if error * Effect: * Stores the conversion string indexed by the character ****************************************************************************/ static boolean spec_char(char * textline) { string * ch; string * conv; char * t = textline; int c; ch = scan_string(&t); conv = scan_string(&t); #if debug_scan | debug_effects printf("conversion string: "); dump_string(conv); printf("\n"); #endif if(ch->len != 1) { /* wrong length */ fprintf(stderr,"%s(%d): Error: .sc sequence not single char\n", cfgname,lineno); fprintf(stderr,"%s\n",textline); return false; } /* wrong length */ c = (int) ch->str[0]; if(xlat[c] != NULL && xlat[c] != &space) { /* already defined */ fprintf(stderr,"%s(%d): Error: .sc already specified for character %d (0%03o, 0x%x)\n",cfgname,lineno,c,c,c); fprintf(stderr,"%s\n",textline); } /* already defined */ #if debug_scan printf("xlat[%d] (\\%03o, 0x%x) = 0x%x\n",c,c,c,conv); #endif xlat[c] = conv; return true; } /**************************************************************************** * test_seq * Inputs: * char * s: String which is argument * printobj * pr: Output file * Effect: * Writes the string, then its decoded value, to prn ****************************************************************************/ void test_seq(char * s, printobj * pr) { string * str; fprintf(pr->prn,".ts %s",s); str = scan_string(&s); #if debug_effects printf("test string: "); dump_string(str); printf("\n"); #endif fprintf(pr->prn," => \""); (*pr->write_translated)(str->str,pr); fprintf(pr->prn,"\"\n"); } /**************************************************************************** * screen_font_reset * Result: void * * Effect: * For all entries defined in screen_xlat, set the screen font ****************************************************************************/ void screen_font_reset() { #ifndef NOMAP int i; unsigned char size; switch(video.adapter) { /* what size */ case SC_EGA: size = 14; break; case SC_VGA: size = 16; break; } /* what size */ for(i=0; i<256; i++) { /* scan entries */ if(screen_xlat[i] != NULL) { /* has map */ fontset(i, screen_xlat[i]->str, (unsigned char)(screen_xlat[i]->len > size ? size : screen_xlat[i]->len), size); } /* has map */ } /* scan entries */ #endif } /**************************************************************************** * generic_printer_init * Inputs: * printobj * pr: Print object * boolean test: true if .ts should be executed * Result: boolean * true if success * false if error * Effect: * Performs generic printer and screen init ****************************************************************************/ boolean generic_printer_init(printobj * pr, boolean test) { FILE * init; int i; char initline[81]; if(pr->prn == NULL) return false; for(i=0;i<256;i++) screen_xlat[i] = xlat[i] = NULL; for(i=177;i<0400;i++) { /* space out */ xlat[i] = &space; } /* space out */ init = fopen(cfgname,"r"); if(init==NULL) { /* no init */ return true; /* no init file, assume ok */ } /* no init */ lineno = 0; while(true) { /* init printer */ fgets(initline,81,init); if(feof(init)) break; /* Process the init line */ lineno++; if(diagnostics_on) tell(initline); if(initline[0] == '.') { /* directive */ if(strncmp(initline,".in",3) == 0) { /* init seq */ init_seq(&initline[3],pr); continue; } /* init seq */ if(strncmp(initline,".ts",3) == 0) { /* test seq */ if(test) test_seq(&initline[3],pr); continue; } /* test seq */ if(strncmp(initline,".fi",3) == 0) { /* fin seq */ fin_seq(&initline[3]); continue; } /* fin seq */ if(strncmp(initline,".sc",3) == 0) { /* spec */ spec_char(&initline[3]); continue; } /* spec */ if(strncmp(initline,".sf",3) == 0) { /* screen font */ screen_char(&initline[3]); continue; } /* screen font */ fprintf(stderr,"%s(%d): Error: Unknown initialization command `%-3.3s'\n", cfgname, lineno, initline); } /* directive */ } /* init printer */ fclose(init); (*pr->flush)(pr); return true; } /**************************************************************************** * physical_printer_init * Inputs: * printobj * pr: print file descriptor * boolean test: True if .ts directives are to have action * false if they are not to have action * Result: boolean * true if successful * false if error * Effect: * Initializes the 'prn' device with whatever string is required * Establishes the print conversion strings for the device * Handles the print directives * .in "str" Printer initialization string * .fi "str" Printer finalization string * .sc "chr" "as" Prints chr as indicated value * chr is ascii char, or \nnn ****************************************************************************/ boolean physical_printer_init(printobj * pr, boolean test) { if(diagnostics_on) tell(">physical_printer_init"); if(!generic_printer_init(pr,test)) { /* failed */ if(diagnostics_on) tell("ready)(pr)) { /* go for it */ if(diagnostics_on) tell("physical_printer_init: writing init string"); outstring(init,pr); init = NULL; } /* go for it */ else if(diagnostics_on) tell("physical_printer_init: device offline, init deferred"); } /* try to write it */ if(diagnostics_on) tell("prn == NULL) return; outstring(final,pr); } /**************************************************************************** * physical_write_translated * Inputs: * unsigned char * str: String to write * printobj * pr: Open device designator * Effect: * Writes the string to the output device * Notes: * It is assumed the device is ready; this is tested at a higher * level. By the time we get here, it is supposed to be ready ****************************************************************************/ void physical_write_translated(unsigned char * str,printobj * pr) { short i; if(init != NULL) { /* perform init */ outstring(init,pr); init = NULL; } /* perform init */ for(i=0;iprn); } /* verbatim */ else { /* translate */ outstring(xlat[str[i]],pr); } /* translate */ } /* write it */ } /**************************************************************************** * physical_printer_close * Inputs: * printobj * pr: * Result: void * * Effect: * Closes the printer ****************************************************************************/ void physical_printer_close(printobj * pr) { if(pr->prn == NULL) return; fclose(pr->prn); pr->prn = NULL; } /**************************************************************************** * physical_printer_eject * Inputs: * printobj * pr: Printer object * Result: void * * Effect: * Ejects the paper ****************************************************************************/ void physical_printer_eject(printobj * pr) { (*pr->print)(pr,"\f"); } /**************************************************************************** * physical_test * Result: boolean * false, always ****************************************************************************/ boolean physical_test() { return false; } /**************************************************************************** * physical_printer_clear * Inputs: * printobj * pr: Printer object * Result: void * * Effect: * Does nothing for physical printer ****************************************************************************/ void physical_printer_clear(printobj * pr) { /* does nothing */ } /**************************************************************************** * physical_printer_ready * Inputs: * printobj * pr: Printer object * Result: boolean * true if printer is ready * false if printer is not ready ****************************************************************************/ boolean physical_printer_ready(printobj * pr) { return printer_ready(pr->nlpt); }