home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol7n22.arc
/
ENVELOPE.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-11-21
|
49KB
|
1,193 lines
;======================================================================
; ENVELOPE: Print envelopes on LaserJet Printers * PC Magazine
;-----------------------------------------------------------------------
; EQUATES
;-----------------------------------------------------------------------
LF EQU 0Ah ; Line feed
CR EQU 0Dh ; Carriage return
ESCAPE EQU 1Bh ; Escape
SCAN_CODE EQU 18 ; scan code for E
SHIFT_MASK EQU 8 ; shift status for Alt
LJ_MODEL EQU 1B ; Printer Flag Bit in status
PR_RET_ADD EQU 10B ; Print Return Address Flag
ENV_SIZE_BIT EQU 100B ; Envelope Size (Large if set)
EGA EQU 1000000B ; EGA Flag
INSTALLED EQU 10000000B ; Installed Flag
;-----------------------------------------------------------------------
; EQUATES for Envelope Margins - Note Bytes reversed
;-----------------------------------------------------------------------
LMARG_ADD_S EQU "06" ; Left Address Margin - Small
LMARG_RET_S EQU "54" ; Left Return Margin - Small
LMARG_ADD_L EQU "05" ; Left Address Margin - Large
LMARG_RET_L EQU "71" ; Left Return Margin - Large
TMARG_RET_S EQU "03" ; Top Return Margin - Small
TMARG_RET_L EQU "92" ; Top Return Margin - Large
TMARG_RET_2 EQU "61" ; Top Return Margin - Series 2
;----------------------------------------------------------------------
CSEG SEGMENT PUBLIC 'CODE'
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
ORG 100H
START: JMP INSTALL ; install TSR program
COPYRIGHT$ DB "ENVELOPE 1.0 Copyright (c) 1988 Ziff Communications Co."
DB CR,LF,"PC Magazine ",254," R. M. Saidikowski",CR,LF,"$",26
;-----------------------------------------------------------------------
; Program Data Area -- Static text first for Residency Check
;-----------------------------------------------------------------------
TEXT_UPPER DB "ark Upp",0,"Left ",0
TEXT_LOWER DB "ove Low",0,"Right",0
OLD09H DD 0 ; Holds old Interrupt 09H vector
BUSY DB 0 ; busy flag for ENVELOPE
; status byte for ENVELOPE ; bit 0 = LJ Series 2 if set
; bit 1 = Print return address ; bit 2 = Large Envelope
; bit 6 = EGA video adapter ; bit 7 = ENVELOPE installed
STATUS DB 00000101B
CURLOC DW 0 ; save cursor location
VID_PAGE DB 0 ; current video page
NUM_COLS DB 80 ; number columns in display
LAST_COL DB 79 ; last column number
LAST_LINE DB 24 ; last line number
ADDR_COLS DB 0 ; columns in address
START_COL DB 0 ; starting column for swap
UPLEFT DW 0 ; upper left position of box
BOTRIGHT DW 0 ; bottom right position of box
HILITE_LOC DW 0 ; highlight location of Small
PRINT_PORT DW 0 ; 0-2=LPT1-LPT3, 3-6=COM1-COM4
MENU_BLOCK DB 0DAH,7,10 DUP(0C4H,7),0BFH,7,0B3H,7,"M",7,"a",7
DB "r",7,"k",7," ",7,"U",7,"p",7,"p",7,"e",7,"r",7
DB 2 DUP(0B3H,7),"L",7,"e",7,"f",7,"t",7," ",7
DB " ",7,"&",7,17,7,0C4H,7,0D9H,7,0B3H,7,0C0H,7
DB 0C4H,7,"E",7,"s",7,"c",7,"=",7,"E",7,"x",7
DB "i",7,"t",7,0C4H,7,0D9H,7
MENU_PRINT DB 0C9H,7,8 DUP(0CDH,7),0BBH,7,0BAH,7,"F",7,"1",7
DB "-",7,"S",7,"m",7,"a",7,"l",7,"l",7,0BAH,7
DB 0BAH,7,"F",7,"2",7,"-",7,"L",7,"a",7,"r",7,"g",7
DB "e",7,2 DUP(0BAH,7),"F",7,"3",7,"-",7,"R",7
DB "t",7,"A",7,"d",7,"d",7,0BAH,7,0C7H,7
DB 8 DUP(0C4H,7),0B6H,7,0BAH,7,"L",7,"P",7,"T",7
DB "1",7," ",7,"L",7,"J",7,"2",7,2 DUP(0BAH,7)
DB 17,7,0C4H,7,0D9H,7,"P",7,"r",7,"i",7,"n",7,"t",7
DB 0BAH,7,0C8H,7,"E",7,"s",7,"c",7,"=",7,"E",7
DB "x",7,"i",7,"t",7,0BCH,7
LINE_SIZE EQU 40
RET_ADD DB LINE_SIZE DUP(32),CR,LF
DB LINE_SIZE DUP(32),CR,LF
DB LINE_SIZE DUP(32)
SKIP_LINE DB CR,LF,0,"$"
LENGTH_RET = (LINE_SIZE + 2) * 3
;-----------------------------------------------------------------------
; Laser Jet Command Sequences
;-----------------------------------------------------------------------
RESET_LJ DB ESCAPE,"E",0 ; reset printer
FONT DB ESCAPE,"&l1O" ; landscape
DB ESCAPE,"(8U" ; Roman-8 symbol set
DB ESCAPE,"(sp10h12vsb3T" ; 10-pitch 12-point
; upright med-weight Courier
DB ESCAPE,"&l2H",0 ; manual feed
TOP_MARGIN DB ESCAPE,"&l" ; skip lines
MODELX DB "16E",0 ; 16 for LJII 30 for LJ and LJ+
LEFT_MARGIN DB ESCAPE,"&a" ; left margin
ENV_SIZE DB "50L",0 ; 50 spaces - default Large
;-----------------------------------------------------------------------
; Arrow Key Jump Offsets
;-----------------------------------------------------------------------
KEYTAB DB 72, 75 , 77 , 80 ; Up Left Right Down
JMPTAB_TOP DW OFFSET TOP_UP,OFFSET TOP_LEFT
DW OFFSET TOP_RIGHT,OFFSET TOP_DOWN
JMPTAB_BOT DW OFFSET BOT_UP,OFFSET BOT_LEFT
DW OFFSET BOT_RIGHT,OFFSET BOT_DOWN
;======================================================================
; Intercept Keyboard Interrupt
;-----------------------------------------------------------------------
INT09H PROC FAR
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
STI ; Turn interrupts back on
PUSH AX
IN AL,60H ; get scan code
CMP AL,SCAN_CODE ; compare scan code
JNE INT9_2 ; if not, exit to old INT09H
MOV AH,2 ; shift key status
INT 16H ; BIOS
AND AL,0FH
CMP AL,SHIFT_MASK ; compare shift status
JE INT9_3 ; if yes, check if routine busy
INT9_2: POP AX
CLI ; flags already pushed
JMP DWORD PTR CS:[OLD09H] ; look like an interrupt
;-----------------------------------------------------------------------
; More ckecks before calling main ENVELOPE routine
;-----------------------------------------------------------------------
INT9_3: CMP CS:[BUSY],0 ; ENVR already active?
JNE INT9_2 ; normal exit
IN AL,61H ; reset keyboard
MOV AH,AL
OR AL,80H ; set bit 7
OUT 6AH,AL ; send to control port
MOV AH,AL ; recover old value
JMP SHORT $+2
OUT 6AH,AL ; send to control port
CLI
MOV AL,20H ; reset the
OUT 20H,AL ; interrupt controller
STI
PUSH BX ; AX already pushed
PUSH CX
PUSH DX
PUSH SI ; Save all registers
PUSH DI
PUSH DS
PUSH ES
PUSH BP
PUSH CS ; establish addressing
POP DS
ASSUME DS:CSEG
INC [BUSY] ; set busy flag
;-----------------------------------------------------------------------
; Get screen parameters -- part of test if interrupt OK
;-----------------------------------------------------------------------
MOV AH,0FH ; get video mode
INT 10H ; BIOS video
CMP AL,7 ; MONO
JE MODEOK
CMP AL,3 ; regular 40 and 80 column modes
JA INT09_X ; graphics mode - exit
MODEOK: MOV [NUM_COLS],AH ; number of columns
DEC AH
MOV [LAST_COL],AH ; last column number
MOV [VID_PAGE],BH ; video page
TEST [STATUS],EGA ; check if EGA (or VGA)
JZ SET_LINES ; not EGA
XOR AX,AX
MOV ES,AX
MOV AL,BYTE PTR ES:[484H]
MOV [LAST_LINE],AL
SET_LINES: PUSH CS ; set segment
POP ES ; for ES
ASSUME ES:CSEG
CALL GET_CURSOR ; get current cursor attributes
MOV [CURLOC],DX ; save cursor position
CALL ENVL_MAIN ; call main envelope routine
MOV DX,[CURLOC] ; saved cursor location
CALL SET_CURSOR ; restore cursor
INT09_X: DEC [BUSY] ; Envelope finished
ASSUME DS:NOTHING, ES:NOTHING
POP BP
POP ES
POP DS
POP DI ; restore all registers
POP SI
POP DX
POP CX
POP BX
POP AX
IRET ; return to Interrupted Routine
INT09H ENDP
;======================================================================
; Main ENVELOPE Routine
;-----------------------------------------------------------------------
ENVL_MAIN PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
;-----------------------------------------------------------------------
; Define address on screen
; Display upper left message and cursor in upper left
;-----------------------------------------------------------------------
MOV UPLEFT,0 ; initialize
CALL BLOCK_WINDOW ; place window on screen
XOR DX,DX ; upper left location
CALL SET_CURSOR
CALL GET_CHAR ; get character
PUSH AX ; save character
CALL BLOCK_WINDOW ; remove window from screen
;-----------------------------------------------------------------------
; set text in window for lower right corner message
;-----------------------------------------------------------------------
MOV SI,OFFSET TEXT_LOWER ; text for lower message
MOV DI,OFFSET MENU_BLOCK+28 ; window location
CALL MOV_TEXT
MOV DI,OFFSET MENU_BLOCK+50 ; window location
CALL MOV_TEXT ; move 'right' message
XOR DX,DX ; cursor location
CALL SET_CURSOR
POP AX ; recover character
JMP SHORT TOP_WIN_GONE
TOP_BADKE: CALL BEEP ; illegal key
TOP_NEXT: CALL SET_CURSOR ; set cursor
TOP_NEXT_KE: CALL GET_CHAR ; get character
TOP_WIN_GONE: MOV UPLEFT,DX ; save cursor location
CMP AL,CR ; carriage return
JE MOV_BOT_RT ; finished with top-left moves
CMP AL,ESCAPE ; Quit
JNE TOP_NOT_ESC
JMP ENV_EXIT ; exit ENVELOPE
TOP_NOT_ESC: OR AL,AL ; extended key code
JNZ TOP_NEXT_KE
MOV BX,OFFSET JMPTAB_TOP+6 ; last entry in table
CALL GET_JMP_OFF ; get jump offset
JC TOP_BADKE ; no match
JMP [DI] ; offset returned by Call
TOP_UP: OR DH,DH ; row number in DH
JE TOP_BADKE ; can't move higher
DEC DH
JMP TOP_NEXT ; get next cursor movement
TOP_LEFT: OR DL,DL ; column number in DL
JE TOP_BADKE ; can't move to left
DEC DL
JMP TOP_NEXT ; get next cursor movement
TOP_RIGHT: CMP DL,LAST_COL ; column number in DL
JE TOP_BADKE ; can't move to right
INC DL
JMP TOP_NEXT ; get next cursor movement
TOP_DOWN: CMP DH,LAST_LINE ; row number in DH
JE TOP_BADKE ; can't move lower
INC DH
JMP TOP_NEXT ; get next cursor movement
;-----------------------------------------------------------------------
; now move to bottom right corner to define address
; first -- display window and reverse video upper-left
;-----------------------------------------------------------------------
MOV_BOT_RT: CALL BLOCK_WINDOW ; move window on screen
MOV DX,UPLEFT ; current location
CALL SET_CURSOR
PUSH DX ; save cursor loc
CALL REVERSE ; reverse video
CALL BURY_CURSOR
CALL GET_CHAR
PUSH AX ; save character
CALL BLOCK_WINDOW ; remove window
POP AX ; recover character
POP DX ; recover cursor location
JMP SHORT BOT_WIN_GONE
BOT_BADKE: CALL BEEP ; illegal key
BOT_NEXTKE: CALL GET_CHAR ; get character
BOT_WIN_GONE: MOV BOTRIGHT,DX ; save cursor location
CMP AL,CR ; carriage return
JE PRINT_MENU ; display print window
CMP AL,ESCAPE ; Quit
JNE BOT_NOT_ESC ; not Escape
JMP SCREEN_RST ; restore screen
BOT_NOT_ESC: OR AL,AL ; extended key code
JNZ BOT_NEXTKE
MOV BX,OFFSET JMPTAB_BOT+6 ; last entry in table
CALL GET_JMP_OFF ; get jump offset
JC BOT_BADKE ; no match
MOV BX,UPLEFT ; upper left location
JMP [DI] ; offset returned by Call
BOT_UP: CMP DH,BH ; compare to top
JE BOT_BADKE ; can't move up
DEC DH ; new bottom right location
PUSH DX ; save
INC DH ; reset
REVERSE_ROW: CALL SET_CURSOR
CALL REVERSE ; reverse video at cursor
DEC DL ; column number
CMP DL,BL ; beyond beginning?
JL BR_FINISH ; finish reversing
JMP REVERSE_ROW ; next column
BOT_LEFT: CMP DL,BL ; compare to left
JE BOT_BADKE ; can't move left
DEC DL ; new bottom right location
PUSH DX ; save
INC DL ; reset
REVERSE_COL: CALL SET_CURSOR
CALL REVERSE ; reverse video at cursor
DEC DH ; row number
CMP DH,BH ; at end?
JGE REVERSE_COL ; next row
BR_FINISH: CALL BURY_CURSOR
POP DX ; recover current location
JMP BOT_NEXTKE ; get next move
BOT_RIGHT: CMP DL,LAST_COL ; can't move beyond last column
JE BOT_BADKE
INC DL ; new bottom right location
PUSH DX ; save
JMP REVERSE_COL ; add column
BOT_DOWN: MOV AX,DX
SUB AH,BH ; number rows
CMP AH,5 ; max rows (is 6)
JE BOT_BADKE
CMP DH,LAST_LINE ; can't move beyond last row
JE BOT_BADKE
INC DH ; new bottom right location
PUSH DX ; save
JMP REVERSE_ROW ; add row
;-----------------------------------------------------------------------
; Display Print Menu
;-----------------------------------------------------------------------
PRINT_MENU: CALL PRINT_WINDOW ; display print window
SET_SIZE: CALL SET_HILITE ; set size and return hilites
PR_NEXT: CALL GET_CHAR
CMP AL,CR ; print if carriage return
JE PRINT_ENV ; print envelope
CMP AL,ESCAPE ; exit without printing
JNE PR_NOTESC
CALL PRINT_WINDOW ; remove print window
JMP SCREEN_RST ; restore screen and exit
PR_NOTESC: OR AL,AL ; test for extended code
JZ PR_CODE
PR_BADKE: CALL BEEP
JMP PR_NEXT ; get another character
PR_CODE: SUB AH,59 ; convert function keys to digit codes
JL PR_BADKE
JG PR_CODE_2
AND STATUS,NOT ENV_SIZE_BIT ; Small Envelope
JMP SET_SIZE
PR_CODE_2: SUB AH,2
JG PR_BADKE ; F4 or greater
JE PR_CODE_3 ; F3
OR STATUS,ENV_SIZE_BIT ; Large Envelope
JMP SET_SIZE
PR_CODE_3: XOR STATUS,PR_RET_ADD ; toggle return address bit
JMP SET_SIZE
;-----------------------------------------------------------------------
; print envelope here
;-----------------------------------------------------------------------
PRINT_ENV: CALL PRINT_WINDOW ; remove print display window
MOV SI,OFFSET RESET_LJ ; reset printer
CALL OUT_STRING
JNC PRINT_OK
;-----------------------------------------------------------------------
; printer error -- beep twice and try again
;-----------------------------------------------------------------------
CALL BEEP
XOR CX,CX
DUMB_LOOP: LOOP DUMB_LOOP ; slight delay
CALL BEEP
JMP PRINT_MENU ; try again
PRINT_OK: MOV SI,OFFSET FONT ; set fonts, etc.
CALL OUT_STRING
;-----------------------------------------------------------------------
; set margins for location of return address
;-----------------------------------------------------------------------
TEST STATUS,LJ_MODEL ; this affects top margin
MOV AX,TMARG_RET_2 ; LJ Series 2
JNZ SET_TOP_RET
TEST STATUS,ENV_SIZE_BIT ; affects top on LJ & LJ+
MOV AX,TMARG_RET_S ; Small on original
JZ SET_TOP_RET
MOV AX,TMARG_RET_L ; Large on original
SET_TOP_RET: MOV WORD PTR MODELX,AX ; set top margin
TEST STATUS,ENV_SIZE_BIT ; this affects left margin
MOV AX,LMARG_RET_S ; small envelope
JZ SET_LEFT_RET
MOV AX,LMARG_RET_L ; large envelope
SET_LEFT_RET: MOV WORD PTR ENV_SIZE,AX ; set left margin
CALL SET_MARGINS ; send commands to printer
;-----------------------------------------------------------------------
; print the return address if requested
;-----------------------------------------------------------------------
MOV CX,9 ; lines to skip if no return
TEST STATUS,PR_RET_ADD ; print return address?
JZ TO_ADDRESS ; no return address
MOV SI,OFFSET RET_ADD ; print return address
CALL OUT_STRING
MOV CX,6 ; lines to skip if return addr
;-----------------------------------------------------------------------
; print 'to' address -- first set margins
;-----------------------------------------------------------------------
TO_ADDRESS: CALL LINE_FEED ; skip a line
LOOP TO_ADDRESS ; count in CX
TEST STATUS,ENV_SIZE_BIT ; this affects left margin
MOV AX,LMARG_ADD_S ; small envelope
JZ SET_LEFT_ADD
MOV AX,LMARG_ADD_L ; large envelope
SET_LEFT_ADD: MOV WORD PTR ENV_SIZE,AX ; set left margin
CALL SET_LEFT_ONLY ; send commands to printer
;-----------------------------------------------------------------------
; read address from reverse-video part of screen - send to printer
;-----------------------------------------------------------------------
XOR CX,CX
MOV AX,BOTRIGHT
MOV DX,UPLEFT ; starting loc on screen
SUB AX,DX ; rows-1 and cols-1 in AX
MOV CL,AH ; rows - 1
INC AL ; columns
MOV ADDR_COLS,AL ; save columns in address
JCXZ LAST_ROW ; only one line
NEXT_ROW: PUSH CX ; save loop counter
PUSH DX ; save cursor location
CALL OUT_LINE ; print line from screen
CALL LINE_FEED ; send carriage return
POP DX ; retrieve cursor
INC DH ; next row
POP CX ; retrieve counter
LOOP NEXT_ROW
LAST_ROW: CALL OUT_LINE ; print last line
MOV SI,OFFSET RESET_LJ ; reset printer
CALL OUT_STRING ; also flushes printer buffer
;-----------------------------------------------------------------------
; restore screen to normal video
;-----------------------------------------------------------------------
SCREEN_RST: MOV DX,UPLEFT
MOV AX,BOTRIGHT
SUB AX,DX
ADD AX,0101H ; rows and columns in AX
XOR CX,CX
MOV CL,AH ; number rows
XOR AH,AH
MOV SI,AX ; save columns
ROW_RESTORE: PUSH CX
MOV CX,SI ; number columns
PUSH DX ; save cursor location
COL_RESTORE: CALL SET_CURSOR
CALL REVERSE ; reset video
INC DL ; next column
LOOP COL_RESTORE
POP DX
INC DH ; next row
POP CX
LOOP ROW_RESTORE
;-----------------------------------------------------------------------
; reset text in window for upper left corner message
;-----------------------------------------------------------------------
ENV_EXIT: MOV SI,OFFSET TEXT_UPPER ; top message
MOV DI,OFFSET MENU_BLOCK+28 ; window location
CALL MOV_TEXT
MOV DI,OFFSET MENU_BLOCK+50 ; window location
CALL MOV_TEXT ; mov 'left ' message
RET
ENVL_MAIN ENDP
;======================================================================
; output a string to the printer
; string address in SI, terminated by ASCII0
;-----------------------------------------------------------------------
OUT_STRING PROC NEAR
LODSB ; next character
OR AL,AL ; check for 0
JZ OUT_STR_X ; CY is clear
CALL OUT_CHAR ; output character
JC OUT_STR_X ; error return
JMP OUT_STRING ; get next character
OUT_STR_X: RET ; ret on ASCII0
OUT_STRING ENDP
;======================================================================
; print line of text from screen at cursor location DX
; number to print in ADDR_COLS
;-----------------------------------------------------------------------
OUT_LINE PROC NEAR
PUSH CX ; save counter
XOR CX,CX
MOV CL,ADDR_COLS ; column counter
LOOP_LINE: CALL SET_CURSOR ; cursor to location DX
MOV AH,8 ; read character
CALL VIDEO_INT ; into AL
PUSH DX ; save location
CALL OUT_CHAR ; print character
POP DX ; recover location
INC DL ; next column
LOOP LOOP_LINE
CALL BURY_CURSOR
POP CX ; recover counter
RET
OUT_LINE ENDP
;======================================================================
; skip line by sending CR LF combination alters AX DX SI
;-----------------------------------------------------------------------
LINE_FEED PROC NEAR
MOV SI,OFFSET SKIP_LINE
CALL OUT_STRING ; send characters CR LF 0
RET
LINE_FEED ENDP
;======================================================================
; output character in AL to printer alters AX DX
;-----------------------------------------------------------------------
OUT_CHAR PROC NEAR
MOV DX,PRINT_PORT ; printer port number
CMP DX,2 ; 0 to 2 are LPT1-LPT3
JG SERIAL
XOR AH,AH ; print character
INT 17H ; BIOS printer
TEST AH,101001B ; check for printer error
TEST_ERROR: JZ NO_ERROR ; normal return
RET_ERROR: STC ; error return
RET
SERIAL: SUB DX,3 ; COM port number
MOV AH,1 ; send char - DX already set
INT 14H ; BIOS
TEST AH,10000000B ; check for printer error
JMP TEST_ERROR ; test for error
OUT_CHAR ENDP
;======================================================================
; Set top and left margins for return or to address
;-----------------------------------------------------------------------
SET_MARGINS PROC NEAR
MOV SI,OFFSET TOP_MARGIN ; top margin
CALL OUT_STRING
SET_LEFT_ONLY LABEL NEAR
MOV SI,OFFSET LEFT_MARGIN ; left margin
CALL OUT_STRING
RET
SET_MARGINS ENDP
;======================================================================
; Calculate offset for NEAR JMP to LABEL
; extended code in AH (from GETCHAR) BX points to end of JumpTable
; Returns JUMP offset in DI No match if CY flag set
;-----------------------------------------------------------------------
GET_JMP_OFF PROC NEAR
MOV DI,OFFSET KEYTAB ; table of key codes
MOV CX,4 ; number of codes
XCHG AH,AL ; code into AL
REPNZ SCASB ; look for match
JNZ RET_ERROR ; no match
MOV DI,BX ; last entry in table
SHL CX,1 ; 2 bytes/word
SUB DI,CX ; offset
NO_ERROR: CLC ; normal return
RET
GET_JMP_OFF ENDP
;======================================================================
; set highlites in printer menu
;-----------------------------------------------------------------------
SET_HILITE PROC NEAR
MOV CX,3 ; 3 lines to reset
MOV DX,HILITE_LOC ; beginning location of Small
PUSH DX ; save
PUSH DX ; save again
SET_H_LOOP: PUSH DX ; save
MOV BL,07H ; normal video
CALL SET_ATTRIB ; set attribute byte
POP DX ; Small message
INC DH ; next row
LOOP SET_H_LOOP
POP DX ; retrieve HILITE_LOC
TEST STATUS,ENV_SIZE_BIT ; test for small
JZ SET_HIL_2 ; not set = small
INC DH ; Large to be hilited
SET_HIL_2: MOV BL,70H ; reverse video
CALL SET_ATTRIB
POP DX ; retrieve HILITE_LOC
ADD DH,2 ; location of 'RtAdd'
TEST STATUS,PR_RET_ADD ; test for print of rt-add
JZ SET_HIL_X ; no print if 0
CALL SET_ATTRIB ; color should still be in BL
SET_HIL_X: CALL BURY_CURSOR ; bury cursor
RET
SET_HILITE ENDP
;======================================================================
; set attributes -- start at DX (cursor)
; change 5 attributes to BL
;-----------------------------------------------------------------------
SET_ATTRIB PROC NEAR
PUSH CX
MOV CX,5 ; attributes to set
SET_ATT_LOOP: CALL SET_CURSOR
MOV AH,8 ; read character
CALL VIDEO_INT
PUSH CX
MOV AH,9 ; write character
MOV CX,1 ; one character
CALL VIDEO_INT ; attribute in BL
INC DL ; next position
POP CX
LOOP SET_ATT_LOOP ; next character
POP CX
RET
SET_ATTRIB ENDP
;======================================================================
BEEP PROC NEAR
PUSH AX
MOV AX,0E07H ; Beep (ASCII 7)
INT 10H ; BIOS
POP AX
RET
BEEP ENDP
;======================================================================
; call BIOS video INT function in AH
;-----------------------------------------------------------------------
VIDEO_INT PROC NEAR
PUSH BX
MOV BH,VID_PAGE ; page number
INT 10H ; BIOS video
POP BX
RET
VIDEO_INT ENDP
;======================================================================
; bury cursor alters DX
;-----------------------------------------------------------------------
BURY_CURSOR PROC NEAR
MOV DH,[LAST_LINE]
INC DH
XOR DL,DL
;-----------------------------------------------------------------------
; set cursor to position in DH DL
;-----------------------------------------------------------------------
SET_CURSOR LABEL NEAR
PUSH AX
MOV AH,2 ; set cursor
VIDEO_CURSOR: CALL VIDEO_INT ; BIOS video
POP AX
RET
;-----------------------------------------------------------------------
; get cursor in DX ( DH DL )
;-----------------------------------------------------------------------
GET_CURSOR LABEL NEAR
PUSH AX
MOV AH,3 ; get cursor
JMP VIDEO_CURSOR ; BIOS video
BURY_CURSOR ENDP
;======================================================================
; get character from keyboard
;-----------------------------------------------------------------------
GET_CHAR PROC NEAR
XOR AH,AH
INT 16H
RET
GET_CHAR ENDP
;======================================================================
; reverse video attribute at cursor location alters AX
;-----------------------------------------------------------------------
REVERSE PROC NEAR
PUSH BX
PUSH CX
MOV AH,8 ; read character
CALL VIDEO_INT ; attribute to AH
MOV CL,4
ROR AH,CL ; reverse video attribute
MOV BL,AH ; need attribute in BL
MOV AH,9 ; write character
MOV CX,1 ; write 1 character
CALL VIDEO_INT ; attribute in BL
POP CX
POP BX
RET
REVERSE ENDP
;======================================================================
; Display Window with Instructions for Blocking out address
; SI offset in memory DX screen location
; CX chars/row AX number rows
;-----------------------------------------------------------------------
BLOCK_WINDOW PROC NEAR
MOV DH,2 ; row start
MOV DL,[NUM_COLS] ; number columns in mode
SUB DL,12 ; number columns
CMP BYTE PTR [UPLEFT],27 ; check start column
JLE BLOCK_WIND_2
XOR DL,DL ; start in first column
BLOCK_WIND_2:
MOV SI,OFFSET MENU_BLOCK ; memory LOCATION
MOV AX,4 ; rows
MOV CX,12 ; columns
;-----------------------------------------------------------------------
; swap window with screen - use BIOS
; call with screen loc in DX memory image at SI
; rows in AX columns in CX
; alters AX BX CX DX SI
;-----------------------------------------------------------------------
WINDOW LABEL NEAR
MOV [START_COL],DL ; starting column for swap
LOOP_ROW: PUSH AX ; rows
PUSH CX ; columns
LOOP_COL: CALL SET_CURSOR
MOV AH,8 ; read character and attrib
CALL VIDEO_INT
XCHG AX,DS:[SI] ; swap with memory
INC SI
INC SI ; next image location
MOV BL,AH ; attribute
MOV AH,9 ; write character and attrib
PUSH CX
MOV CX,1 ; write only one character
CALL VIDEO_INT
POP CX
INC DL ; move cursor
LOOP LOOP_COL ; next character and attribute
POP CX ; number columns
INC DH ; next row
MOV DL,[START_COL] ; starting column
POP AX ; rows to move
DEC AX ; row moved
JNZ LOOP_ROW ; next row
CALL BURY_CURSOR
RET
BLOCK_WINDOW ENDP
;======================================================================
; Display Print Command Window
; SI offset in memory DX screen location
; CX chars/row AX number rows
;-----------------------------------------------------------------------
PRINT_WINDOW PROC NEAR
MOV AH,2 ; row start
MOV AL,[NUM_COLS] ; number columns in mode
SUB AL,10 ; start column
MOV DX,AX ; save
ADD AX,0104H ; location for highlight
MOV [HILITE_LOC],AX ; save
MOV SI,OFFSET MENU_PRINT ; memory location
MOV AX,8 ; rows
MOV CX,10 ; columns
JMP WINDOW ; swap
PRINT_WINDOW ENDP
;======================================================================
; move text in memory from DS:[SI] to ES:[DI]
; the destination is assumed to be a screen image w/attribute bytes
; ASCII 0 terminates move alters AL
; sets SI and DI to next space in sequences
;-----------------------------------------------------------------------
MOV_TEXT PROC NEAR
LODSB ; next character
OR AL,AL
JNZ MOV_TEXT_X ; ASCII 0
RET
MOV_TEXT_X: STOSB ; send to display
INC DI ; 2 bytes/video
JMP MOV_TEXT ; get next character
MOV_TEXT ENDP
;======================================================================
; this part of code will not remain resident
;-----------------------------------------------------------------------
INSTRUCT$ DB "/U - Uninstall",CR,LF
DB "/Pxx - Printer Port, xx=L1-L3,C1-C4. Default"
DB "=L1 (LPT1)",CR,LF
DB "/Ln - LaserJet Model"
DB " n=1 original & +, n=2 Series 2. Default=2",CR,LF
DB "/R - Change Return Address",LF,"$"
WHITE DB " ,;",9 ; space, comma, semicolon, tab
FILENAME DB "ENVELOPE.COM",0
RESIDENT_SEG DW 0 ; segment of installed ENVELOPE
INSTALLED$ DB CR,LF,"Port "
PORT$ DB "LPT1, Model LJ"
MODEL$ DB "2, Hotkey is Alt-E$"
ALREADY_IN$ DB "Resident$"
NOT_INST$ DB "NOT Resident$"
UNINSTALL$ DB "Uninstalled$"
NO_UN_INST$ DB "Can't Uninstall$"
SAVE_TO_FILE$ DB "Save new ENVELOPE.COM?$"
FILE_ERROR$ DB "FILE ERROR - nothing saved$"
FILE_UPDATE$ DB "ENVELOPE.COM updated$"
RET_UPDATE$ DB "Resident Return Address Updated$"
PORT_NAMES DB "LPT1",0,"LPT2",0,"LPT3",0
DB "COM1",0,"COM2",0,"COM3",0,"COM4",0
;----------------------------------------------------------------------
INSTALL PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
CLD ; standard UP direction
MOV DX,OFFSET COPYRIGHT$
MOV AH,9 ; copyright message
INT 21H ; DOS
MOV DX,OFFSET INSTRUCT$
CALL MESSAGE
MOV NUM_COLS,80
MOV LAST_COL,79
MOV LAST_LINE,24
MOV PRINT_PORT,0
MOV STATUS,5
;-----------------------------------------------------------------------
; first check if ENVELOPE already installed and set flag in STATUS
;-----------------------------------------------------------------------
ASSUME ES:NOTHING
NOT WORD PTR [START] ; Modify
MOV BX,600H ; segment to compare
MOV AX,CS ; this segment
FIND_RES: INC BX ; next paragraph
MOV ES,BX ; ES is search segment
CMP AX,BX ; current segment?
JE CHECK_TAIL ; not in memory flag is 0
MOV SI,OFFSET START ; compare static part of data
MOV DI,SI ; same offset in both strings
MOV CX,16 ; bytes to compare
REP CMPSB ; compare DS:SI to ES:DI
OR CX,CX ; all matched
JNZ FIND_RES ; check next paragraph
OR STATUS,INSTALLED ; set bit for installed
MOV RESIDENT_SEG,BX ; save installed segment
MOV DX,OFFSET ALREADY_IN$
CALL MESSAGE
;-----------------------------------------------------------------------
; Now check command tail for switches
; DS points to CODE and to PSP
;-----------------------------------------------------------------------
CHECK_TAIL:
PUSH DS ; reset extra segment
POP ES
ASSUME ES:CSEG
MOV SI,80H ; location of command tail
LODSB ; length in AL
OR AL,AL ; Check if parameters
JNZ CHECK_0 ; commands to check
ATTEMPT_INST: TEST STATUS,INSTALLED
JNZ RLH_1
JMP OK_INSTALL ; proceed with default install
RLH_1: MOV AX,4C01H ;Terminate with return code
INT 21H
;-----------------------------------------------------------------------
; Decode command line using brute force
;-----------------------------------------------------------------------
CHECK_0: MOV BL,AL ; character count
CHECK_1: OR BL,BL ; more commands?
JZ ATTEMPT_INST ; processing complete
LODSB ; next character
DEC BL ; keep count current
MOV DI,OFFSET WHITE ; delimiters and space
MOV CX,4 ; number to check
REPNE SCASB
JE CHECK_1 ; look for next character
CHECK_2: CMP AL,"/" ; normal delimiter
JNE ATTEMPT_INST ; anything else - default
;-----------------------------------------------------------------------
; check character after slash
;-----------------------------------------------------------------------
OR BL,BL ; if / terminates
JZ ATTEMPT_INST ; then try default install
LODSB ; character after slash
AND AL,01011111B ; capitalize
CMP AL,"U" ; uninstall
JNE CHECK_3
JMP UNINSTALL ; attempt to uninstall
CHECK_3: CMP AL,"P" ; check for port input
JNE CHECK_4
CALL GET_PORT
JC ATTEMPT_INST ; if input errors
JMP CHECK_1 ; continue with input
CHECK_4: CMP AL,"L" ; check LJ Model input
JNE CHECK_5
CALL GET_MODEL
JC ATTEMPT_INST ; if input errors
JMP CHECK_1 ; continue with input
CHECK_5: CMP AL,"R" ; input new return address
JNE ATTEMPT_INST ; no match
CALL GET_RET_ADD
;-----------------------------------------------------------------------
; Prompt for saving new Return Address to ENVELOPE.COM
;-----------------------------------------------------------------------
CHECK_SAVE: MOV DX,OFFSET SAVE_TO_FILE$
MOV AH,9
INT 21H
;;; CALL MESSAGE
;;; CALL GET_CHAR ; get response
MOV AH,1 ;DOS get char fn
INT 21H ; allows for redirection
AND AL,01011111B ; capitalize
CMP AL,"Y"
JNE NO_RET_SAVE
;-----------------------------------------------------------------------
; save to file here - attempt to open file
;-----------------------------------------------------------------------
NOT WORD PTR [START]
MOV AH,3CH ;Create file
MOV DX,OFFSET FILENAME ; name of ENVELOPE.COM
XOR CX,CX ;Normal attribute
INT 21H ; DOS
JNC SAV_FILE_OK
SAV_FILE_ERR: MOV DX,OFFSET FILE_ERROR$
JMP SHORT SAV_FILE_MSG ; display string, proceed
SAV_FILE_OK: MOV BX,AX ; file handle
MOV AH,40H ; write to file
MOV CX,(OFFSET COM_SIZE - OFFSET CSEG - 100H) ;bytes
MOV DX,100H
INT 21H ; DOS
JC SAV_FILE_ERR
MOV AH,3EH ; close file handle
INT 21H ; DOS
MOV DX,OFFSET FILE_UPDATE$
SAV_FILE_MSG: CALL MESSAGE
NOT WORD PTR [START]
NO_RET_SAVE:
TEST STATUS,INSTALLED ; is ENVELOPE installed?
JZ OK_INSTALL ; install
MOV SI,OFFSET RET_ADD
MOV DI,SI ; same offset
MOV AX,RESIDENT_SEG ; segment of installed ENVELOPE
MOV ES,AX ; destination
MOV CX,LENGTH_RET ; bytes to move
REP MOVSB
MOV DX,OFFSET RET_UPDATE$
CALL MESSAGE
MOV AX,4C05H
INT 21H
;-----------------------------------------------------------------------
; final preparations for installation of ENVELOPE
; set printer model and port name in PRINT_MENU
;-----------------------------------------------------------------------
OK_INSTALL: PUSH CS
POP ES ; reset segment
ASSUME ES:CSEG
MOV DI,OFFSET MENU_PRINT+116 ; location for model
MOV AL," " ; original LJ or LJ+
TEST STATUS,LJ_MODEL ; check for LJ Series 2
JZ SET_MODEL
MOV AL,"2" ; LJ Series II
SET_MODEL: STOSB
MOV MODEL$,AL ; Model in message
MOV DI,OFFSET MENU_PRINT+102 ; location for port
MOV SI,OFFSET PORT_NAMES ; location for names
MOV AX,PRINT_PORT ; 0 through 6 LPT1 - COM4
ADD SI,AX
SHL AX,1
SHL AX,1
ADD SI,AX ; offset in memory in SI
PUSH SI ; save location
CALL MOV_TEXT ; move text to video image
POP SI ; location of port name
MOV DI,OFFSET PORT$ ; location in message
MOVSW
MOVSW ; move 4 bytes
;-----------------------------------------------------------------------
; check for EGA (or VGA) and set byte if present
;-----------------------------------------------------------------------
MOV AH,12H ; special EGA function
MOV BL,10H ; return EGA information
INT 10H ; BIOS video
CMP BL,10H ; if BL unchanged then
JE ENV_REL ; no EGA or VGA
OR STATUS,EGA ; set EGA bit
;-----------------------------------------------------------------------
; Release environment block
;-----------------------------------------------------------------------
ENV_REL: MOV BX,WORD PTR DS:[2CH] ; environment block
MOV ES,BX ; segment
ASSUME ES:NOTHING
MOV AH,49H ; free memory block
INT 21H ; DOS
;-----------------------------------------------------------------------
; go resident
;-----------------------------------------------------------------------
MOV AX,3509H ; get interrupt vector 09h
INT 21H ; DOS
MOV WORD PTR OLD09H,BX ; offset old interrupt 09h
MOV WORD PTR OLD09H[2],ES ; segment for above
MOV DX,OFFSET INT09H ; new INT handler
MOV AX,2509H ; set interrupt vector 09h
INT 21H ; DOS
MOV DX,OFFSET INSTALLED$ ; installation message
CALL MESSAGE
MOV DX,OFFSET INSTALL ; save code up to INSTALL
INT 27H ; The infamous TSR interrupt
;-----------------------------------------------------------------------
; attempt to uninstall ENVELOPE
;-----------------------------------------------------------------------
UNINSTALL: TEST STATUS,INSTALLED ; first see if it is resident
JNZ UNINST_2 ; it is in memory
MOV DX,OFFSET NOT_INST$
CALL MESSAGE
MOV AX,4C02H
INT 21H
UNINST_2: MOV AX,3509H ; get segment of keyboard INT
INT 21H ; DOS
ASSUME ES:NOTHING
MOV AX,ES ; current segment
CMP AX,RESIDENT_SEG ; segment of ENVELOPE
JE UNINST_3 ; OK to uninstall
NO_UNINST: MOV DX,OFFSET NO_UN_INST$
MOV AX,4C03H
INT 21H
;-----------------------------------------------------------------------
; OK to uninstall
;-----------------------------------------------------------------------
UNINST_3: MOV ES,RESIDENT_SEG ; segment of installed ENVELOPE
NOT WORD PTR ES:[START] ; don't confuse next install
LDS DX,ES:[OLD09H] ; old INT09H interrupt vector
ASSUME DS:NOTHING
MOV AX,2509H ; reset vector 09H
INT 21H ; DOS
PUSH CS ; reset DS to code
POP DS
ASSUME DS:CSEG
MOV AH,49H ; free memory block in ES
INT 21H ; DOS
JC NO_UNINST ; error return
MOV DX,OFFSET UNINSTALL$
CALL MESSAGE
MOV AX,4C04H
INT 21H
INSTALL ENDP
;-----------------------------------------------------------------------
; Read port number from command tail SI points to next character
; BL characters left CY set on return if error
;-----------------------------------------------------------------------
GET_PORT PROC NEAR
CALL GET_NEXT_CH ; next character from tail
JZ G_ERROR_RET ; no characters left
AND AL,01011111B ; capitalize
CMP AL,"L" ; parallel port
JNE GET_PORT_1
CALL GET_NEXT_CH ; next character from tail
SUB AL,"1" ; should be number
CMP AL,2 ; LPT3
JBE SET_PORT_NUM
G_ERROR_RET: STC ; carry set on error
RET
SET_PORT_NUM: XOR AH,AH ; port number in AX
MOV PRINT_PORT,AX ; save port number
CLC ; carry clear on normal return
RET
GET_PORT_1: CMP AL,"C" ; serial port
JNE G_ERROR_RET
CALL GET_NEXT_CH ; next character from tail
SUB AL,"1" ; should be number
CMP AL,3 ; COM4
JA G_ERROR_RET
ADD AL,3 ;Skew port number in AX
JMP SET_PORT_NUM
GET_PORT ENDP
;-----------------------------------------------------------------------
; Read LJ Model type from command tail SI points to next character
; BL characters left CY set on return if error
;-----------------------------------------------------------------------
GET_MODEL PROC NEAR
CALL GET_NEXT_CH ; next character from tail
JZ G_ERROR_RET ; no characters left
SUB AL,"1" ; should be number
JB G_ERROR_RET ; illegal input
JA GET_MODEL_2
AND STATUS,NOT LJ_MODEL ; clear model bit
CLC
RET
GET_MODEL_2: CMP AL,1
JNE G_ERROR_RET ; illegal input
OR STATUS,LJ_MODEL ; set model bit
CLC
RET
GET_MODEL ENDP
;-----------------------------------------------------------------------
; enter new return address from keyboard
; if CY set on return - then return address is not altered
; first display current return address
;-----------------------------------------------------------------------
CURRENT_RET$ DB "Current Address:$"
ACCEPT_RET$ DB "Enter new address (Enter = no change).",CR,LF
DB "3 lines, 40 characters max.$"
GET_RET_ADD PROC NEAR
MOV DX,OFFSET CURRENT_RET$
CALL MESSAGE
MOV DX,OFFSET RET_ADD
MOV AH,9 ; display string
INT 21H ; DOS
MOV DX,OFFSET ACCEPT_RET$ ; accept prompt
CALL MESSAGE
MOV DX,OFFSET ADR_BUF ;Single line buffer
MOV BYTE PTR [ADR_BUF],LINE_SIZE+1
MOV AH,0AH ; buffered input
INT 21H ; DOS
CMP BYTE PTR ADR_BUF[1],0 ; any input?
JE GET_RET_ADD_2 ; first line read
MOV DI,OFFSET RET_ADD
CALL MOVE_LINE ; blank line, move new, saves DI
CALL GET_LINE ; get next line
CALL GET_LINE ; get final line
GET_RET_ADD_2: RET
GET_RET_ADD ENDP
;======================================================================
; get line from STDIN and then move to return address
;----------------------------------------------------------------------
GET_LINE PROC NEAR
MOV DX,OFFSET ADR_BUF
MOV AH,0AH ; buffered input
INT 21H ; DOS
ADD DI,LINE_SIZE+2 ; next line
;----------------------------------------------------------------------
; blank line in return address
;----------------------------------------------------------------------
MOVE_LINE LABEL NEAR
PUSH DI ; save pointer
PUSH DI ; save pointer
MOV CX,LINE_SIZE ; # characters
MOV AL," " ; set to blanks
REP STOSB
POP DI ; recover address
MOV SI,OFFSET ADR_BUF+2 ; last input
MOV CL,BYTE PTR ADR_BUF[1] ; number characters CH=0
JCXZ MOVE_LINE_X ; no characters
REP MOVSB
MOVE_LINE_X: MOV DX,OFFSET CR_LF$ ; move to next line
MOV AH,9 ; display string
INT 21H ; DOS
POP DI
RET
GET_LINE ENDP
;======================================================================
; get next character from command tail (pointed to by SI)
; BL set to number left ZF set if not chacters left
;----------------------------------------------------------------------
GET_NEXT_CH PROC NEAR
LODSB ; next character
DEC BL ; update count
OR BL,BL ; check if last character
RET
GET_NEXT_CH ENDP
;======================================================================
; Write a line using the DOS print string function.
;----------------------------------------------------------------------
CR_LF$ DB CR,LF,"$" ; carriage return -- line feed
MESSAGE PROC NEAR
MOV AH,9
INT 21H
MOV DX,OFFSET CR_LF$
MOV AH,9
INT 21H
RET
MESSAGE ENDP
;======================================================================
COM_SIZE = $
PC = $
ADR_BUF = PC ;ADR_BUF DB 41, 0, 41 DUP(0)
CSEG ENDS
END START