; SWRT - WRITE STRING ON CONSOLE
; USE HERE BECAUSE NORMAL FORTRAN WRITES DO TOO MUCH FORMAT CONTROL
; AND WE JUST WANT A DUMP OF THE CHARACTERS.
; V2: STOP WRITING WHERE A NULL IS SEEN...
; GLENN C. EVERHART 1984.
; COPYRIGHT (C) GLENN AND MARY EVERHART 1984
; ALL RIGHTS RESERVED
;
; CALL:
;	CALL SWRT(ADDR,CNT)
; WHERE
; ADDR IS START OF A STRING, AND
; CNT IS THE NUMBER OF BYTES IN THE STRING TO WRITE OUT.

DGROUP	GROUP DATA
DATA	SEGMENT PUBLIC 'DATA'
	ASSUME DS:DGROUP
LCLLEN	DW	0	;LOCAL COPY OF LENGTH
LCLMOD  DW      0       ; 0 FOR NORMAL CHAR MODE, 1 FOR IBM BIOS MODE
CURATR  DB      07
        DB      07
CURROW  DB      0	;ROW NUMBER. 0=TOP
CURCOL  DB      0       ;COL NUMBER, 0=LEFT
DATA ENDS
CODE	SEGMENT 'CODE'
	ASSUME CS:CODE,SS:DGROUP
PUBLIC SWRT
PUBLIC SWSET
PUBLIC ATRSET
PUBLIC POSSET
SWRT	PROC FAR	;MAKE PROCEDURE CALLABLE FROM ANYWHERE
;NORMAL MS FORTRAN INIT
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
	PUSH	SI
	PUSH	DI	;FORT 4.0
	MOV	BX,8[BP]
	MOV	ES,BX
	MOV	BX,6[BP]
;	LES	BX,6[BP]	;ES,BX=LENGTH OF STRING
	MOV	AX,ES:[BX]	;GET LENGTH INTO AX NOW
	CMP	AX,80		;ENSURE LEGALITY
	JL	LENOK
	MOV	AX,80		;USE 80 CHARS IF USER SPEC'D TOO MANY
LENOK:
	MOV	DS:LCLLEN,AX	;SAVE COPY LOCALLY TOO
	MOV	BX,12[BP]
	MOV	ES,BX
	MOV	BX,10[BP]
;	LES	BX,10[BP]	;NOW GET ADDRESS OF STRING
; MUST NOW DUMP STRING TO CONSOLE A CHAR AT A TIME.
;(SINCE STRINGS CAN CONTAIN $ SIGNS)
WSTRG:
	MOV	AX,LCLMOD	;GET LOCAL MODE CHARACTER...
	CMP	AX,1		;SEE IF IBM BIOS MODE
	JZ	IBMMOD		;IF SO SKIP TO DO IT THE IBM BIOS WAY (INT 10)
	XOR	AX,AX		;ZERO A REG
	MOV	AH,6		;DOS FUNCTION 2=CONSOLE OUT
	MOV	DL,ES:[BX]	;GET CHARACTER
; CHECK FOR NULL CHARACTER SO THAT LONG BUT NULL TERMINATED STRINGS DON'T ALL
; GET SHIPPED OVER.
	OR	DL,DL		;SEE IF NULL
	JZ	ZERXT		;IF SO, LEAVE LOOP EARLY
	INC	BX		;POINT AT NEXT
	INT	21H		;CALL DOS TO EMIT THE CHARACTER
	NOP
	NOP
	JMP	WSTCMN		;GO TO COMMON ADDRESS
