.TITLE ALVST5 Alvin Console Input .PSECT ALVIN,GBL,CON .Ident /LVL51 / .MCALL $ALVIN,$LIST,$SPAN ;; ;;*************** Internal Globals: ;; .GLOBL GetList,GETSTR,GETINPUT,GETNUMBER,GETDECIMAL .GLOBL GETYN ;ADDED 7-27-79 ;; ;;************** External Globals: ;; .Globl PutList .Globl Receive,AlvIdle .Globl BufEOL,Press,Span,CmdCopy,CmdMatch,GetByte .Globl CRLF,BufLimit,CanLine,BrkOut,CmdNx0 ;+ ;;********************************************************************** ;; The ALVIN STRING I/O SUBROUTINES provide console input and ;; OUTPUT FUNCTIONS. The PUTList routine is now reentrant and ;; is a separate module for linking purposes. ;; FOR INPUT, STANDARD STRING PREPROCESSING IS APPLIED ;; AND THE RESULTANT STRING OR NUMBER IS RETURNED IN AN EASILY ;; USED FORM. CONTROL IS NOT RETURNED TO THE USER UNTIL THE ;; INPUT IS COMPLETE. ;; FOR OUTPUT, SIMPLE LINEAR STRINGS (ASSUMED TO BE STATIC DURING ;; THE OUTPUT OPERATION) ARE listed using the "STRING" control ;; function of the Alvin SEND routine. ;; THE OUTPUT IS BEGUN and CONTROL IS RETURNED TO THE USER ;; FOR ASYNCHRONOUS PROCESSING, BUT THE NEXT REQUEST FOR OUTPUT ;; MAY BE HELD UP IF THE PREVIOUS LIST IS NOT COMPLETE. ;; Output is to the global LIST logical unit number and input ;; is from the global KEYB logical unit number. Input ;; operations use the Keyboard's default buffer. ;; ;; LATEST REVISION: 20-DEC-79 - LINKED TO ALVIN LEVEL 4 BASE ;; 15-APR-80 - ADDED CALLS TO ALVIDLE WHERE IN WAIT LOOPS ;; 18-Nov-83 - Conversion to Alvin Version 5. ;; 29-Dec-83 - GetList global defined to replace GETSTR. ;; 11-Jul-84 DVJ - Added a Null character to the end of input strings. ;;********************************************************************** ;- $ALVIN $REGS HT=011 ;HORIZONTAL TAB CHARACTER BLANK=40 ;SPACE CHARACTER ;+ ;;********************************************************************** ;; GetList - Subroutine to input strings using the Alvin console. It ;; advances to a new line, lists the user prompt, and lists a '? '. ;; The string is input via Getinput which pre-processes the input. ;; The string is copied into a variable string descriptor of the form: ;; ;; VARIABLE_STRING_DESC: .WORD (BEGINNING ADDRESS OF STRING - STATIC) ;; .WORD (ADR OF LAST CHAR IN STRING - DYNAMIC) ;; .WORD (MAXIMUM ENDING ADR OF STRING - STATIC) ;; ;; The string is linear starting at the beginning address and is ;; truncated on the right if there is insufficient room. ;; CONTROL CHARACTERS are NOT copied into the string. ;; LOWER CASE characters are forced to UPPER CASE. ;; the PARITY bit has been REMOVED on all chars in the string. ;; If a null string is input, the 1st and only char in the string ;; will be a binary zero (character=null). A null character is ;; always appended to the end of each string although it is not ;; included in the character count returned to the user. ;; The CHARACTER COUNT of the string is returned in REGISTER 0. ;; if a BREAK is entered during input, a message will print ;; acknowledging the fact and the break exit will be taken. ;; ;; Expects calls of the form: ;; JSR R5,GETList ;(can be shortened to GETLis) ;; .Word (adr of user prompt static string descriptor) ;; .Word (adr of target variable string descriptor) ;; Br break ;Break requested during input ;; ;; ;; Note: If the user prompt static string descriptor address is zero, ;; then this address is assumed to be in register 3. ;; ;- GetList:: ;Name to replace GetStr which is a conflict. GETSTRING: Mov R4,-(SP) Mov R3,-(SP) ;Save registers used. Mov R2,-(SP) Clr -(SP) ;Input character count=0 if break. Mov (R5)+,R2 ;Get adr of prompt static string desc. Beq GETS20 ;If zero, then prompt desc already in reg 3. Mov R2,R3 ;Else, put it in reg 3. GETS20: Jsr R5,GETINPUT ;Get input from the keyboard. .Word 0 ;Prompt desc is in reg 3. Br GETSX ;If break requested, exit. Mov R0,R4 ;Save the Buffer descriptor used by GetInput. Mov (R5)+,R3 ;Get adr of target variable string desc. Mov (R3),R2 ;Get starting adr of target string. GETS50: Jsr R5,GETCHR ;Get a char from the buffer in Register 4. Br GETS60 ;Proceed when buffer empty. Movb R0,(R2)+ ;Store this char in the string. Inc (Sp) ;Increment the character counter. Cmp R2,4(R3) ;Is the available space used? Blo GETS50 ;No, loop for all chars (leave space for a null). GETS60: Clrb (R2) ;Add a null character to the end of the string. Tst (SP) ;Were any other characters put into the string? Beq Gets80 ;No, branch - Do not backup the end pointer. Dec R2 ;Backup pointer to last character input. GetS80: Mov R2,2(R3) ;Update dynamic end pointer of the target desc. GETSX: Tst (R5)+ ;Increment the return address. Mov (SP)+,R0 ;Return the count to the user. Mov (SP)+,R2 ;Restore registers used. Mov (SP)+,R3 Mov (SP)+,R4 Rts R5 ;Return with char count in reg 0. ;+ ;;********************************************************************** ;; GetInput - subroutine to get input from the Alvin keyboard device. ;; Advances to a new line and lists the user prompt and a '? '. ;; Processes backspaces and overrides tabs to blanks dynamically. ;; Reads into the DEFAULT BUFFER for the console KEYBOARD. ;; If a BREAK is entered during input, a message will be listed ;; and the break exit will be taken. ;; ;; Expects calls of the form: ;; JSR R5,GETINPUT ;(Can be shortened to GETINP) ;; .Word (adr of user prompt static string descriptor) ;; Br break ;Break requested during input. ;; ;; ;; Note: If the user prompt static string descriptor address is zero, ;; then this address is assumed to be in register 3. ;; ;- $Span ;Define the SPAN subroutine function bits. ;; GETINPUT:: Mov R4,-(SP) Mov R3,-(SP) ;Save registers used. Mov R2,-(SP) Mov R1,-(SP) Mov (R5)+,R2 ;Get adr of user prompt static string desc. Beq GETIN1 ;If zero, then it is already in reg 3. Mov R2,R3 ;Else put it in reg 3. GETIN1: Jsr PC,CRLF ;Go to a new line. Jsr R5,PutList ;List the prompt. .Word 0 ;(adr of prompt string desc is in reg 3) Jsr PC,CMDNX0 ;Prompt '? ' for input now. GETIN2: Jsr R5,RECEIVE ;Enable the keyboard for input. .Word KEYB+Reset+UseDB ;Use the Default Buffer and Reset it. .Word 0 ;(filler - using Default Buffer) Br GETIN2 ;Loop until keyboard enabled. Mov R0,R1 ;Device Desc adr - Was this a valid device? Bne Getin4 ;Yes, branch with control block adr in R1 $LIST Br Getinx ;Take the break exit. ;; GETIN4: MOV (R1),R2 ;Get Input device logical status Mov BDAdr(R1),R4 ;Get the Buffer Desc address. GETIN5: Jsr R5,SPAN ;Find any occurance of a tab .Word 0 ;Use the Buffer Desc in Reg 4. .WORD RETURN+NOUPDATE+UNTIL!HT ;FIND TAB AND RETURN POINTER BR GETIN8 ;PROCEED WHEN NO MORE TABS MOVB #BLANK!200,(R0) ;OVERRIDE THE TAB TO A BLANK W/PARITY BR GETIN5 ;LOOP FOR ALL TABS IN THE BUFFER ;; GETIN8: JSR R5,PRESS ;REMOVE BACKSPACES .WORD 0 BIT #COMPLETE,R2 ;IS THE KEYBOARD INPUT DONE? BNE GETINDONE ;NO, LOOP UNTIL ;; JSR PC,ALVIDLE ;WAITING NOW, LET ALVIDLE DO SOME WORK BR GETIN4 ;LOOP TO CHECKUP ON KEYBOARD ;; GETINDONE: BIT #CANCEL!BRKREQ,R2 ;YES, WAS THE INPUT CANCELED? BEQ GETIN9 ;NO, BRANCH TO PROCESS THE INPUT JSR PC,CANLINE ;ACKNOWLEDGE INPUT CANCELLED BIT #BRKREQ,R2 ;WAS A BREAK REQUESTED? BEQ GETIN1 ;NO, LOOP TO ALLOW INPUT AGAIN JSR PC,BRKOUT ;ACKNOWLEDGE BREAK REQUESTED BR GETINX ;AND EXIT ;; GETIN9: BIT #BUFULL,R2 ;DID INPUT TERMINATE WITH BUFFER FULL? BEQ GETINOK ;NO, PROCEED NORMALLY JSR PC,BUFLIMIT ;YES, ACKNOWLEDGE BUFFER LIMIT EXCEEDED JSR R5,BUFEOL ;TERMINATE BUFFER WITH STANDARD END-OF-LINE .WORD 0 GETINOK: TST (R5)+ ;INCR RETURN ADDRESS GETINX: MOV R4,R0 ;Return the Buffer Desc in Reg 0. Mov (SP)+,R1 ;Restore Registers Used. MOV (SP)+,R2 MOV (SP)+,R3 Mov (SP)+,R4 RTS R5 ;AND RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO INPUT DECIMAL INTEGERS FROM THE KEYBOARD. ;; ALLOWS FOR STANDARD ALVIN STRING PRE-PROCESSING. ;; ALLOWS PREFIX AND/OR POSTFIX BLANKS, BUT NO IMBEDDED BLANKS. ;; ALL CONTROL CHARS AFTER PRE-PROCESSING ARE IGNORED. ;; NUMBERS TOO LARGE OR SMALL (INCLUDING OVERFLOW) ARE RE-INPUT. ;; NULL INPUT AND/OR INVALID CHARACTERS FORCE RE-INPUT OF NUMBER. ;; A PREFIX '+' OR '-' IS ALLOWED IMMEDIATELY BEFORE THE NUMBER. ;; ALL INPUT NUMBERS ARE CHECKED AGAINST USER SPECIFIED BOUNDS. ;; NUMBERS OUT-OF-RANGE ARE FORCED TO BE RE-INPUT. ;; IF A BREAK IS ENTERED DURING INPUT, THE BREAK EXIT IS TAKEN. ;; THE NUMBER IS RETURNED IN REGISTER 0. ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,GETNUMBER ;(CAN BE SHORTENED TO GETNUM) ;; .WORD (ADDRESS OF USER PROMPT STATIC STRING DESCRIPTOR) ;; .WORD (LOWER BOUND ON NUMBER, INCLUSIVE) ;; .WORD (UPPER BOUND ON NUMBER, INCLUSIVE) ;; BR BREAK ;BREAK REQUESTED DURING INPUT ;; GETDECIMAL: ;ALIAS GETDEC ;; ;- GETNUMBER: MOV R4,-(SP) ;SAVE REGISTERS USED MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) GETN10: Mov (R5),R3 ;Get adr of user prompt static str desc. Jsr R5,GETINPUT ;Get input from the keyboard. .WORD 0 ;USER PROMPT DESC ADR IS IN REG 3 BR GETNX ;EXIT IF BREAK REQUESTED Mov R0,R4 ;Put the Buffer Desc Address in R4. JSR R5,SPAN ;SPAN PREFIX BLANKS AND CONTROL CHARS .WORD 0 .WORD BLANK BR GETN50 ;INVALID INPUT IF NULL CLR R1 ;SET SIGN-OF-NUMBER FLAG=0=POSITIVE CLR R2 ;SET CURRENT NUMBER VALUE TO ZERO JSR R5,GETCHR ;CHECK FOR THE SIGN BR GETN50 ;INVALID IF INPUT NULL CMP R0,#'+ ;IS THERE A PREFIX PLUS? BEQ GETN20 ;YES, PROCEED WITH NEXT CHAR CMP R0,#'- ;IS THERE A PREFIX MINUS? BNE GETNCH ;NO, THEN THIS MUST BE A DECIMAL CHAR COM R1 ;YES, SET NEGATIVE INDICATOR GETN20: JSR R5,GETCHR ;FOUND THE SIGN - NOW MUST BE A DECIMAL BR GETN50 ;IF NO DECIMAL CHAR, THEN IS INVALID GETNCH: CMP #'0,R0 ;CHECK FOR VALID DECIMAL CHAR BHI GETN50 ;IF LESS THAN '0' THEN INVALID CMP #'9,R0 BLO GETN50 ;IF GREATER THAN '9' THEN INVALID SUB #60,R0 ;CONVERT DECIMAL CHAR TO BINARY MOV #10.,R3 ;SET DECIMAL RADIX COUNTER GETNLP: ADD R2,R0 ;BUILD THE NUMBER BVS GETN95 ;OVERFLOW ERROR - BRANCH DEC R3 ;COUNT DOWN FOR MULTIPLY BY RADIX BGT GETNLP ;LOOP UNTIL RADIX EXHAUSTED MOV R0,R2 ;SAVE CURRENT VALUE JSR R5,GETCHR ;GET NEXT CHAR BR GETNBD ;IF NO MORE CHARS, THEN PROCEED OK CMP #BLANK,R0 ;IS THIS A BLANK? BLO GETNCH ;LOOP TO PROCESS NEXT POSSIBLE DIGIT JSR R5,SPAN ;SPAN POSTFIX BLANKS & CONTROL CHARS .WORD 0 .WORD BLANK BR GETNBD ;IF BUFFER NOW EMPTY, THEN PROCEED OK GETN50: JSR PC,CRLF JSR R5,PutList ;Invalid decimal integer error. .WORD GETND1 ;Alert the user to the error. BR GETN10 ;LOOP FOR RE-ENTRY OF THE NUMBER ;; GETNBD: MOV R2,R0 ;MOVE RESULT TO RETURN REGISTER TST R1 ;CHECK SIGN OF RESULT BEQ GETN80 ;POSITIVE, BRANCH NEG R0 ;2'S COMPLEMENT THE RESULT GETN80: CMP R0,2(R5) ;Check number against lower bound. BGE GETN90 ;BRANCH IF >=USER SPECIFIED LOWER LIMIT GETN85: JSR PC,CRLF JSR R5,PutList ;Alert the user to the error. .WORD GETND3 ;NUMBER TOO SMALL BR GETN10 ;LOOP FOR RE-ENTRY OF THE NUMBER ;; GETN90: CMP R0,4(R5) ;CHECK NUMBER AGAINST UPPER BOUND BLE GETNOK ;BRANCH IF <= USER SPECIFIED UPPER LIMIT GETN95: JSR PC,CRLF JSR R5,PutList ;Alert the user to the error. .WORD GETND2 ;NUMBER TOO LARGE BR GETN10 ;LOOP FOR RE-ENTRY OF THE NUMBER ;; GETNOK: TST (R5)+ ;INCR RETURN ADDRESS FOR SUCCESS GETNX: Add #6.,R5 ;Incr return address past parameters. MOV (SP)+,R1 ;RESTORE REGISTERS MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RTS R5 ;and return with number in Register 0. ;;*************************** ;; LOCAL STATIC STRINGS AND DESCRIPTORS ;; GETND1: .WORD GETNS1 GETND2: .WORD GETNS2 GETND3: .WORD GETNS3 GETND4: .WORD GETNS4 ;; GETNS1: .ASCII ' : Invalid decimal integer.' GETNS2: .ASCII ' : Number too large.' GETNS3: .ASCII ' : Number too small.' GETNS4: .ASCII ' ' .EVEN ;+ ;;********************************************************************** ;; GetChr - subroutine to access a character from the buffer is Register 4. ;; Removes the parity bit and all higher order bits. ;; Ignores all control chars. ;; Converts all LOWER CASE characters to UPPER CASE. ;; Returns the character right justified in register 0. ;; If the buffer becomes empty, the buffer empty exit is taken. ;; ;; Expects calls of the form: ;; JSR R5,GETCHR ;; BR (buffer empty handler) ;; ;; ;- GETCHR: JSR R5,GETBYTE ;GET A BYTE FROM THE BUFFER .WORD 0 ; the descriptor is in register 4. BR GETCHX ;BUFFER EMPTY DETECTED BIC #177600,R0 ;CLEAR PARITY AND HIGHER ORDER BITS CMP #BLANK,R0 ;IS THIS A CONTROL CHAR? BHI GETCHR ;YES, THEN GET ANOTHER CHAR FROM THE BUF CMP #141,R0 ;IS THIS A LOWER CASE "A"? BHI GETCHG ;NO, NOT LOWER CASE AT ALL CMP #172,R0 ;IS THIS A LOWER CASE "Z"? BLO GETCHG ;NO, IT IS ABOVE SUB #40,R0 ;YES, CONVERT LOWER CASE TO UPPER CASE GETCHG: TST (R5)+ ;INCR RETURN ADDRESS GETCHX: RTS R5 ;RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO GET A YES OR NO RESPONSE TO A QUESTION. ;; ONLY ANSWERS OF YES OR NO OR THEIR SHORTENED FORMS ARE ;; ALLOWED. PREFIX AND POSTFIX BLANKS ARE ALLOWED BUT THERE ;; MAY BE NOTHING ELSE INPUT. IF AN INVALID ANSWER IS ;; RECEIVED, THE USER WILL BE ALERTED TO ANSWER YES OR NO ;; AND THE QUESTION WILL BE RE-ISSUED. ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,GETYN ;; .WORD (PROMPT STATIC STRING DESCRIPTOR) ;; BR (BREAK REQUESTED) ;; BR (NO) ;; (PROCESS YES) ;; NOTE: IF THE USER PROMPT STATIC STRING DESCRIPTOR ADDRESS IS ZERO, ;; THEN THIS ADDRESS IS ASSUMED TO BE IN REGISTER 3. ;- GETYN:: Mov R4,-(SP) MOV R3,-(SP) ;STACK REGISTERS USED MOV R0,-(SP) MOV (R5)+,R0 ;GET PROMPT STATIC STRING DESC ADR BEQ GETYNLP ;IF ZERO, IS ALREALDY SELECTED IN REG 3 MOV R0,R3 ;ELSE PUT IT IN REG 3 GETYNLP: JSR R5,GETINPUT ;GET THE ANSWER .WORD 0 ;PROMPT SELECTED IN REG 3 BR GETYBREAK ;BREAK REQUESTED Mov R0,R4 ;Put the Buffer Desc in Reg 4. JSR R5,CMDCOPY ;COPY INPUT TO COMMAND STRING .WORD 0 ;Keyboard default buffer in R4. .WORD YESNOSTR ;COMMAND STRING DESCRIPTOR CMP R0,#5 ;WERE TOO MANY CHARS ENTERED? BLO GETYNMAT ;NO, TRY TO MATCH GETYNAGAIN: JSR PC,CRLF ;SKIP TO NEXT LINE JSR R5,PutList ;ALERT USER .WORD GETYNPROMPT ;"ANSWER YES OR NO." BR GETYNLP ;REQUEST ANSWER AGAIN ;; GETYNMAT: JSR R5,CMDMATCH ;TRY TO MATCH TO 'YES' OR 'NO' .WORD YESNOTABLE .WORD YESNOSTR BR GETYNAGAIN ;MATCH FAIL - ASK AGAIN TST (R5)+ ;SUCCESS - INCR PAST BREAK EXIT TST R0 ;CHECK IF YES OR NO BEQ GETYBREAK ;IF ZERO, THEN NO AND BRANCH TST (R5)+ ;YES, INCR RETURN ADDRESS ONCE MORE GETYBREAK: MOV (SP)+,R0 ;RESTORE REGISTERS USED MOV (SP)+,R3 Mov (SP)+,R4 RTS R5 ;RETURN ;;**************************** ;; YESNOSTR: .WORD GETY60 ;INPUT COMMAND STRING DESCRIPTOR .WORD GETY60 .WORD GETY70 ;END OF STRING .WORD GETY60 ;STATIC START OF STRING ;; GETYNPROMPT: .WORD GETY10 ;"ANSWER YES OR NO. " .WORD GETY50 ;; YESNOTABLE: .WORD GETYTB .WORD GETYTE .WORD 10 ;LENGTH OF A TABLE ENTRY ;; GETYTBEGIN: .WORD 1 ;MATCH LENGTH - ALLOW "Y" .WORD GETY20 .WORD GETY21 ;END OF STRING .WORD 1 ;VALUE RETURNED - NON-ZERO ;*; .WORD 1 ;MATCH LENGTH - ALLOW "N" .WORD GETY30 ;BEGINNING OF STRING .WORD GETY31 ;END OF STRING .WORD 0 ;VALUE RETURNED FOR NO - ZERO GETYTEND=.-2 ;;**************************** ;; GETY10: .ASCII 'ANSWER ' GETY20: .ASCII 'YES' GETY21=.-1 .ASCII ' OR ' GETY30: .ASCII 'NO' GETY31=.-1 .ASCII '.' GETY50: .ASCII ' ' GETY60: .BYTE 0,0,0,0 ;COMMAND STRING BUFFER GETY70: .BYTE 0 ;END OF INPUT STRING .EVEN ;;********************************************************************** .END