%TITLE  "Print Screen - <Print Scrn> enhancement TSR"

DISPLAY	"Link with /t option to create a .COM file"

;-----------------------------------------------------------------------;
; PRNTSCRN.ASM  - a TSR to enhance the print screen key                 ;
; 3-18-90  Robert Mashlan						;
;									;
;                                                               	;
; o Prefixes IBM characters with ASCII codes below 32 with the		;
;   a printer control sequence.						;
;									;
; o Prints characters with the bold attribute set in bold.		;
;									;
; o On monochrome monitors, underlined characters are printed in	;
;   underlined mode							;
;									;
;-----------------------------------------------------------------------;

	DOSSEG
	MODEL	tiny

        LOCALS @@
;-----------------------------------------------------------------------;
; status masks returned by bios int 17h (printer service)		;
;-----------------------------------------------------------------------;

printererrors   EQU  	00101001b    	; these bits indicate an error on int 17h
printerselected	EQU     00010000b       ; printer selected bit

	CODESEG


	ORG	0100h

begin:
	jmp	install

string		macro	name, str
name		db	str
name&len	=	$-name
		endm


;---------------------------------------;
; printer control codes			;
;---------------------------------------;

string		cntrseq  <27,'^'>	; printer control code for control ch.
string		boldon	 <27,'G'>	; turn bold printing on
string		boldoff	 <27,'H'>	; turn bold printing off
string		underon	 <27,'-',1>	; turn underlined printing on
string		underoff <27,'-',0>	; turn underlined printing off

port		db	0		; printer port number lpt1=0, lpt2=1,..
inprogress 	db	0		; in progress status byte

;-------------------------------------------------;
; Local variables here instead of stack           ;
; because this TSR is stack parasitic 		  ;
;-------------------------------------------------;

boldflag	db	0	; bold printing is on
underflag	db	0	; underlined printing on
videomode	db	0	; video mode
videopage	db	0	; display page
row		db	0	; row  ( 0 based )
col		db	0	; col. ( 0 based )
char		db	0	; character
attr		db	0	; attribute
displaypage	db	0	; display page
screenwidth	db	0	; width of screen

%NEWPAGE

bputchar     proc	near
;----------------------------------------------;
;  subroutine to output a char to the printer  ;
;  input: al=char                              ;
;  dx, ax changed                              ;
;  carry flag set on error                     ;
;----------------------------------------------;
@@start:
	push	ax			; save char
	mov	dl,byte ptr [port]	; get printer port
        xor	dh,dh			; clear high byte
        mov	ah,02h			; bios printer - check status
        int	17h			; bios printer
        test    ah,printererrors	; check for errors
        jnz	@@error			;
        test	ah,printerselected	; make sure printer selected
	pop	ax			; get saved char
        jz	@@error			; to avoid time out
        xor	ah,ah			; bios printer - write char
        int	17h			; bios printer
        test	ah,printererrors	; check for errors
        jnz	@@error			;
@@noerror:
	clc				; clear carry flag
	retn				; and return
@@error:
	stc				; set carry
	retn				; and return
bputchar     endp


%NEWPAGE


bpputs	proc	near
;-----------------------------------------------;
; prints a string to bios printer          	;
; input : ds:si points to string                ;
;	  cx = length of string                 ;
; ax,dx,si destroyed				;
;                                               ;
; carry flag set on error                       ;
;-----------------------------------------------;

	cld				; auto increment si
@@repeat:
        lodsb				; get char (in al)
	call    bputchar		; print char
        jc	@@error			; printer error
	loop	@@repeat		; repeat until cx exhausted

@@noerror:
        clc				; clear carry flag
	retn				; and return

@@error:
	stc				; set carry
	retn				; and return

bpputs	endp


%NEWPAGE

printscreen	proc	near
;---------------------------------------------;
; Dump contents of screen to printer          ;
;---------------------------------------------;

@@start:
	mov	byte ptr [boldflag], 0	; clear bold flag
	mov	byte ptr [underflag],0	; clear underline flag

	mov	ah,0fh			; bios video - get display mode
	int	10h
	mov	byte ptr [screenwidth],ah; save width
	mov	byte ptr [videomode],al	; save mode
	mov	byte ptr [videopage],bh

	mov	ah,03h			; bios video - get positon
	int	10h
	push    dx			; save col and row to restore

	mov	byte ptr [row],0	; clear row
	jmp	@@rowstart

@@repeatrow:
	mov	byte ptr [col],0	; clear col
	jmp	@@colstart

@@repeatcol:

	mov	bh,[videopage]		; set page
	mov	dh,[row]		; set row
	mov	dl,[col]		; set col
	mov	ah,02h			; bios video - set cursor position
	int	10h

	mov	bh,[videopage]		; set page
	mov	ah,08h			; bios video - read char/attr
	int	10h
	mov	[attr],ah		; get attribute
	mov	[char],al		; get char

;	check to see if character is a 0 or a 255
;	these chars are blank on screen but freak out printers
; 	converted to spaces here

	cmp	byte ptr [char],0	; char = 0?
	je	@@changetospace		; then change to space
	cmp	byte ptr [char],255	; else is char = 255?
	jne	@@nochange		; then no change
@@changetospace:
	mov	byte ptr [char],' '	; else char = ' '
@@nochange:


%NEWPAGE

@@boldcheck:
	cmp	byte ptr boldflag,0	; bold flag set?
; then
	jne	@@boldflagset
; else

@@boldflagclear:
	test	byte ptr [attr],8	; bold attribute set?
; then
	je	@@endboldcheck
; else
	mov	byte ptr [boldflag],1	; set bold flag
	mov	cx,boldonlen		; print bold on sequence
	mov	si,offset boldon	; print bold on sequence
	call	bpputs

	jnc	@@endboldcheck
	jmp	@@printererror		; printer error - abort