IBMMOD:
	PUSH	BP
	MOV	AH,9		;SET TO EMIT ATT/CHAR
	MOV	CX,1		;1 CHAR AT A TIME
	MOV	AL,ES:[BX]	;GET CHARACTER TO EMIT
	INC	BX		;POINT AT NEXT ONE
	PUSH	BX		;NEED BX FOR LOOP CONTROL OUTSIDE SO SAVE IT
	MOV	BL,CURATR	;ATTRIBUTE BYTE TO USE...
	MOV	BH,0		;1ST PAGE
	OR	AL,AL		;(TEST NULL TERMINATOR)
	JZ	IBMZX
	INT	10H		;EMIT THE CHAR
	NOP
; HAVE TO ADVANCE CURSOR BY HAND HERE, SO DO SO.
	CMP	AL,13		;SEE IF THIS WAS A CARRIAGE RETURN AND
				;AVOID UPDATE OF POS IF SO.
	JZ	WASCR
	MOV	AH,3
	INT	10H	;READ CURSOR
	INC	DL	;BUMP COLUMN BY ONE
	MOV	AH,2
	INT	10H	;AND SET CURSOR TO NEW LOCATION
	JMP	CRMMM
WASCR:
;RETURN CURSOR TO BEGINNING OF LINE FOR CLEARING
;NOT MUCH OTHER USE FOR CARRIAGE RETURN BUT THAT...
	MOV	AH,3
	INT	10H
	MOV	DL,0	;ZERO THE COLUMN
	MOV	AH,2
	INT	10H	;STORE IT VIA BIOS
CRMMM:
	POP	BX		;RESTORE BX TO ORIGINAL USE...
	POP	BP
	JMP	WSTCMN
IBMZX:
;NEED THIS ENTRY TO POP JUNK OFF STACK PRIOR TO RETURN
;OUT OF LOOP.
	POP	BX
	POP	BP
	JMP	ZERXT
;
WSTCMN:
	DEC	DS:LCLLEN		;COUNT DOWN LENGTH
