.TITLE ZTEXT .IDENT /V1.3/ ; ++ ; This is the Z-machine routines for text packing/unpacking. ; (c) 2000 by Johnny Billquist ; ; History: ; ; 00-07-19 BQT Initial coding started. ; Y1.0 00-08-26 21:00 BQT First release. ; V1.1 00-11-07 16:00 BQT Code is working. ; V1.2 05-08-01 16:00 BQT Small optimization done. ; V1.3 05-10-25 01:00 BQT Added ZSCII conversion functions, and ; uppercase of ZSCII table. ; -- .INCLUDE /ZMAC/ ; .PSECT DATA,D,RW ; DECCHR::.WORD 0 ; The correct decode pointer. DECPTR::.WORD 0 ; The current decode pointer. ASCPTR::.WORD ASCV1 ; The correct ASCII table. ; CTAB: .WORD 0 ; Current table. OTAB: .WORD 0 ; Old table. STATE: .WORD 0 ; State of translation. ; .PSECT TEXT,D,RO ; ; The ASCII tables for different versions... ; ASCV1:: .ASCII /abcdefghijklmnopqrstuvwxyz/ .ASCII /ABCDEFGHIJKLMNOPQRSTUVWXYZ/ .ASCII / 0123456789.,!?_#'"/<57>/\<-:()/ ASCV2:: .ASCII /abcdefghijklmnopqrstuvwxyz/ .ASCII /ABCDEFGHIJKLMNOPQRSTUVWXYZ/ .ASCII / 0123456789.,!?_#'"/<57>/\-:()/ ; .PSECT DATA,D,RW ; ; ZSCII to Latin-1 conversion for top half of 128 codes... ; ZSCII:: .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .BYTE 344,366,374,304,326,334 ; Diaresis .BYTE 337,273,253 ; sz, quotes. .BYTE 353,357,377,313,317 ; More diaresis .BYTE 341,351,355,363,372,375,301,311,315,323,332,335 ; Acute .BYTE 340,350,354,362,371,300,310,314,322,331 ; Grave .BYTE 342,352,356,364,373,302,312,316,324,333 ; Circumflex .BYTE 345,305 ; Aring .BYTE 370,330 ; Oslash .BYTE 343,361,365,303,321,325 ; Tilde .BYTE 346,306 ; AE .BYTE 347,307 ; ccedille .BYTE 376,360,336,320 ; Icelandic chars. .BYTE 243 ; Pound. .BYTE 366,326 ; oe .BYTE 241,277 ; ! ? .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; .PSECT CODE,I,RO ; ; CZ2L - Convert ZSCII to Latin-1 ; ; In: R1 - Character ; ; Out: R1 - Character ; CZ2L:: TSTB R1 ; ASCII char? BPL 10$ ; Yes. Same same. BIC #^C177,R1 ; No. Mask low bits. MOVB ZSCII(R1),R1 ; Take conversion. 10$: RETURN ; Done. ; ; CL2Z - Convert Latin-1 to ZSCII ; ; In: R1 - Character ; ; Out: R1 - Character ; CL2Z:: TSTB R1 ; ASCII char? BPL 100$ ; Yes. MOV R0,-(SP) ; No. Save registers MOV R2,-(SP) MOV #ZSCII,R0 ; Point at table. MOV #200,R2 ; Count. 10$: CMPB R1,(R0)+ ; Match? BEQ 20$ ; Yes. SOB R2,10$ ; No. Loop. 20$: MOV #400,R1 ; Match found. We now know offset. SUB R2,R1 ; And that offset is the answer. MOV (SP)+,R2 ; Restore registers MOV (SP)+,R0 100$: RETURN ; ; OBJTXT - Print the text for an object. ; ; In: R0 - Object number. ; OBJTXT:: MOV R0,-(SP) ; Save register. MOV R1,-(SP) INC R0 ; Point to the following object. CALL FNDOBJ ; Find object. SUB #2,R0 ; Point at object properties. .GETWB R0 ; Get address of properties. DEC R0 ; Point at name string. 10$: ADD #2,R0 ; Next word. .GETWB R0,R1 ; Get data. CALL PUTZW ; Print it. TST R1 ; End of data? BPL 10$ ; No. MOV (SP)+,R1 ; Restore registers. MOV (SP)+,R0 RETURN ; Done. ; ; NUMTXT - Print a number. ; ; In: R0 - Number. ; NUMTXT:: MOV R0,-(SP) ; Save registers. MOV R1,-(SP) MOV R2,-(SP) CLR R2 MOV R0,R1 ; Check number. BPL 10$ ; Negative? MOVB #'-,R1 ; Yes. Put in a '-' CALL PUTCHR MOV R0,R1 NEG R1 ; And change sign. 10$: CLR R0 ; Do a divide. DIV #10.,R0 ADD #'0,R1 ; Make remainder into ASCII form. MOVB R1,-(SP) ; And save digit. INC R2 ; Count digits. MOV R0,R1 ; Get result in R3. BNE 10$ ; And repeat until result is 0. 20$: MOVB (SP)+,R1 ; Now get all digits back. CALL PUTCHR ; And print them. SOB R2,20$ MOV (SP)+,R2 ; Restore registers. MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; ; PUTZW - Output a word with packed characters. ; ; In: R1 - Word. ; ; If the high bit is set on the word, the state machine shall ; be reset. ; PUTZW:: MOV R1,-(SP) ; Save registers. ASH #-10.,R1 ; Get first char. CALL PUTZB ; Output byte. MOV (SP),R1 ; Get word again. ASH #-5,R1 ; Next char. CALL PUTZB MOV (SP),R1 CALL PUTZB MOV (SP)+,R1 ; Restore register. BPL 10$ ; No reset. MOV DECCHR,DECPTR CLR OTAB CLR CTAB CLR STATE 10$: RETURN ; ; Output a single packed character. ; ; In: R1 - Character in low five bits. ; ; R1 is destroyed. ; PUTZB: BIC #^C37,R1 ; Mask away unwanted bits. CALLR @DECPTR ; Jump to correct decode function. ; ; DECCH1 - Decode one ZASCII character according to V1. ; ; In: R1 - Char in 5 low bits. ; ; R1 is destroyed. ; DECCH1:: TST STATE ; Flag set? BGT SPC1 ; Yes. First part. BLT SPC2 ; Yes. Low part. TST R1 ; No. Check this char. BEQ SPCHR ; Space. DEC R1 ; Newline? BEQ NLCHR ; Yup. DEC R1 ; Next set? BEQ NXSET DEC R1 ; Previous set? BEQ PRSET DEC R1 ; Next set lock? BEQ NXSETL DEC R1 ; Previous set lock? BEQ PRSETL DEC R1 ; A normal char? BNE NCHR ; Yes. ; ; Possibly a multichar... ; CMP CTAB,#52. ; Are we using A2? BNE NCHR ; No. MOV #1,STATE ; Yes. Set multibyte flag. RETURN ; ; DECCH2 - Decode one ZASCII character according to V2. ; ; In: R1 - Char in 5 low bits. ; ; R1 is destroyed. ; DECCH2:: TST STATE ; Flag set? BGT SPC1 ; Yes. First part. BLT SPC2 ; Yes. Low part. TST R1 ; No. Check this char. BEQ SPCHR ; Space. DEC R1 ; Abbreviation? BEQ 10$ ; Yup. DEC R1 ; Next set? BEQ NXSET DEC R1 ; Previous set? BEQ PRSET DEC R1 ; Next set lock? BEQ NXSETL DEC R1 ; Previous set lock? BEQ PRSETL DEC R1 ; A normal char? CMP R1,#1 ; Maybe... BGT NCHR ; Yes. ; ; Possibly a special char. It depends on if A2 is selected. ; CMP CTAB,#52. ; Are we using A2? BNE NCHR ; No. ; ; Now we now it is special. We have A2, and the character is 0 or 1. ; TST R1 ; Which character? BNE NLCHR ; 1 means newline. ; ; Character 0 means we have a multibyte. ; MOV #1,STATE ; Yes. Set flag. RETURN ; ; Abbreviation. ; 10$: MOV #ABBR1,DECPTR ; Setup pointer to abbreviations. RETURN ; And continue. ; ; Handle multibyte char. ; SPC1: ASH #5,R1 ; Shift up. BIS #100000,R1 ; Set flag. MOV R1,STATE ; First part of long byte. RETURN SPC2: BIS STATE,R1 ; Low part of long byte. CLR STATE ; Clear flag. BIC #^C377,R1 ; Clear unwanted bits. CALL PUTCHR ; Write char. MOV OTAB,CTAB RETURN ; ; A "normal" char. ; NCHR: ADD CTAB,R1 ADD ASCPTR,R1 MOVB (R1),R1 BR CHRDON ; ; Space. ; SPCHR: MOVB #' ,R1 BR CHRDON ; ; Newline. ; NLCHR: MOVB #13.,R1 CALL PUTCHR MOVB #10.,R1 BR CHRDON ; ; Next charset. ; NXSET: ADD #26.,CTAB CMP #78.,CTAB BNE 10$ CLR CTAB 10$: RETURN ; ; Prev charset. ; PRSET: SUB #26.,CTAB BPL 10$ MOV #52.,CTAB 10$: RETURN ; ; Next charset lock. ; NXSETL: ADD #26.,OTAB CMP #72.,OTAB BNE 10$ CLR OTAB 10$: MOV OTAB,CTAB RETURN ; ; Prev. charset lock. ; PRSETL: SUB #26.,OTAB BPL 10$ MOV #52.,OTAB 10$: MOV OTAB,CTAB RETURN ; ; Done with this char. ; CHRDON: CALL PUTCHR ; Output char. MOV OTAB,CTAB ; Reset char table. RETURN ; Done. ; ; DECCH3 - Decode one ZASCII character according to V3. ; ; In: R1 - Char in low 5 bits. ; ; R1 destroyed. ; DECCH3:: TST STATE ; Flag set? BGT SPC1 ; Yes. First part. BLT SPC2 ; Yes. Low part. TST R1 ; No. Check this char. BEQ SPCHR ; Space. DEC R1 ; Abbreviation? BEQ 10$ ; Yup. DEC R1 BEQ 20$ ; Yup. DEC R1 BEQ 30$ ; Yup. DEC R1 ; Next set? BEQ NXSET DEC R1 ; Previous set? BEQ PRSET DEC R1 ; A normal char? CMP R1,#1 ; Maybe... BGT NCHR ; Yes. ; ; Possibly a special char. It depends on if A2 is selected. ; CMP CTAB,#52. ; Are we using A2? BNE NCHR ; No. ; ; Now we now it is special. We have A2, and the character is 0 or 1. ; TST R1 ; Which character? BNE NLCHR ; 1 means newline. ; ; Character 0 means we have a multibyte. ; MOV #1,STATE ; Yes. Set flag. RETURN ; ; Abbreviation. ; 10$: MOV #ABBR1,DECPTR ; Setup pointer to abbreviations. RETURN 20$: MOV #ABBR2,DECPTR RETURN 30$: MOV #ABBR3,DECPTR RETURN ; ; Handle abbreviations. ; ABBR3: MOV R0,-(SP) ; Save registers. MOV #128.,R0 BR ABBREV ABBR2: MOV R0,-(SP) ; Save registers. MOV #64.,R0 BR ABBREV ABBR1: MOV R0,-(SP) ; Save registers. CLR R0 ABBREV: ASL R1 ; Get abbreviation number * 2. ADD R1,R0 ; Add table offset. ADD ZABBR,R0 ; Add offset to abbreviation table. .GETWB R0 ; Get word at word address. MOV DECCHR,DECPTR ; Reset state machine. CLR CTAB CLR OTAB 10$: .GETWW R0,R1 ; Copy data. CALL PUTZW ; Output data. INC R0 ; And bump address. TST R1 ; End of string? BPL 10$ ; No. Go on. MOV (SP)+,R0 ; Restore register. RETURN ; And now continue. ; .END