.TITLE ALVGet Alvin Console Input .PSECT ALVIN,GBL,CON .Ident /LVL51 / .MCALL $ALVIN,$LIST,$SPAN ;+ ;;********************************************************************** ;; 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 easy to ;; use form. Control is not returned to the user until the ;; input is 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. ;; 12-Jul-84 DVJ - Added a Null character to the end of input strings. ;; 19-Jul-85 DVJ - Now that RECEIV will allow subsequent requests to receive ;; into the same buffer without error, its not a good idea to ;; reset the default buffer descriptor. GETINPUT NO RESET. ;; 7-Oct-85 - So much for that last one. If it is not reset, junk can ;; remain in the buffer. It is now reset. ;; - If GetInput cannot receive from the keyboard, the break ;; exit will be taken. ;;********************************************************************** ;- $ALVIN ;+ ;;********************************************************************** ;; 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 never ;; included in the character count returned to the user. Although ;; the NULL STRING returns a count of zero, the string contains one ;; null character to avoid the dynamic end pointer from ever being ;; an address less than the beginning address of the string. ;; ;; 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. The Break exit will also ;; be taken if the Receive from the console fails. ;; ;; 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. ;; .Globl PutList .Globl Receive,AlvIdle .Globl BufEOL,Press,Span .Globl CRLF,BufLimit,CanLine,BrkOut,CmdNx0 ;- $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+UseDB+Reset ;Use the Default Buffer. .Word 0 ;(filler - using Default Buffer) Br GetIBad ; Loop until keyboard enabled. Mov R0,R2 ; Device Desc adr - Was this a valid device? Beq GetIBad ; No, branch, take an immediate break exit. ;; GETIN4: MOV (R2),R1 ;Get Input device logical status Mov BDAdr(R2),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,R1 ;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,R1 ;YES, WAS THE INPUT CANCELED? BEQ GETIN9 ;NO, BRANCH TO PROCESS THE INPUT JSR PC,CANLINE ;ACKNOWLEDGE INPUT CANCELLED BIT #BRKREQ,R1 ;WAS A BREAK REQUESTED? BEQ GETIN1 ;NO, LOOP TO ALLOW INPUT AGAIN GetIbad: JSR PC,BRKOUT ;ACKNOWLEDGE BREAK REQUESTED BR GETINX ;AND EXIT ;; GETIN9: BIT #BUFULL,R1 ;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 ;; .Globl Span,Putlist,CRLF ;; 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 ;Enter with Buffer Desc Adr in Reg 4. ;; BR (buffer empty handler) ;; ;; .Globl GetByte ;- 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. ;; .Globl Putlist,CRLF,CmdCopy,CmdMatch ;- 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