; (WE DON'T USE A REG SINCE DOS MIGHT EAT IT...)
	JG	WSTRG		;GO DO  ANOTHER IF COUNT IS STILL POSITIVE
ZERXT:
;HERE DONE WITH THE OUTPUT --  CLEAN UP AND LEAVE.
;
;NOW PUT ALL THE FRAMES ETC BACK AND RETURN TO CALLER
	POP	DI
	POP	SI	; FORT V4.0
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
;(ALSO FIXES UP SP)
	RET	08H		;RETURN, POP 8 BYTES
; NOTE: MAY NEED TO BE AN LRET, NOT A RET.
	SWRT	ENDP
SWSET   PROC    FAR
;CALL WITH 1 ARGUMENT, VIZ. THE SETTING FOR IBM BIOS MODE, 0 OR 1.
; 0=PCDOS, 1=BIOS
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
	PUSH	SI	;
	PUSH	DI
; REAL WORK NOW HERE...
	LES	BX,DWORD PTR [BP+6] ;ES:BX = ADDR 1ST PARAM
	MOV	AX,ES:[BX]	;GET THE ARGUMENT
	MOV	LCLMOD,AX	;SAVE IT IN LOCAL DATA...
	OR	AX,AX		;SEE IF IT WAS 0
	JZ	SWSXX
	MOV	AH,5		;ELSE FORCE SELECT PAGE 0
	MOV	AL,0		;PAGE #
	INT 10H
SWSXX:
	POP	DI
	POP	SI
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
        RET     04H             ;RETURN, POP 4 BYTES
        SWSET   ENDP
ATRSET  PROC    FAR
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
; REAL WORK NOW HERE...
	LES	BX,DWORD PTR [BP+6] ;ES:BX = ADDR 1ST PARAM
	MOV	AX,ES:[BX]	;GET THE ARGUMENT
; SAVE LOW BYTE OF INT ARGUMENT
; BECOMES IBM MODE ATTRIBUTE...
	MOV	CURATR,AL	;SAVE IT IN LOCAL DATA...
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
        RET     04H             ;RETURN, POP 4 BYTES
        ATRSET  ENDP
POSSET  PROC    FAR
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
	PUSH	SI
	PUSH	DI
; REAL WORK NOW HERE...
	LES	BX,DWORD PTR [BP+10] ;ES:BX = ADDR 1ST PARAM
	MOV	AX,ES:[BX]	;GET THE ARGUMENT
	DEC	AX
	MOV	CURROW,AL	;SAVE IT IN LOCAL DATA...
; SAVE CURSOR LOCS AND SET UP CURSOR IN IBM MODE
	LES	BX,DWORD PTR [BP+6]  ;GET 1ST ARG
	MOV	AX,ES:[BX]
	DEC	AX		;SUBTRACT 1 TO ADJUST...
	MOV	CURCOL,AL	;SAVE COL
; CALL POSSET(IROW,ICOL)
	MOV	DX,LCLMOD
	OR	DX,DX		;SEE IF 0 (ANSI) MODE
	JZ	POSXX
	PUSH	BP
	MOV	DH,CURROW
	MOV	DL,CURCOL
	MOV	AH,2		;SET CURSOR POSITION
	XOR	BX,BX		;FORCE BH=0 FOR PAGE 0
	INT 10H			;SET BIOS CURSOR LOC IF IN IBM MODE
	NOP
	POP	BP
POSXX:
	POP	DI
	POP	SI
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
        RET     08H             ;RETURN, POP 4 BYTES
        POSSET  ENDP
PUBLIC CLRL
PUBLIC CLRSCR
CLRL    PROC    FAR
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
	PUSH	SI
	PUSH	DI
; CLEAR ALL OF CURRENT LINE
; FROM CURRENT LOCATION TO END
	MOV	DX,LCLMOD
	OR	DX,DX		;SEE IF 0 (ANSI) MODE
	JZ	CLRLX
	PUSH	BP
;FIRST READ CURRENT CURSOR
	MOV	AH,3
	MOV	BH,0	;GET CURSOR LOCATION
;(WRITING COULD HAVE CHANGED IT SO CURROW NOT USEFUL...)
	INT	10H
	NOP
;DH,DL=ROW/COL
	MOV	CL,80		;80 CHARS MAX
	SUB	CL,DL		;GET ROW NUMBER INTO ACCUM
	MOV	CH,0		;GUARANTEE LEGALITY...
; THIS GETS COUNT OF SPACES TO WRITE INTO CX REG
	MOV	AH,9		;SET TO WRITE
	MOV	AL,20H	;ASCII SPACE
	MOV	BL,CURATR
	INT	10H		; WRITE THE SPACES (CLR LINE)
	NOP
	POP	BP
CLRLX:
	POP	DI
	POP	SI
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
        RET
        CLRL    ENDP
CLRSCR  PROC    FAR
	PUSH	BP	;SAVE FRAME POINTER ON STACK
	MOV	BP,SP	;POINT BASE POINTER AT NEW FRAME (STACK PTR)
	PUSH	SI
	PUSH	DI
	MOV	DX,LCLMOD
	OR	DX,DX		;SEE IF 0 (ANSI) MODE
	JZ	CLRSX	;ONLY DO STUFF IF IBM MODE
	PUSH	BP
	MOV	AH,2
	XOR	DX,DX		;GO TO ORIGIN
	XOR	BX,BX
	INT	10H		;VIA BIOS
	NOP
	MOV	AH,9		;WRITE LOTS SPACES
	MOV	CX,2000		;2000 = 80 TIMES 25
	MOV	AL,20H		;20H=ASCII SPACE
	MOV	BL,CURATR	;ATTRIBUTE CODE...
	INT	10H		;ZAP IT OUT
	NOP
	POP	BP
CLRSX:
	POP	DI
	POP	SI
	MOV	SP,BP		;BACK OUT OVER THIS FRAME INTO LAST
	POP	BP		;BY GETTING BACK OLD BP
        RET
        CLRSCR  ENDP
	CODE	ENDS
END
