SUBTTL STRING FUNCTIONS PAGE + ;OUTPUT A ZSTR, BLOCK-POINTER IN AX, BYTE-POINTER IN BX ;RETURN UPDATED POINTER PUBLIC PUTSTR PUTSTR PROC PUSH SI ;SAVE PUSH CX ;SAVE PUSH DX ;SAVE PUSH DI ;SAVE PUSH BP ;SAVE SUB DX,DX ;TEMP CS STARTS AT 0 SUB DI,DI ;PERM CS STARTS AT 0 PTS1$: CALL GETWRD ;GET NEXT STRING WORD MOV SI,CX PUSH AX ;SAVE POINTER & COPY OF STRING WORD PUSH BX PUSH SI MOV CX,3 ;3 BYTES IN WORD PTS2$: PUSH SI ;SAVE CURRENT BYTE (IN LOW-ORDER POSITION) MOV BP,CX ;SHIFT TO NEXT BYTE MOV CL,5 SAR SI,CL MOV CX,BP LOOP PTS2$ ;LOOP UNTIL DONE MOV CX,3 ;RETRIEVE THE 3 BYTES PTS3$: POP SI ;GET NEXT BYTE AND SI,1FH ;CLEAR UNWANTED BITS CMP DX,0 ;IN WORD MODE? JGE PTS4$ ;NO {WAS BPL, CHECK} SAL SI,1 ;YES, CALCULATE WORD OFFSET ADD SI,WRDTAB ;POINT INTO WORD TABLE ADD SI,WRDOFF ;USING PROPER 32-WORD BLOCK GTAWRD A,[SI] ;POINT TO WORD STRING CALL BSPLIT ; SPLIT IT CALL PUTSTR ;AND PRINT IT JMP PTS15$ ;CONT. WHERE WE LEFT OFF WITH TEMP CS RESET PTS4$: CMP DX,3 ;CS 3 SELECTED (ASCII MODE)? JL PTS6$ ;NO, NORMAL CS JNE PTS5$ ;NO, BUT WE ARE IN ASCII MODE XCHG DL,DH ;SHIFT SOME BITS HIGH TO MAKE NUMBER LARGE OR DX,SI ;SAVE HIGH-ORDER ASCII BITS HERE JMP PTS16$ ;GO GET NEXT BYTE PTS5$: AND DX,3 ;EXTRACT PREVIOUSLY SAVED HIGH-ORDER BITS MOV BP,CX ;POSITION THEM MOV CL,5 SAL DX,CL MOV CX,BP OR DX,SI ;OR IN LOW-ORDER BITS MOV AX,DX JMP PTS14$ ;GO PRINT THE CHARACTER PTS6$: CMP SI,6 ;SPECIAL CODE? JL PTS9$ ;YES, SPACE, WORD, OR SHIFT CMP DX,2 ;MIGHT ALSO BE SPECIAL IF IN CS 2 JNE PTS8$ ;BUT WE'RE NOT CMP SI,7 ;CRLF? JE PTS7$ ;YES JG PTS8$ ;NO, NOT ASCII MODE, EITHER? INC DX ;YES IT IS, SWITCH TO ASCII MODE JMP PTS16$ ;AND GO GET NEXT BYTE PTS7$: CALL NEWLIN ;CRLF REQUESTED, DO A NEWLINE JMP PTS15$ PTS8$: MOV AX,DX ;NORMAL CHARACTER, GET CS MOV BP,26 ;CALCULATE OFFSET FOR THIS CS MUL BP ADD AX,SI ;ADD IN CHARACTER OFFSET (+6) SUB AX,6 ;CHARACTER OFFSET MOV BX,OFFSET ZCHRS ;GET THE CHARACTER FROM CONVERSION VECTOR XLAT ZCHRS JMP PTS14$ ;GO PRINT IT PTS9$: CMP SI,0 ;IS IT A SPACE? JNE PTS10$ ;NO MOV AX," " ;YES, GO PRINT A SPACE JMP PTS14$ PTS10$: CMP SI,3 ;IS IT A WORD? JG PTS11$ ;NO, MUST BE A SHIFT OR DX,8000H ;SWITCH TO WORD MODE FOR NEXT BYTE DEC SI ;CALCULATE WORD-TABLE BLOCK OFFSET MOV BP,CX ;64 BYTES IN A BLOCK MOV CL,6 SHL SI,CL MOV CX,BP MOV WRDOFF,SI ;SAVE IT AND LOOP JMP PTS16$ PTS11$: SUB SI,3 ;CALCULATE NEW CS CMP DX,0 ;TEMPORARY SHIFT (FROM CS 0)? JNE PTS12$ ;NO MOV DX,SI ;YES, JUST SAVE NEW TEMP CS JMP PTS16$ PTS12$: CMP SI,DX ;IS THIS THE CURRENT CS? JE PTS13$ ;YES, DO A PERM SHIFT TO IT SUB DX,DX ;OTHERWISE, PERM SHIFT TO CS 0 PTS13$: MOV DI,DX ;TEMP & PERM CS'S ARE SAME NOW JMP PTS16$ PTS3A$: JMP PTS3$ ;DUMMY FOR NON-SHORT LOOP PTS14$: CALL PUTCHR ;PRINT THE CHARACTER PTS15$: MOV DX,DI ;RESET TEMP CS TO PERM CS PTS16$: LOOP PTS3A$ ;NEXT BYTE POP SI ;RESTORE POINTERS & ORIGINAL STRING WORD POP BX POP AX CMP SI,0 ;END-OF-STRING? JL PTS1A$ ;YES, CLEAN UP & RETURN UPDATED POINTER JMP PTS1$ ;NO, GET NEXT WORD PTS1A$: POP BP ;RESTORES POP DI POP DX POP CX POP SI RET PUTSTR ENDP ;GIVEN AN ASCII CHARACTER IN AX, RETURN THE CHARACTER SET # IN AX PUBLIC CHRCS CHRCS PROC CMP AX,0 ;IS THIS A NULL? JNE CCS1$ ;NO MOV AX,3 ;YES, RETURN DUMMY CS NUMBER RET CCS1$: PUSH BX ;SAVE MOV BX,OFFSET ZCHRS ;POINT TO CONVERSION VECTOR CCS2$: INC BX ;FOUND THE CHARACTER? CMP AL,[BX-1] JE CCS3$ ;YES CMP BYTE PTR [BX],0 ;NO, END OF STRING? JNE CCS2$ ;NO, CONTINUE LOOP MOV AX,2 ;YES, CALL IT CS 2 JMP CCS5$ CCS3$: SUB BX,OFFSET ZCHRS ;FIND CHARACTER POSITION SUB AX,AX ;START WITH CS 0 CCS4$: SUB BX,26 ;EVERY 26 CHARACTERS IS A NEW CS JLE CCS5$ ;DONE INC AX ;INCREMENT CS # & CONTINUE LOOP JMP CCS4$ CCS5$: POP BX RET CHRCS ENDP ;GIVEN AN ASCII CHARACTER IN AX, RETURN ZSTR BYTE VALUE IN AX PUBLIC CHRBYT CHRBYT PROC PUSH BX ;SAVE MOV BX,OFFSET ZCHRS ;POINT TO CHARACTER CONVERSION TABLE CHB1$: INC BX ;FOUND THE CHARACTER? CMP AL,[BX-1] JE CHB2$ ;YES CMP BYTE PTR [BX],0 ;NO, END OF STRING? JNE CHB1$ ;NO, CONTINUE LOOP SUB AX,AX ;YES, RETURN ZERO FOR FAILURE JMP CHB4$ CHB2$: SUB BX,OFFSET ZCHRS-5 ;ADJUST POINTER SO FIRST CHARACTER IS 6 MOV AX,BX CHB3$: CMP AX,32 ;SUBTRACT MULTIPLES OF 26 UNTIL BASE CODE JL CHB4$ SUB AX,26 JMP CHB3$ CHB4$: POP BX ;RESTORE RET CHRBYT ENDP ;CONVERT UP TO 9 ASCIZ CHARS POINTED TO BY DS:AX ;TO A 3-WORD ZSTR RETURNED IN AX & BX & CX PUBLIC ZWORD ZWORD PROC PUSH SI ;SAVES PUSH DX PUSH DI PUSH BP MOV SI,AX ;CHARACTER STRING POINTER SUB DI,DI ;CS STARTS AT 0 MOV CX,9 ;MAKE 9 ZSTR BYTES ZWD1$: INC SI ;GET NEXT CHARACTER MOV BL,[SI-1] CMP BL,0 JNE ZWD3$ ;NOT END-OF-STRING MOV AX,OFFSET PADCHR;AT END-OF-STRING, PAD WITH PAD CHARACTER ZWD2$: PUSH AX ;SAVE A PAD BYTE LOOP ZWD2$ ;LOOP UNTIL DONE JMP ZWD6$ ;THEN GO FORM ZWORD ZWD3$: MOV AX,BX CALL CHRCS ;FIND THE CS NUMBER FOR THIS CHAR CMP AX,0 ;CS 0? JE ZWD4$ ;YES ADD AX,3 ;NO, CALCULATE TEMP SHIFT BYTE PUSH AX ;SAVE THE SHIFT BYTE DEC CX ;REDUCE BYTE COUNT JE ZWD6$ ;DONE ZWD4$: MOV AX,BX ;FIND THE PROPER BYTE VALUE FOR THIS CHAR CALL CHRBYT CMP AX,0 ;IN NORMAL CS'S? JNE ZWD5$ ;YES MOV AX,6 ;NO, USE ASCII SHIFT PUSH AX DEC CX ;DONE YET? JE ZWD6$ ;YES MOV AX,BX ;NO, SAVE HIGH-ORDER ASCII BITS MOV BP,CX MOV CL,5 SAR AX,CL MOV CX,BP PUSH AX DEC CX ;DONE YET? JE ZWD6$ ;YES AND BX,1FH ;NO, SAVE LOW-ORDER ASCII BITS MOV AX,BX ZWD5$: PUSH AX ;SAVE THIS BYTE LOOP ZWD1$ ;LOOP UNTIL ZWORD FULL ZWD6$: MOV BP,SP ;BUILD ZWORD WORDS FROM 6 SAVED BYTES MOV AX,[BP+16] ; (A0) MORE ON STACK NOW MOV CL,5 SHL AX,CL OR AX,[BP+14] ; (A0) SHL AX,CL OR AX,[BP+12] ; (A0) MOV BX,[BP+10] ; (A0) SHL BX,CL OR BX,[BP+8] ; (A0) SHL BX,CL OR BX,[BP+6] ; (A0) MOV DX,[BP+4] ; (A0) GET LAST WORD INTO DX SHL DX,CL ; (A0) OR DX,[BP+2] ; (A0) SHL DX,CL ; (A0) OR DX,[BP] ; (A0) OR DX,8000H ;SET END-OF-STRING BIT IN SECOND WORD MOV CX,DX ; (A0) SAVE THIRD WORD IN REG ADD SP,18 ; (A0) FLUSH STACK POP BP ;RESTORES POP DI POP DX POP SI RET ZWORD ENDP SUBTTL TERMINAL I/O PAGE + ; ; QUEUE CHARACTER IN AX FOR OUTPUT ; PUBLIC PUTCHR,PTC$,PTC0,PTC00,PTC0A,PTC0B,PTC0C,PTC0B PUBLIC PTC0C,PTC0C1,PTC0D,PTC0E,PTC0F,PTC0G,PTC1,PTC2 PUBLIC PTC3,PTC4,PTC4A,PTC5,PTC6,PTC7,PTC8 PUTCHR PROC TEST BUFBIT,1 ; (A0) ARE WE BUFFERING OUTPUT JNZ PTC0 ; ....YES CMP RDIR,1 ; (A0) SEND CHAR TO A TABLE? JZ PTC$ ; ....YES ; {CASE} DIRECT OUTPUT JMP MTTYO ; ....NO. OUTPUT TO THE CONSOLE DEVICE ; {CASE} OUTPUT TO A TABLE PTC$: PUSH BX ; (A0) USE AS A PTR MOV BX,RTABLE2 ; (A0) GET OFFSET INTO TABLE MOV ES:[BX],AL ; (A0) "PUTB" THE CHAR INC RTABLE2 ; (A0) INCREMENT THE OFFSET INC RDIROUT ; (A0) INC THE COUNT OF CHAR'S OUTPUT POP BX RET ; {CASE} BUFFERED OUTPUT PTC0: PUSH BP MOV BP,CHRPTR ;GET THE CURRENT POSITION IN THE BUFFER CMP BP,ENDBUF ;ARE WE AT THE END OF THE BUFFER? ; JNE PTC7 ; (A13) ....NO JNE PTC00 ; (A13) ....NO JMP PTC0G ; (A13) ....YES ; WE'RE NOT AT THE END OF THE BUFFER PTC00: CMP CHRCNT,0 ; (A13) HAVE WE FILLED THE OUTPUT LINE? JE PTC0A ; (A13) ....YES JMP PTC7 ; (A13) ....NO ; THE OUTPUT LINE IS FULL, BUT THE BUFFER ISN'T PTC0A: PUSH AX ; (A13) SAVE THE CHARACTER PUSH BX ; (A13) AND SOME REGISTERS PUSH SI ; LOOK BACK THROUGH THE OUTPUT BUFFER FOR A SPACE CHARACTER ; IN ORDER TO BREAK UP THE LINE AT THE LAST COMPLETE WORD MOV BX,CHRPTR ; (A13) START AT CHRPTR MOV SI,OFFSET OUTBUF ; (A13) UNTIL REACHING THE BUFFER HEAD PTC0B: DEC BX ; (A13) BACKUP CMP BYTE PTR [BX]," " ; (A13) HAVE WE FOUND A SPACE CHAR? JE PTC0D ; (A13) ....YES CMP BX,SI ; (A13) NO. ARE WE AT THE BUFFER HEAD? JNE PTC0B ; (A13) ....NO. KEEP TRYING ; PRINT THE BUFFER FOLLOWED BY A CRLF. PTC0C: MOV BYTE PTR [BX],0 ; (A13) WE WANT A CRLF PRINT OUTBUF ; (A13) PRINT THE BUFFER MOV CHRPTR,SI ; (A13) RESET TO THE BUFFER START MOV CHRCNT,BUFLEN ; (A13) RESET THE OUTPUT LINE COUNTER MOV BP,SP ; (A13) CMP BYTE PTR 4 [BP]," " ; (A13) IS THE NEW CHARACTER A SPACE? JNE PTC0C1 ; (A13) ....NO. LEAVE IT ALONE MOV WORD PTR 4 [BP],0 ; (A13) ....YES. MAKE IT A NUL PTC0C1: JMP PTC6 ; WE FOUND A SPACE IN THE OUTPUT BUFFER PTC0D: CMP BX,SI ; (A13) WAS IT AT THE BUFFER HEAD? JE PTC0C ; (A13) ....YES MOV BYTE PTR [BX],0 ; (A13) ....NO. MAKE IT A NUL ; PRINT THE BUFFER PRINT OUTBUF ; (A13) ; INITIALIZE REGISTERS FOR THE BLOCK MOVE MOV AX,CHRPTR ; (A13) POINT TO THE NEXT POSITION INC BX ; (A13) AND THE 1ST NON OUTPUTED CHAR ; MOVE THE CHARACTERS THAT HAVEN'T BEEN OUTPUTED TO THE BEGINNING ; OF THE OUTPUT BUFFER PTC0E: CMP BX,AX ; (A13) DONE? JE PTC0F ; (A13) ....YES MOV BP,AX ; (A13) SAVE AX MOV AL,[BX] ; (A13) GET THE CURRENT CHARACTER MOV [SI],AL ; (A13) MOVE IT MOV AX,BP ; (A13) RESTORE AX INC BX ; (A13) NEXT SOURCE INC SI ; (A13) NEXT DESTINATION JMP PTC0E ; (A13) LOOP UNTIL WE'VE MOVED THEM ALL PTC0F: MOV AX,ENDBUF ; (A13) COMPUTE CHARACTERS REMAINING SUB AX,SI ; (A13) IN THE OUTPUT LINE MOV CHRCNT,AX ; (A13) AND SAVE IT JMP PTC5 ; (A13) ; {SUBCASE} THE OUTPUT BUFFER IS FULL PTC0G: PUSH AX ;SAVE THE CHARACTER PUSH BX ; AND SOME REGISTERS PUSH SI ; LOOK BACK THROUGH THE OUTPUT BUFFER FOR A SPACE CHARACTER ; IN ORDER TO BREAK UP THE LINE AT THE LAST COMPLETE WORD MOV BX,ENDBUF ;START AT ENDBUF MOV SI,OFFSET OUTBUF ;UNTIL REACHING THE BUFFER HEAD PTC1: DEC BX ;BACKUP CMP BYTE PTR [BX]," " ;HAVE WE FOUND A SPACE CHAR? JE PTC3 ;....YES CMP BX,SI ;....NO. ARE WE AT THE BUFFER HEAD? JNE PTC1 ;....NO. KEEP TRYING ; SOMEHOW WE REACHED THE BUFFER HEAD WITHOUT FINDING A SINGLE SPACE ; CHARACTER IN THE ENTIRE BUFFER. ALL WE CAN DO IS TO ASSUME THAT ; THE ENTIRE STRING IS TO BE PRINTED FOLLOWED BY A CRLF. PTC2: PRINT OUTBUF ;PRINT THE BUFFER FOLLOWED BY CRLF MOV CHRPTR,SI ;RESET TO THE START OF THE BUFFER MOV BP,SP CMP BYTE PTR 4 [BP]," " ;LOOK AT THE CHARACTER JUST RECEIVED JNE PTC6 ;IF IT'S NOT A SPACE, LEAVE IT ALONE MOV WORD PTR 4 [BP],0 ; ELSE, MAKE IT A NUL JMP PTC6 ; WE FOUND A SPACE IN THE OUTPUT BUFFER PTC3: CMP BX,SI ;WAS IT AT THE BUFFER HEAD? JE PTC2 ;....YES MOV BYTE PTR [BX],0 ;....NO. MAKE IT A NUL ; PRINT THE BUFFER PRINT OUTBUF ; INITIALIZE REGISTERS FOR THE BLOCK MOVE MOV AX,ENDBUF ;POINT TO THE END OF THE BUFFER INC BX ;POINT TO THE 1ST NON OUTPUTED CHAR ; MOVE THE CHARACTERS THAT HAVEN'T BEEN OUTPUTED TO THE BEGINNING ; OF THE OUTPUT BUFFER PTC4: CMP BX,AX ;HAVE WE REACHED THE END OF THE BUFFER? JE PTC4A ;....YES MOV BP,AX ;SAVE AX MOV AL,[BX] ;GET THE CURRENT CHARACTER MOV [SI],AL ;MOVE IT MOV AX,BP ;RESTORE AX INC BX ;NEXT SOURCE INC SI ;NEXT DESTINATION JMP PTC4 ;LOOP UNTIL WE'VE MOVED THEM ALL PTC4A: MOV AX,ENDBUF ; (A13) COMPUTE CHARACTERS REMAINING SUB AX,SI ; (A13) IN THE OUTPUT LINE MOV CHRCNT,AX ; (A13) AND SAVE IT PTC5: MOV CHRPTR,SI ;NEXT CHARACTER INPUT POSITION PTC6: POP SI ;RECOVER THOSE REGISTERS POP BX POP AX ; AND THE CURRENT CHARACTER CMP AX,0 ;EOL? JE PTC8 ;....YES. IGNORE IT PTC7: MOV BP,CHRPTR ;GET THE INPUT POSITION MOV [BP],AL ;STORE THE CHARACTER INC CHRPTR ;NEXT POSITION DEC CHRCNT ; (A13) AND ONE LESS IN OUTPUT LINE PTC8: POP BP RET PUTCHR ENDP ;GO TO NEW LINE, OUTPUTTING CURRENT BUFFER NEWLIN PROC PUSH BX ;SAVE MOV BX,CHRPTR ;END LINE AT CURRENT POINT MOV BYTE PTR [BX],0 MOV CHRPTR,OFFSET OUTBUF ;RESET CHARACTER POINTER MOV CHRCNT,BUFLEN ; (A13) RESET THE OUTPUT LINE COUNTER POP BX ;RESTORE REGISTER PRINT OUTBUF ; AND OUTPUT LINE RET NEWLIN ENDP