home *** CD-ROM | disk | FTP | other *** search
- ;======================================================================
- ; 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
-