@@boldflagset:
	test	byte ptr [attr],8	; bold attribute set?
; then
	jne	@@endboldcheck		; then go on
; else
	mov	byte ptr [boldflag],0	; else set boldflag
	mov	cx, boldonlen
	mov	si,offset boldoff	; print bold off sequence
	call	bpputs
@@endboldcheck:

%NEWPAGE


@@undercheck:
	cmp	[videomode],7		; is mode monochrome?
; then
	jne	@@endundercheck		; then go on
; else
	cmp	byte ptr underflag,0	; underflag set?
; then
	jne	@@underflagset		; then underflag set
; else
@@underflagclear:
	mov	al,byte ptr [attr]	; get attribute
	and	al,00000111b		; mask last three bits
	cmp	al,1			; 1 result means underlined
; then
	jne	@@underflagset
; else
	mov	byte ptr [underflag],1	; set underflag

	mov	cx, underonlen		; start underlining on printer
	mov	si,offset underon	; print underlining on sequence
	call	bpputs

	jnc     @@endundercheck		; no error - go on
	jmp     @@printererror		; printer error - abort

@@underflagset:
	cmp	byte ptr underflag,0	; underflag clear?
	je	@@endundercheck		; then underflagclear
	mov	al,byte ptr [attr]	; else get attribute
	and	al,00000111b		; mask last three bits
	cmp	al,1			; underlined if equal
; then
	je	@@endundercheck		; still underlined
; else
	mov	byte ptr [underflag],0	; clear underflag

	mov	cx, underofflen		; tell printer to stop underlining
	mov	si, offset underoff	; output under off sequence
	call	near ptr bpputs
	jc	@@printererror		; printer error - abort

@@endundercheck:

%NEWPAGE

;
;	output control sequence to notify printer
;	that the next character is a control code
;
	cmp	byte ptr [char],31	; not a control character?
; then
	ja	@@notcontrol		; then notcontrol
; else
	mov	cx, cntrseqlen		; tell printer that next char is cntrl
	mov	si, offset cntrseq	; output control sequence
	call	near ptr bpputs
	jc	@@printererror		; printer error - abort

@@notcontrol:

	mov	al,byte ptr [char]	; get char
	call 	near ptr bputchar	; print it
	jc	@@printererror		; printer error - abort

	inc	byte ptr [col]		; increment col
@@colstart:
	mov	ah,byte ptr [col]	; get col
	cmp	ah,[screenwidth]	; col>=width?
; then
	jge	@@endofline		;
; else
	jmp	@@repeatcol		; start over

@@endofline:				; print a carriage return and linefeed
	mov	al,13			; CR
	call	near ptr bputchar	;
	jc	@@printererror		; printer error - abort
        mov	al,10                   ; LF
	call	near ptr bputchar	;
	jc	@@printererror		; printer error - abort

	inc	byte ptr [row]		; increment row counter

@@rowstart:
	cmp	byte ptr [row],25	; last row?
	jge	short @@quitrow		; then quit
	jmp	@@repeatrow		; else repeat

@@quitrow:
	cmp	byte ptr [underflag],0	; underflag clear?
	je	@@next1			; then go on
	mov	cx, underofflen
	mov	si,offset underoff	; else
	call	near ptr bpputs		; print underoff
	jc	@@printererror		; printer error - abort
@@next1:
	cmp	byte ptr [boldflag],0	; bold flag clear?
	je	@@next2			; then go on

	mov	cx, boldofflen		; else tell printer bold off
	mov	si,offset boldoff	;
	call	near ptr bpputs		; print bold off
	jc	@@printererror		; printer error - abort
@@next2:
	mov	al,12			; print a form feed
	call	bputchar

@@printererror:

	mov	bh,[videopage]
	pop	dx			; restore cursor position
	mov	ah,02h			; bios video - set position
	int	10h
	ret

printscreen	endp


%NEWPAGE

isr05		proc
;-----------------------------------------------;
; new print screen interrupt			;
; called when <Print Scrn> key pressed		;
;-----------------------------------------------;

	push 	ax				; save registers
	push	bx
	push	cx
	push	dx
	push	es
	push	ds
	push	si
	push	di
        push    bp

	mov	ax,cs				; restore the data segment
	mov	ds,ax
	cmp	byte ptr [inprogress],0		; did we  interrupt ourselves?
	jne     @@skip                          ; then skip
	mov     byte ptr [inprogress],1       	; set in progress flag
	sti 					; reenable ints
	call	near ptr printscreen		; print the screen
	mov	byte ptr [inprogress],0	;       ; clear in progress flag

@@skip:
	pop     bp				; restore registers
	pop     di
	pop	si
	pop	ds
	pop	es
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret

isr05	endp


%NEWPAGE



;-----------------------------------------------------------------------;
;  transient code below							;
;-----------------------------------------------------------------------;

transientcode:

string		message,<13,10,'Print Screen now installed ',13,10>

install:

;  	Install new print screen  ISR

	mov	dx,offset isr05
	mov	al,05h			; printscreen vector
	mov	ah,25h			; dos - set vector
	int 	21h

;       Print message

	cld				; auto increment si
	mov	si,offset message
	mov	cx, messagelen
@@repeat:
	lodsb				; get char from message
	mov	dl,al			; mov char to dl
	mov	ah,02h			; dos - display output
	int	21h
	loop	@@repeat		; loop for length of message

; 	free enviroment

	mov	ax,word ptr [ds:02ch]	; get enviroment address from psp
        mov     es,ax
	mov	ah,49h			; dos - release memory
	int	21h

; 	Terminate and stay resident

	mov	dx,OFFSET transientcode	; don't save transient part
	int	27h			; terminate stay resident


	END	begin


