/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 15-Nov-85 | [1.40] Created * 25-Nov-85 | [1.125] Default extension to .cdr * 25-Nov-85 | [1.135] Set eof only for last card of last deck * 7-Dec-85 | [1.152] Change sense of '.' test to be correct * 14-Dec-85 | [1.190] Clear eof when 'clear' button activated * 14-Dec-85 | [1.190] Also clear eof when new deck added via 'name' * 15-Dec-85 | [1.211] Change number to include 'card(s) read' * 15-Dec-85 | [1.211] Include legend "reader" on card stack * 19-Dec-85 | [1.215] If bad card column read, display address in B-register * | lights. * | Emit 'tell' messages only if diagnostic mode on * 11-Jan-86 | [1.290] Record bad card column in error message * 8-Feb-86 | [1.355] Added colors to button declarations * 8-Feb-86 | [1.355] Changed from <> to "" on includes * 8-Feb-86 | [1.355] Turn 'name' button on while active, off afterwards * 8-Feb-86 | [1.358] Added hide/show operations around drawing. Mainly * | required to suppress non-mouse cursor * 6-Aug-86 | [1.410] Added NOTREACHED comment to file_error * 18-Aug-86 | [1.414] screen.h -> bscreen.h * 18-Nov-91 | [1.472] Kludged repair to truncated end of this file * 18-Nov-91 | [1.428] memory.h => mem1401.h, avoid ANSI name * 24-Nov-91 | [1.472] _oserr => errno * 24-Nov-91 | [1.472] fileerror now uses strerror instead of hardwired * | decode * 24-Nov-91 | [1.472] removed obsolete #if 0 code * 23-Dec-91 | [1.527] use char_corner to get small card corner *****************************************************************************/ /***************************************************************************** 1401 Emulator Virtual Card Reader *****************************************************************************/ #include "stdio.h" #include "graph.h" #include "stdlib.h" #include "string.h" #include "boolean.h" #include "errno.h" #include "btypes.h" #include "scdspmsg.h" #include "mach.h" #include "mem1401.h" #include "periph.h" #include "button.h" #include "hercules.h" #include "diag.h" #include "disp.h" #include "color.h" #include "display.h" #include "kb.h" #include "scan.h" #include "switches.h" #include "bcd.h" #include "chars.h" void cdr_clear(void); void cdr_name(void); button cdr_clear_button = { cdr_clear_X, cdr_clear_Y, "Clear", false, cdr_clear, YELLOW, YELLOW, YELLOW}; button cdr_name_button = { cdr_name_X, cdr_name_Y, "Name ", false, cdr_name, GREEN, GREEN, GREEN}; void card_status(char * msg,boolean error); extern void draw_card_stack(boolean erase); /* nice big scratch buffer */ #define CDR_LENGTH 132 /* Maximum number of card decks we can have */ #define MAX_CDR_NAME 40 #define CDR_STACK 8 char * cardfiles[CDR_STACK]; short cardstack= -1; /* highest numbered card deck */ static char reader_status[80]; static boolean status_error; static short card_count; static boolean cdr_open = false; static FILE * cdr = NULL; static boolean cdr_eof = false; /**************************************************************************** * init_cdr * Effect: * Initializes the card reader stack structure ****************************************************************************/ void init_cdr() { short i; for(i=0;i 0) { /* text */ sprintf(fmt,"%%-%ds",cardwidth-2); sprintf(msg,fmt,reader_status); scdspmsg(cardbase_Y+2,cardbase_X+1, fore, back, msg); } /* text */ else { /* count */ if(card_count>0) { /* show it */ sprintf(msg,"%5d card%s read",card_count,(card_count == 1 ? "" : "s")); scdspmsg(cardbase_Y+2,cardbase_X+1,H_NORMAL,0,msg); } /* show it */ } /* count */ } /**************************************************************************** * card_status * Inputs: * char * msg: Message to display on top card * boolean error: true if error, false if non-error status * Effect: * Displays the message on the topmost card ****************************************************************************/ void card_status(char * msg,boolean error) { strcpy(reader_status,msg); status_error = error; if(!showing_peripherals()) return; show_status(); } /**************************************************************************** * draw_reader * Effect: * Draws the reader control box ****************************************************************************/ void draw_reader() { attrib fore; attrib back; if(ismono()) { /* mono */ fore = H_NORMAL; back = 0; } /* mono */ else { /* color */ fore = WHITE; back = BLACK; } /* color */ scdspmsg(reader_Y,reader_X,fore,back, "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"); scdspmsg(reader_Y+1,reader_X,fore,back,"³Card Reader ³"); scdspmsg(reader_Y+2,reader_X,fore,back,"³ ³"); scdspmsg(reader_Y+3,reader_X,fore,back,"³ ³"); scdspmsg(reader_Y+4,reader_X,fore,back,"³ ³"); scdspmsg(reader_Y+5,reader_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"); draw_button(&cdr_clear_button); draw_button(&cdr_name_button); draw_card_stack(false); } /**************************************************************************** * check_reader * Inputs: * coord X: screen X-coordinate of mouse hit * coord Y: screen Y-coordinate of mouse hit * Effect: * If a reader operation is selected, performs it ****************************************************************************/ void check_reader(coord X,coord Y) { if(in_button(X,Y,&cdr_clear_button)) (*cdr_clear_button.push)(); if(in_button(X,Y,&cdr_name_button)) (*cdr_name_button.push)(); } /**************************************************************************** * cdr_clear * Effect: * Removes all cards from the reader * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ * ³Card Reader ³ * ³ÉÍÍÍÍÍ» ³ * ³ºclearº ³ * ³ÈÍÍÍÍͼ ³ * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ****************************************************************************/ void cdr_clear() { clear_off(); if(cdr!=NULL) fclose(cdr); cdr = NULL; cdr_open = false; strcpy(reader_status,""); status_error = false; card_count = 0; while(cardstack >= 0) { /* erase card */ cardstack--; draw_card_stack(true); } /* erase card */ clear_cdr_eof(); if(diagnostics_on) log_console_event("CLEAR reader"); } /**************************************************************************** * cdr_name * Effect: * Prompts user for filename of new card image * * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ * ³Card Reader ³ * ³ ÉÍÍÍÍÍ»³ * ³ ºname º³ * ³ ÈÍÍÍÍͼ³ * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ****************************************************************************/ void cdr_name() { char name[MAX_CDR_NAME]; coord Y; coord X; clear_off(); if(cardstack >= CDR_STACK-1) { /* stacker full */ return; } /* stacker full */ cardstack++; draw_card_stack(false); Y = cardbase_Y - cardstack * cardoffset_Y + 1; X = cardbase_X + cardstack * cardoffset_X; /* turn the button on */ cdr_name_button.active = true; draw_button(&cdr_name_button); /* Create a space for the user to type */ scscroll(1,H_REVERSE,Y,(coord)(X+2),Y,(coord)(X+cardwidth-3),SCR_UP); sccurset(Y,(coord)(X+2)); gets(name); scscroll(1,H_NORMAL,Y,(coord)(X+2),Y,(coord)(X+cardwidth-3),SCR_UP); strcpy(cardfiles[cardstack],name); if(strlen(cardfiles[cardstack])==0) { /* delete card */ cardstack--; draw_card_stack(true); } /* delete card */ else { /* add card */ draw_card_stack(false); clear_cdr_eof(); } /* add card */ /* turn the button off */ cdr_name_button.active = false; draw_button(&cdr_name_button); if(diagnostics_on) { /* log it */ log_console_event("NAME reader"); sprintf(diag_buffer,"Card deck %d, name \"%s\"", cardstack,cardfiles[cardstack]); tell(diag_buffer); } /* log it */ } /**************************************************************************** * draw_card_stack * Inputs: * boolean erase: true to erase n+1st image * false if no erasure * Effect: * Draws the stack of active cards in the reader ****************************************************************************/ void draw_card_stack(boolean erase) { short i; short limit; attrib fore; attrib back; if(ismono()) { /* mono */ fore = H_NORMAL; back = 0; } /* mono */ else { /* color */ fore = WHITE; back = BLACK; } /* color */ if(!showing_peripherals()) return; limit = (erase ? cardstack+1 : cardstack); if(limit < 0) return; /* nothing to draw */ hide_mouse_cursor(); for(i=0;i <= limit;i++) { /* draw a card */ char msg[cardwidth+5]; char fmt[20]; coord X; coord Y; X = cardbase_X + i * cardoffset_X; Y = cardbase_Y - i * cardoffset_Y; if(erase && i==limit) scdspmsg(Y,X,fore,back," "); else { /* draw it */ char L[40]; if(i= 0) show_status(); show_mouse_cursor(); } /**************************************************************************** * file_error * Inputs: * short err: File error code * Result: char * * Pointer to string which holds message. MUST COPY THIS STRING! ****************************************************************************/ char * file_error(short err) { return strerror(err); } /**************************************************************************** * read_card * Result: boolean * true if card was read successfully * false if card jammed, no virtual card reader assigned or similar * problem * Effect: * Reads a card image from the virtual card reader into memory * locations 1-80. ****************************************************************************/ static char next_card[CDR_LENGTH]; /* the 'next' card goes here */ boolean read_card() { short i; unsigned char buffer[132]; unsigned char bcd_buffer[80]; if(cardstack < 0) { /* no more */ tell("No cards in card reader"); return false; /* no cards in reader */ } /* no more */ if(!cdr_open) { /* If the current card file is not open, open it. At eof we mark the card reader as closed before popping the stack */ /* We first try the filename as given */ cdr = fopen(cardfiles[0],"r"); if(cdr == NULL) { /* try again? */ short err = errno; char * msg; /* If the open failed, we try appending the extension '.cdr' and trying that file */ if(err==2) { /* file not found */ /* Note that the test below doesn't work with names like ../foo. Fix this someday */ if(strchr(cardfiles[0],'.') == NULL) { /* try extension */ strcat(cardfiles[0],".cdr"); cdr = fopen(cardfiles[0],"r"); if(cdr != NULL) goto ok; err = errno; } /* try extension */ } /* file not found */ /* If we get here, the failure was something other than file not found or the retry with extension .cdr failed */ msg = file_error(err); /* Mark the 1401 as having a reader error */ card_status(msg,true); /* Log the info the the file */ if(diagnostics_on) { /* report error to log */ sprintf(diag_buffer,"Unable to open file %s, code = %d (%s)", cardfiles[0],err, strerror(err)); tell(diag_buffer); } /* report error to log */ return false; } /* try again? */ ok: /* Clear any error status, clear eof, mark the card stack as open Read the first card. */ strcpy(reader_status,""); cdr_eof = false; cdr_open = true; fgets(next_card,CDR_LENGTH,cdr); } /* We have now read a card, either the first read of the deck or leftover from the last read of the deck */ if(feof(cdr)) { /* go to next deck */ fclose(cdr); /* close last file */ cdr = NULL; /* and mark it as gone */ cdr_open = false; remove_stack(); /* bring next deck into play */ return read_card(); /* recursive call to get next card */ } /* go to next deck */ /* At this point we have an open card reader and no EOF condition */ strcpy(buffer,next_card); /* read a card! */ card_count++; /* The line may not exceed 80 characters */ { /* validate card image */ boolean saw_lf; saw_lf = false; /* Scan the image looking for a newline. Note that the test is '<=80' so that we actually search for the lf in card position 81, which is where we would find it in a perfect world. (In the real world, we probably find it earlier) */ for(i=0;i<=80;i++) if(buffer[i] == '\n') { /* short line */ saw_lf = true; break; } /* short line */ if(!saw_lf) { /* bad */ if(diagnostics_on) { /* tell problem */ tell("Bad card image; >80 characters"); tell(buffer); } /* tell problem */ return false; /* bad card image */ } /* bad */ } /* validate card image */ /* At this point we have a valid card image which we can now transfer to the input buffer. If the card image is less than 80 columns we pad on the right with spaces */ /* clear out the BCD buffer (set to BCD spaces) */ for(i=0;i<80;i++) bcd_buffer[i] = '\0'; /* We have a card image of 80 or fewer characters */ for(i=0;i<80;i++) { /* convert to BCD */ int ch; /* not unsigned char! */ if(buffer[i] == '\n' || buffer[i] == '\0') break; ch = ascii_to_bcd(buffer[i]); if(ch == -1) { /* illegal character */ /* We probably want to implement I/O check stop here someday */ char badcol[80]; if(diagnostics_on) tell("Illegal BCD character"); sprintf(badcol,"Bad column %d",i); B_addr = i; /* display column in B_addr */ cycle = cycle_B; card_status(badcol,true); return false; } /* illegal character */ bcd_buffer[i] = (unsigned char) ch; } /* convert to BCD */ /* At this point we have established that all the characters are valid BCD characters, and we have moved them to the BCD buffer */ /* Now transfer he BCD buffer to the input buffer locations 1-80 without disturbing the word marks which have been set. */ for(i=0;i<80;i++) { memory[i+1] = WM(memory[i+1]) | bcd_buffer[i]; } fgets(next_card,132,cdr); /* read a card! */ if(feof(cdr)) { /* eof */ if(cardstack == 0) { /* no more cards */ /* The image we just transferred was the last card. Turn on sense switch A indicator */ set_cdr_eof(); } /* no more cards */ } /* eof */ /* let user know card is in */ #pragma message(__FILE__ "():" ": Error: MISSING MATERIAL HERE") /* Somehow over the years the tail of this file was truncated. After careful examination, I can't figure out what was meant by the comment 'let user know card is in', which was the last line of the file. Backup tapes going back three years have the same damage, and I have no older backups. Sigh. -jmn 20-Nov-91 */ return true; }