/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 15-Nov-85 | [1.40] Created * 23-Nov-85 | [1.97] Added fflush operations * 7-Dec-85 | [1.151] Init printer * 7-Dec-85 | [1.151] Use \r\n, open in binary mode so control chars work * 11-Dec-85 | [1.170] Call write_translated instead of fprintf * 27-Dec-85 | [1.252] Implemented immediate carriage operations. Deferred * | operations NYI * 27-Dec-85 | [1.253] Put diagnostic printout in various places for advancing * | lines and such * 28-Dec-85 | [1.264] Added printwm * 29-Dec-85 | [1.273] Handle deferred skip/space. Set C9, C12 indicators * | on skip_to_channel * 30-Dec-85 | [1.281] Because CRLF now issued in advance_line, put fflush * | after advance_line calls, not before * 31-Dec-85 | [1.289] Put some more printer_ready calls around some * | operations, hoping to avoid DOS error. May yet have to use * | critical error vector (grumble) * 23-Jan-86 | [1.303] Added device designator 'lpt' instead of hardwired * | printer number * 24-Jan-86 | [1.306] Added 'nlpt', pass to printer_ready() * 8-Feb-86 | [1.357] Added color support. <> => "" in includes * 23-Feb-86 | [1.365] All printfs => scdspmsg for color support * 29-Jul-86 | [1.385] Added dump_color_screen * 29-Jul-86 | [1.385] Added void decls * 18-Aug-86 | [1.414] screen.h -> bscreen.h * 10-Nov-91 | [1.428] converted to Microsoft C 6.0 * 18-Nov-91 | [1.428] memory.h => mem1401.h, avoid ANSI name * 20-Nov-91 | [1.429] new virtual printer code installed * 22-Dec-91 | [1.507] added clear button for virtual printer * 22-Dec-91 | [1.513] adjust carriage tape test to line - 1 * 22-Dec-91 | [1.513] reorganized for better carriage tape handling * 22-Dec-91 | [1.514] moved channel tape vars to form.h * 23-Dec-91 | [1.536] check open before ready, since the open can * | proceed even if the printer is offline. *****************************************************************************/ /***************************************************************************** 1401 Emulator Print Device Emulator This module implements the virtual printer; includes the 'print storage' function. *****************************************************************************/ #include "stdio.h" #include "boolean.h" #include "btypes.h" #include "scdspmsg.h" #include "mem1401.h" #include "mach.h" #include "diag.h" #include "button.h" #include "periph.h" #include "alerts.h" #include "disp.h" #include "hercules.h" #include "bcd.h" #include "color.h" #include "addr.h" #include "alert.h" #include "pr.h" #include "printers.h" #include "print.h" #include "cdump.h" #include "prdev.h" #include "display.h" #include "rdy.h" #include "form.h" extern void prn_form(void); extern void prn_line(void); extern void prn_clear(void); button Form_button = { prn_form_X, prn_form_Y, "Form ", false, prn_form, COLOR_GREEN, COLOR_GREEN, COLOR_GREEN}; button Line_button = { prn_line_X, prn_line_Y, "Line ", false, prn_line, COLOR_GREEN, COLOR_GREEN, COLOR_GREEN}; button prn_Clear_button ={ prn_clear_X, prn_clear_Y, "Clear", false, prn_clear, COLOR_YELLOW, COLOR_YELLOW, COLOR_YELLOW}; extern char * lpt; boolean pr64 = true; /* Use 64-character set */ unsigned char deferred = '\0'; boolean C9 = false; /* did we see channel 9 indicator */ boolean C12 = false; /* did we see channel 12 indicator */ /**************************************************************************** * draw_printer * Effect: * Draws the printer control box ****************************************************************************/ void draw_printer() { attrib fore; attrib back; if(ismono()) { /* mono */ fore = H_NORMAL; back = 0; } /* mono */ else { /* color */ fore = COLOR_WHITE; back = COLOR_BLACK; } /* color */ if((*current_printer->is_virtual)()) { /* virtual printer */ scdspmsg(printer_Y,printer_X,fore,back, "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"); scdspmsg(printer_Y+1,printer_X,fore,back,"³Printer ³"); scdspmsg(printer_Y+2,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+3,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+4,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+5,printer_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"); } /* virtual printer */ else { /* physical printer */ scdspmsg(printer_Y,printer_X,fore,back, "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"); scdspmsg(printer_Y+1,printer_X,fore,back,"³Printer ³"); scdspmsg(printer_Y+2,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+3,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+4,printer_X,fore,back,"³ ³"); scdspmsg(printer_Y+5,printer_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"); } /* physical printer */ draw_button(&Form_button); draw_button(&Line_button); if((*current_printer->is_virtual)()) draw_button(&prn_Clear_button); } /**************************************************************************** * check_printer * Inputs: * coord X: screen X-coordinate of mouse hit * coord Y: screen Y-coordinate of mouse hit * Effect: * If a printer operation is selected, performs it ****************************************************************************/ void check_printer(coord X,coord Y) { if(in_button(X,Y,&Form_button)) (*Form_button.push)(); if(in_button(X,Y,&Line_button)) (*Line_button.push)(); if(in_button(X,Y,&prn_Clear_button)) (*prn_Clear_button.push)(); } /**************************************************************************** * open_printer * Inputs: * printobj * pr: Printer object to open * channel_tape tape: Pointer to channel tape, or NULL if default is * to be used * Result: boolean * true if printer could be opened * false if some failure occurred * Effect: * Opens the 'prn' device, initializes state ****************************************************************************/ boolean open_printer(printobj * pr,channel_tape * tape) { if(diagnostics_on) tell("open_printer"); if(!(*pr->open)(pr)) return false; if(!(*pr->ready)(pr)) return false; /* Checks hardware ready line */ pr->current_line = 0; if(tape != NULL) pr->form = tape; else pr->form = &standard_tape; if(pr->prn != NULL) { /* got printer */ boolean ok; ok = (*pr->init)(pr,diagnostics_on); if(diagnostics_on) { /* tell init */ if(ok) tell("Initialized printer for extended set"); else tell("Failed to initialize printer for extended set"); } /* tell init */ /* Initialize 1401 simulated state */ C9 = false; C12 = false; return true; } /* got printer */ return false; } /**************************************************************************** * close_printer * Inputs: * printobj * pr: * Effect: * Closes the printer file if it was open ****************************************************************************/ void close_printer(printobj * pr) { (*pr->final)(pr); (*pr->close)(pr); } /**************************************************************************** * advance_line * Inputs: * printobj * pr: Print object * Effect: * Advances the printer by a suitable amount. If 'deferred' is * NUL, advances by one line, otherwise advances as indicated * by the deferred count. * If channel 9 is sensed, set C9 indicator; if channel 12 is sensed, * set C12 indicator. Clear * C9 or C12 if any indicator is sensed (except corresponding one) ****************************************************************************/ void advance_line(printobj * pr) { if(!(*pr->ready)(pr)) return; (*pr->newline)(pr); switch(deferred) { /* do deferred action */ case '\0': /* No deferred carriage action */ printer_upline(pr); break; /* nothing */ case 'A': /* skip to channel 1 */ case 'B': /* skip to channel 2 */ case 'C': /* skip to channel 3 */ case 'D': /* skip to channel 4 */ case 'E': /* skip to channel 5 */ case 'F': /* skip to channel 6 */ case 'G': /* skip to channel 7 */ case 'H': /* skip to channel 8 */ case 'I': /* skip to channel 9 */ skip_to_channel(pr,deferred - '@'); break; case '?': skip_to_channel(pr,10); break; case '.': skip_to_channel(pr,11); break; case ')': skip_to_channel(pr,12); break; case 'T': /* triple space */ (*pr->newline)(pr); if(pr->form->tape[pr->current_line] != 0) C9 = C12 = false; if(pr->form->tape[pr->current_line] & (1<<9)) C9 = true; if(pr->form->tape[pr->current_line] & (1<<12)) C12 = true; /* FALLS THRU */ case 'S': /* double space */ (*pr->newline)(pr); if(pr->form->tape[pr->current_line] != 0) C9 = C12 = false; if(pr->form->tape[pr->current_line] & (1<<9)) C9 = true; if(pr->form->tape[pr->current_line] & (1<<12)) C12 = true; /* FALLS THRU */ case '/': (*pr->newline)(pr); break; /* We do not need a default case because the carriage function will always leave a valid value (he said optimistically...) */ } /* do deferred action */ if(pr->form->tape[pr->current_line] != 0) C9 = C12 = false; if(pr->form->tape[pr->current_line] & (1<<9)) C9 = true; if(pr->form->tape[pr->current_line] & (1<<12)) C12 = true; deferred = '\0'; } /**************************************************************************** * print_storage * Result: boolean * true if succeeded * false if lpt wedged * Effect: * Prints out the locations as selected by the address switches ****************************************************************************/ boolean print_storage(printobj * pr) { short addr; short i; char buffer[PRINT_LENGTH+2]; if(!(*pr->open)(pr)) return false; /* DOS open */ addr = get_address_switches(); for(i=0;iwrite_translated)(buffer,pr); (*pr->newline)(pr); if(diagnostics_on) { /* diag dump */ sprintf(diag_buffer,"%s",buffer); tell(diag_buffer); } /* diag dump */ for(i=0;iwrite_translated)(buffer,pr); if(diagnostics_on) { /* diag dump */ sprintf(diag_buffer,"%s",buffer); tell(diag_buffer); } /* diag dump */ (*pr->newline)(pr); (*pr->flush)(pr); return true; } /**************************************************************************** * print * Result: boolean * true if print succeeded * false if print failed * Effect: * Transfers the contents of locations 201-332 to the printer * Advances the line count ****************************************************************************/ boolean print(printobj * pr) { short i; char buffer[PRINT_LENGTH+2]; if(!(*pr->open)(pr)) return false; for(i=0;iready)(pr)) return false; (*pr->write_translated)(buffer,pr); if(!(*pr->ready)(pr)) return false; (*pr->flush)(pr); if(diagnostics_on) tell(buffer); (*pr->newline)(pr); return true; } /**************************************************************************** * printwm * Result: boolean * true if print succeeded * false if print failed * Effect: * Transfers the word mark info of locations 201-332 to the printer * Advances the line count ****************************************************************************/ boolean printwm(printobj * pr) { int i; char buffer[PRINT_LENGTH+2]; if((*pr->open)(pr)) return false; for(i=0;iwrite_translated)(buffer,pr); if(diagnostics_on) tell(buffer); (*pr->newline)(pr); (*pr->flush)(pr); return true; } /**************************************************************************** * form * Inputs: * printobj * pr: Printer descriptor object * Result: boolean * true if printer succeeds * false if fails * Effect: * Performs a formfeed (eject to carriage control 1) on the printer * * Notes: * This implements the 'form' button on the virtual printer station. * It effects the realignment by sending a formfeed to the printer * and sets the current_line to the first line which contains a column 1 * mark ****************************************************************************/ boolean form(printobj * pr) { int i; if(!(*pr->open)(pr)) return false; if(!(*pr->ready)(pr)) return false; if((*pr->is_virtual)()) { /* virtual printer */ /* In the loop below we artificially limit the span to no more than some small multiple of page length. This is our "hardware protection" against runaway carriage tapes. The multiple chosen is > 2 so we can have parity-preserving channel tapes. */ for(i=0; i < 3*pr->form->pagelength; i++) { /* skip to chnl 1 */ (*pr->newline)(pr); /* Note that we skip and then test, so that the virtual printer works just like the regular one in that repeated 'form eject' pushes eject successive pages */ if( pr->form->tape[pr->current_line] & (1<<1)) { /* channel 1 punch */ return true; } /* channel 1 punch */ } /* skip to chnl 1 */ } /* virtual printer */ else { /* physical printer */ (*pr->eject)(pr); if(!(*pr->ready)(pr)) return false; (*pr->flush)(pr); if(!(*pr->ready)(pr)) return false; for(pr->current_line = 0; pr->current_line < pr->form->pagelength; pr->current_line++) if(pr->form->tape[(pr->current_line)] & (1<<1)) { /* found chn 1 */ return true; } /* found chn 1 */ /* if we get here, no channel 1 set in tape, return false */ (*pr->flush)(pr); return false; } /* physical printer */ } /**************************************************************************** * line * Inputs: * printobj * pr: Printer object * Result: boolean * true if succeeded * false if failed * Effect: * Advances printer one line ****************************************************************************/ static boolean pr_line(printobj * pr) { if(!(*pr->open)(pr)) return false; if(!(*pr->ready)(pr)) return false; advance_line(pr); if(!(*pr->ready)(pr)) return false; (*pr->flush)(pr); if(diagnostics_on) { /* tell */ sprintf(diag_buffer,"advanced printer, now on line %d;%s%s", pr->current_line, (C9 ? " channel 9 on" : ""), (C12 ? " channel 12 on" : "")); tell(diag_buffer); } /* tell */ return true; } /**************************************************************************** * skip_to_channel * Inputs: * short n: Channel to go to * * Result: boolean * true if succeeded * false if failed * Effect: * Advances to the indicated channel ****************************************************************************/ boolean skip_to_channel(printobj * pr, short n) { int i; if(diagnostics_on) { /* report */ sprintf(diag_buffer,"skip_to_channel(%d)",n); tell(diag_buffer); } /* report */ if(!(*pr->open)(pr)) return false; for(i=0;i < 3 * pr->form->pagelength; i++) { /* skip ahead */ if(pr->form->tape[pr->current_line] & (1<ready)(pr)) return false; (*pr->newline)(pr); if(pr->form->tape[pr->current_line] != 0) C9 = C12 = false; if(pr->form->tape[pr->current_line] & (1<<9)) C9 = true; if(pr->form->tape[pr->current_line] & (1<<12)) C12 = true; if(!(*pr->ready)(pr)) return false; } /* skip ahead */ (*pr->flush)(pr); return true; } /**************************************************************************** * prn_form * Effect: * Performs a formfeed realignment of the printer ****************************************************************************/ void prn_form() { if(form(current_printer)) return; alert(alert_printer); return; } /**************************************************************************** * oneline * Inputs: * printobj * pr: Printer object * Result: void * * Effect: * Advances printer one line, turning on alert light if not ready ****************************************************************************/ static void oneline(printobj * pr) { if(pr_line(current_printer)) return; alert(alert_printer); } /**************************************************************************** * prn_line * Effect: * Performs a linefeed function from the console switch ****************************************************************************/ void prn_line(void) { oneline(current_printer); } /**************************************************************************** * carriage * Inputs: * unsigned char d: BCD character for forms control * printobj * pr: Printer descriptor * Result: boolean * true if operation succeeded * false if operation failed (illegal d-char, printer offline, etc.) * Effect: * Effects the forms control operation specified; if an operation * that takes place after print, defers it to next print operation ****************************************************************************/ boolean carriage(unsigned char d,printobj * pr) { unsigned char p; p = bcd_to_ascii(d); deferred = '\0'; /* cancel pending deferred operation (is this correct?) */ if(diagnostics_on) { /* report */ sprintf(diag_buffer,"carriage(%d [\'%c\'])",d,p); tell(diag_buffer); } /* report */ switch(p) { /* cc decode */ /* immediate skip to channel */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': skip_to_channel(pr,p - '0'); break; case '0': skip_to_channel(pr,10); break; case '#': case '=': skip_to_channel(pr,11); break; case '@': case '\'': skip_to_channel(pr,12); break; /* Deferred skip */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case '?': case '.': case ')': deferred = p; break; /* space immediate */ case 'J': oneline(pr); break; case 'K': oneline(pr); oneline(pr); break; case 'L': oneline(pr); oneline(pr); oneline(pr); break; /* Space deferred */ case '/': case 'S': case 'T': deferred = p; break; default: alert(alert_process); tell("**** Illegal CC d-character ****"); return false; } /* cc decode */ return true; } /**************************************************************************** * dump_color_screen * Inputs: * printobj * prn: * Effect: * Dumps the screen to a color printer (assumed to be connected) ****************************************************************************/ void dump_color_screen(printobj * pr) { cdump(pr->prn,true); fflush(pr->prn); } /**************************************************************************** * prn_clear * Result: void * * Effect: * Clears the printer ****************************************************************************/ void prn_clear() { (*current_printer->clear)(current_printer); }