home *** CD-ROM | disk | FTP | other *** search
- title LPTx : Line PrinTer Output Capture Routine
- page 60,132
- ;------------------------------------------------------------
- ;
- ; MAIN PROGRAM Version 7.00
- ;
- ; (C) Copyright 1987 by Mark DiVecchio, All Rights Reserved
- ; (C) Copyright 1987 by Kepa Zubeldia, All Rights Reserved
- ;
- .xlist
- ;
- ;This program is released for use in non-commercial environments. I
- ;ask commercial users to register the program with a $25 copyright fee for
- ;each site (any number of users and computers) at which the program is used.
- ;
- ; DISCLAMER : this program tries to perform a function which is
- ; not supported by DOS. It will work sometime and will not work
- ; other times. That kind of explains why you don't see this type
- ; of program on the market.
- ; I have tested it under DOS 2.1 and DOS 3.1. Some users have
- ; reported trouble when running under DOS 3.x and for other users
- ; it works fine. USE AT YOUR OWN RISK.
- ;
- ; Mark C. DiVecchio
- ; 10435 Mountain Glen Terrace
- ; San Diego, CA 92131
- ; 619-566-6810
- ;------------------------------------------------------------
- ; Updates for Version 7.00 6 Oct 87
- ;
- ; Kepa Zubeldia
- ; Micro Consulting, Inc.
- ; 1650 Citizens Tower Bldg.
- ; Oklahoma City, OK 73106
- ; (405) 528-8133
- ;
- ; -Added a pop-up window that allows the control of the redirection from within
- ; an application program.
- ; -Added a switch for monochrome screens combined with color cards, to cancel
- ; the color generation and make the window more visible.
- ; -Deleted the Control-Z that was appended on the last close to a file.
- ; -Allow for file append when the program is called with the name of a file
- ; that already exists. The user still has the option of overwriting the file.
- ; -Added a switch to perform the append automatically.
- ; -Corrected the -? switch so it works.
- ; -Assembled with Microsoft MASM V5.0
- ;
- ; The major change is the addition of the pop-up window. The code for this was
- ; taken from PC Magazine, October 13, 1987, page 401, a productivity utility
- ; written by Jeff Prosise. It works with CGA, MGA, and EGA. With the EGA it
- ; will also work in 120 cols. and/or 35 or 43 line modes. Exiting the pop-up
- ; with an EGA leaves the cursor in underline. This is not a bug, but a feature.
- ;
- ; The pop-up window lets you turn redirection on and off from within a
- ; running program. You first must start LPTx from the command line as
- ; usual :
- ;
- ; lptx output.fil
- ;
- ; Then you can press Alt-PrtSc and a pop-up window will appear. When it
- ; does, the up and down arrow keys select a printer and the right and
- ; left arrow keys select redirection. The pop-up will state "to file"
- ; or "to printer" indicating the state of the redirection.
- ;
- ; Press <Enter> or <Esc> to close the window.
- ;
- ; Remember that you must start LPTx from the command line before the
- ; pop-up will let you turn redirection on or off.
- ;
- ;------------------------------------------------------------
- ; Updates for Version 6.00 18 Mar 87
- ;
- ; Added use of Timer Interrupt and Idle interrupt to permit
- ; writing to disk
- ;
- ; Added a switch to inhibit the output of linefeed characters when
- ; capturing a file. Program strips linefeed character at the
- ; end of the line if you turn on this switch. The switch is -l on the
- ; command line when you open a capture file.
- ;
- ; This version does not use the PSP swapping of previous versions.
- ;
- ;------------------------------------------------------------
- ; Updates for Version 5.02 19 Nov 86
- ;
- ; Added -i inactivate option. Must be only option on command line :
- ; lptx -i
- ;
- ; This version adds a check for DOS interuupt 21h
- ; function 40h for standard printer device = 0004.
- ;
- ; This addition was suggested by Dale Letterman of Seattle.
- ;
- ; Assembled using MicroSoft MASM v 4.0
- ;
- ; Program is called and used in the same way as version 3.00
- ;
- ; I now enter DOS with interrupts disabled.
- ;
- ; Added a switch to inhibit the checking of the Critical Section Flag
- ; Add -x to the command line the first time that you run LPTx.
- ;
- ;------------------------------------------------------------
- ; Updates for Version 5.00 13 May 86
- ;
- ; This version also takes over the DOS interuupt 21h and specifically
- ; checks for function 5.
- ; If that is the call, LPTx captures the character if LPTx has been
- ; activated. If it is a DOS call, LPTx assumes that DOS wants LPT1 since
- ; there is no way for the DOS call to specify a line printer number.
- ;
- ; Uses undocumented DOS int 21h calls 50h and 51h.
- ; 50h Set new current Program Segment Prefix(PSP) from
- ; segment number in BX
- ; 51h Get current PSP into BX.
- ; These calls are used before any file is opened by the resident portion
- ; of LPTx. There is some concern that DOS puts information about open files
- ; into the current PSP. Before we open our spooler file, we want to set
- ; the current PSP to our PSP and then restore it after the file I/O
- ; is complete. This idea was expressed in PC Magazine May 13, 1986 on page
- ; 314 in an article by Charles Petzold.
- ;
- ;
- ; This version 5.0 does not obsolete versions 4.0 and 3.0. Those versions
- ; may work under some conditions where this one does not and vica versa.
- ;------------------------------------------------------------
- ; Updates for Version 4.01 5 May 86
- ;
- ; Had an error in the way LPTx detected if it was already in memory.
- ; This error existed from back in version 3.00 and may have been
- ; the cause of this program locking up the system the very first
- ; time it was called.
- ;------------------------------------------------------------
- ; Updates for Version 4.0 25 April 86
- ;
- ; Assembled using MicroSoft MASM v 4.0
- ;
- ; Program is called and used in the same way as version 3.00
- ;
- ; Modified the code to check if DOS was running when the print interrupt
- ; occurs. If so the print request is routed back to the regular line
- ; printer. This will limit the use of this capture program to user
- ; programs which do their own output without going to DOS.
- ;
- ; In turn, this guarantees that we do re-enter DOS.
- ;
- ; The trick of saving the DOS stack was dropped in this version and
- ; I have resorted to another trick which I garnered from the
- ; following message found on info-ibmpc. I use method number 2.
- ;
- ; This version 4.0 does not obsolete version 3.0. That version may
- ; work under some conditions where this one does not and vica versa.
- ; This one worked fine for me using DOS 2.1 and 123 version 1.A.
- ; Will not work with Shift PrtSc.
- ;
- comment *
- Date: Thu, 30 Jan 86 08:47:51 est
- Subject: File I/O from resident programs
- To: allegra!seismo!usc-isib.arpa!info-ibmpc
-
- Regarding opening up a file when you are terminate-and-stay-resident:
-
- Be very careful when you attempt this. Many an FAT has been eaten for
- lunch when I first tried doing it. Two ways that work like a charm:
-
- 1) Take over interrupt 0x28. This interrupt gets called by DOS
- while its waiting for a key to be hit. Whenever it does get
- called (your program should not be time critical, btw, as
- this routine is never called from CPU intensive tasks), it
- is safe to do with DOS what you will. (Except for certain
- interruptions, such as Search First and Search Next, which
- either you'll screw-up for the foreground task, or they'll
- screw-up for you.)
-
- 2) Get the Critical Section Flag by issuing an int 21, with ah=0x34.
- This returns a pointer to a flag in ES:BX. When this flag is
- NULL, and interrupts are on, it is safe to play DOS games.
- Unless you are the last program to take over the interrupt,
- don't trust the flag word: many "fine" programs like SideKick
- do not give you a true copy of the flag word on the stack, but
- rather give a simple "pushf" after interrupts are turned off.
- * ;end of comment
- ;
- ; More information from a message posted on USENIX:
- ;
- comment *
- From sdcsvax!ihnp4!timeinc!greenber Mon Jul 1 05:12:16 1985
- Date: 30 Jun 85 17:12:37 CDT (Sun)
- -----------------------------------------------------------
- INT 21 - Internal - Return CritSectFlag Pointer (MSDOS generic)
- REG AH = 34H
- On Return:
- ES:BX points to DOS "Critical Section Flag"
- When byte pointed to is zero, DOS is supposed to be
- safe to interrupt. NOT RELIABLE according to Chris
- Dunford.
- Examination of DOS 2.10 code in this area
- indicates that the byte immediately FOLLOWING this
- "Critical Section Flag" must be 00 to permit the
- PRINT.COM interrupt to be called. This suggests that
- checking the WORD pointed to, rather than the BYTE,
- might increase reliability of the test greatly.
- -----------------------------------------------------------
- INT 28 - Internal routine for MSDOS
- This interrupt is called from inside the "get input
- from keyboard" routine in DOS, if and only if it is safe to use
- INT 21 to access the disk at that time. It is used primarily by
- the PRINT.COM routines, but any number of other routines could
- be chained to it by saving the original vector, and calling it
- with a FAR call (or just JMPing to it) at the end of the new
- routine.
- Until PRINT.COM installs its own routine, this
- interrupt vector simply points to an IRET opcode.
- -----------------------------------------------------------
- * ;end of comment
- ;
- ;------------------------------------------------------------
- ; Updates for Version 3.0
- ;
- ; This version is fully compatible with IBM's PRINT command and
- ; hopefully most other print spoolers. I changed the method by which
- ; LPTx determines if a resident copy of itself is already in memory.
- ;
- ;------------------------------------------------------------
- ; This program intercepts the BIOS interrupt 17, the line printer
- ; interrupt. It will redirect the output of LPT1, LPT2, or LPT3 to a disk
- ; file. All three redirects may be active at the same time.
- ;
- ;
- ; Background:
- ;
- ; The basic problem with this type of program is that PC-DOS as written
- ; by Microsoft is not re-entrant. That means that if DOS is in control when
- ; the print interrupt occurs, you can not call DOS again to do some other
- ; function. Therefore, LPTx can not call DOS to write the captured print
- ; data to disk. Version 3.00 of LPTx tries to get around this by making
- ; PC-DOS re-entrant. Version 4.00 of LPTx gets around this by not ever
- ; trying to re-enter DOS.
- ;
- ;*******This Program Must be Converted to a .COM file before running ******
- ; Assemble with :
- ; masm lptx;
- ; link lptx;
- ; exe2bin lptx,lptx.com
- ; erase lptx.obj
- ; erase lptx.exe
- ;
- ;-----------------------------------------------------------------
- .list
- if1
- %out Pass 1 - Including Macros - v6.00
- ;
- .xlist
- ;-----------------------------------------------------------------
- ;
- ; Macros
- ;
- display macro msg
- mov DX,offset msg
- mov AH,DISPLAY_OUTPUT
- int DOS_CALL
- endm
- ;
- ; For the PC-AT:
- ; POPF macro described in the IBM Personal Computer
- ; Seminar Proceedings Volume 2, Number 4 September 1984
- ; QUOTE
- ; "If the system microprocessor executes a POPF instruction in either
- ; the real or the virtual address mode with CPL <= IOPL, then a
- ; pending maskable interrupt (the INTR pin active) may be improperly
- ; recognized after executing the POPF instruction even if maskable
- ; interrupts were disabled before the POPF instruction and the value
- ; popped had IF=0. If the interrupt is improperly recognized, the
- ; interrupt is still correctly executed. This errata has no effect
- ; when interrupts are enabled in either real or virtual address mode.
- ; The errata has no effect in the virtual address mode when
- ; CPL > IOPL."
- ;
- popff macro ;use POPFF instead of POPF
- local popem,skip
- ;simulate popping flags using IRET
- jmp short skip ;jump around iret
- popem:
- iret ;pop CS,IP,flags
- skip:
- push CS
- call popem ;call within segment
- ;program will continue here
- endm
-
- ;
- call_dos macro ;Enter DOS with interrupts disabled
- cli
- int DOS_CALL
- sti
- endm
- ;
- ;
- .list
- else
- %out Pass 2
- endif
- ;-----------------------------------------------------------------
- NULL equ 0
- OFF equ 0
- ON equ 1
- EMPTY equ 0
- BEL equ 7
- CR equ 13
- LF equ 10
- DOLLAR equ '$'
- COLON equ ':'
- BACKSLASH equ '\'
- BLANK equ ' '
- DASH equ '-'
- DOS_CALL equ 21h
- ;
- REQ equ 00B91h ;LPTx request flag
- ACK equ 0ABCBh ;LPTx acknowledge flag
- ;
- BUFSIZE equ 4096 ;size of DMA buffer
- DISPLAY_OUTPUT equ 9 ;for DOS call
- DEF_DRIVE equ 19h
- CREATE_FILE equ 3Ch
- OPEN_FILE equ 3Dh
- CLOSE_FILE equ 3Eh
- WRITE_FILE equ 40h
- DELETE_FILE equ 41h
- LSEEK_FILE equ 42h
- DEF_PATH equ 47h
- FIND_FILE equ 4Eh
- ;-----------------------------------------------------------------
- ;
- p_block struc
- ;
- ; data structure - these variables are used only in the
- ; memory resident copy of LPTx. BX is set to point to the offset of the
- ; allocation of this structure for the selected LPT
- ; NOTE : all of the labels in this structure are required as place
- ; holders even if not referenced. Used by the initialization calls
- ; later on.
- ;
- active db OFF ;ON = this LPTx is on, OFF = off
- handle dw NULL ;handle of disk file used by this LPT
- filen db 'a:\lptx' ;space for redirection disk file name
- pnum db '0' ;default to '0' just in case
- db '.lst',NULL
- db ' '
- db ' '
- bufcntr dw EMPTY ;bytes used in DMA buffer for this LPT
- request db OFF ;ON indicates a write request is active
- ;for this LPT
- prt_status db 10h ;printer status for this LPT
- linefeed db ON ;ON = output a linefeed
- ;OFF = don't output a linefeed
- buffer db BUFSIZE dup(0) ;data buffer for this LPT
- ;
- p_block ends
- ;
- ;-----------------------------------------------------------------
- ;
- bios_data segment at 40h
- org 4Ah
- crt_cols dw ? ;number of display columns
- org 4Eh
- crt_start dw ? ;video page offset address
- org 63h
- addr_6845 dw ? ;CRTC base address
- org 87h
- infobyte label word
- ega_info db ? ;EGA info byte
- bios_data ends
- ;
- ;-----------------------------------------------------------------
- ;
- subttl Main Code
- page
- %out Assembling CODE Segment
- cseg segment para public 'CODE'
- assume CS:cseg,DS:nothing,SS:nothing
- org 100h
- lptx: jmp lptx_start
- ;
- ; What follows are three allocations of the Structure p_block
- ; One for each line printer that we can support.
- ; With this, all three line printers have DMA buffers and flag
- ; variables.
- ; BX is used to point to the offset of the allocation currently in use
- ; Line printer 1
- lpt1 p_block <,,,'1'>
- ; Line printer 2
- lpt2 p_block <,,,'2'>
- ; Line printer 3
- lpt3 p_block <,,,'3'>
- ;
- crit_flag db OFF ;set to ON if critical error occured
- off_crit dw 0 ;save old critical error address
- seg_crit dw 0
- ;
- csect_off dw 0 ;pointer to Critical Section flag
- csect_seg dw 0
- cerrf_off dw 0 ;pointer to Critical Error flag
- cerrf_seg dw 0
- ; cs_switch can be cleared by the transient copy of LPTx
- cs_switch db ON ;enable check of Critical Section flag
- P_NORMAL equ 90h ;Printed selected and ready
- P_TIMEOUT equ 01h ;Time out
- save_psp dw 0 ;Save area for User's PSP Segment Address
- lptx_psp dw 0 ;Our PSP Segment Address
- byte_count dw 0 ;to save DOS byte count
- busy db OFF ;ON indicates write is taking place
- sound db OFF ;ON uses speaker to indicate progress of LPTx
- ;
- flag_10h db 0 ;status of interrupt 10h
- flag_13h db 0 ;status of interrupt 13h
- request_popup db 0 ;status of processing request
- adapter db 2 ;0=MDA, 1=CGA, 2=EGA
- ;The following 5 lines MUST not be changed. They are dynamically set at Run Time
- video_segment dw 0B800h ;video segment address
- border_attr db ? ;window border attribute
- text_attr db ? ;window text attribute
- menu_attr db ? ;menu line attribute
- video_page db ? ;current video page
- cursor_mode dw ? ;cursor shape
- cursor_pos dw ? ;cursor position
- cursor_addr dw ? ;cursor CRTC address
- new_cursor dw 0607h ;Popup cursor shape
- nocolors db 0 ;monochrome only
- menu_choice db 0 ;popup cursor line (0,1,2)
- screen_buffer db 48 dup('SCREEN BUFFER ') ;10 * 34 * 2 bytes
- color_attr db 0,0B8h,10h,07h,3fh ;black/blue,white/black,hi-white/blue
- nocolor_attr db 0,0B8h,70h,07h,70h ;mono
- mono_attr db 0,0B0h,70h,07h,70h
- enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
- ;
- ; Old interrupt vector addresses
- old_08h dd 0 ;address of old int 08h routine
- old_09h dd 0 ;address of old int 09h routine
- old_10h dd 0 ;address of old int 10h routine
- old_13h dd 0 ;address of old int 13h routine
- old_17h dd 0 ;address of old int 17h routine
- old_21h dd 0 ;address of old int 21h routine
- old_28h dd 0 ;address of old int 28h routine
- ;
- old1Bh_segment dw ? ;old interrupt 1Bh segment
- old1Bh_offset dw ? ;old interrupt 1Bh offset
- old23h_segment dw ? ;old interrupt 23h segment
- old23h_offset dw ? ;old interrupt 23h offset
- old24h_segment dw ? ;old interrupt 24h segment
- old24h_offset dw ? ;old interrupt 24h offset
- ;
- ; New Stack for Interrupt 17h
- stk1_save dd 0 ;caller's stack EA
- db 128 dup('STACK ')
- stk1 equ this byte - 4
- ; New Stack for Interrupts 08h and 28h
- stk2_save dd 0 ;caller's stack EA
- db 128 dup('STACK ')
- stk2 equ this byte - 4
- ; New Stack for Popup window process
- stk3_ss dw 0 ;caller's stack EA
- stk3_sp dw 0
- db 128 dup('STACKP ')
- stk3 equ this byte - 4
- ;
- ;------------------------------------------------------------------------------
- ; Window text
- ;------------------------------------------------------------------------------
- ;
- ;You will need an editor capable of handling graphics to edit the window.
- ;I used PC-Write, but old edlin will also work.
- ;Do not change the width or the depth of the window !!!
- ;
- window db "┌──────────────LPTX──────────────┐"
- db "│ │"
- menuline1 db "│ lpt1: to PRINTER │"
- menuline2 db "│ lpt2: to PRINTER │"
- menuline3 db "│ lpt3: to PRINTER │"
- db "│ │"
- db "├────────────────────────────────┤"
- db "│ Press: to move, to toggle,│"
- db "│ <Enter> to close window. │"
- db "└────────────────────────────────┘"
- menufile1 db "│ lpt1: to FILE │"
- menufile2 db "│ lpt2: to FILE │"
- menufile3 db "│ lpt3: to FILE │"
- ;------------------------------------------------------------------------------
- ; Interrupt handler for interrupt 09h (keyboard)
- ;------------------------------------------------------------------------------
- ;
- keyboard proc near
- push ax
- cmp CS:busy,OFF ;program already active?
- jne kb_regular ; yes, skip processing this key.
- in al,60h ;look at the hardware register
- cmp al,55 ;is this PrtSc ?
- jne kb_regular ; no, process it the old way.
- sti ;set interrupt enable flag
- mov ah,2 ;get keyboard shift status
- int 16h
- test al,8 ;Alt key also pressed?
- je kb_regular ; no, process old way.
- mov CS:request_popup,18 ;set request flag for 1 second.
- ;now, call keyboard handling routine
- ; to reset keyboard controller
- ; and as courtesy to other TSRs.
- kb_regular: pop ax
- jmp dword ptr CS:old_09h
- keyboard endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 10h handling routine.
- ;------------------------------------------------------------------------------
- video proc near
- pushf ;push flags onto stack
- inc flag_10h ;increment flag
- call dword ptr CS:old_10h ;call BIOS routine
- dec flag_10h ;decrement flag
- iret
- video endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 13h handling routine.
- ;------------------------------------------------------------------------------
- bdisk proc far
- pushf ;push flags onto stack
- inc flag_13h ;set 'busy' flag
- call dword ptr CS:old_13h ;call BIOS routine
- pushf ;save output flags
- dec flag_13h ;clear flag
- popff ;restore output flags
- ret 2 ;exit without destroying flags
- bdisk endp
- ;
- ;
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 17h
- ;
- int_17h proc far
- sti ;interrupts on
- cmp AH,3 ;AH=3 for LPTx Function
- jne reg_call ;This is a regular print call
- jmp ret_ack ;This is an LPTx Call
- reg_call:
- push BX
- ; set up BX to point to the data area for the requested printer
- cmp DX,0 ;lpt1?
- jne chk_lpt2 ;no
- mov BX,offset lpt1 ;offset to LPT1
- jmp short bx_set
- chk_lpt2:
- cmp DX,1 ;lpt2?
- jne chk_lpt3 ;no
- mov BX,offset lpt2 ;offset to LPT2
- jmp short bx_set
- chk_lpt3:
- cmp DX,2 ;lpt3?
- jne ill_ptr ;no - bad printer number
- mov BX,offset lpt3 ;offset to LPT3
- bx_set:
- cmp CS:[BX].active,OFF ;are we active?
- je sleep17 ;no
- mov CS:[BX].prt_status,P_NORMAL ;signal ready status
- cmp AH,1 ;initialize call?
- je do_nix ;yes
- cmp AH,2 ;status call?
- je do_nix ;yes
- cmp AH,0 ;print call?
- jne do_nix ;no
-
- jmp prt_17 ;we are active
- do_nix: mov AH,CS:[BX].prt_status ;return print status
- rtn: pop BX
- iret
- ;
- ill_ptr:mov CS:[BX].prt_status,P_TIMEOUT ;time out status
- jmp do_nix
- ;
- ret_ack: ;return acknowledgement that I'm here
- ; note : Change REQ & ACK from version to version so two versions
- ; of LPTx don't get intermixed.
- cmp DX,REQ ;my flag to detect that LPTx is
- ;already loaded and alive.
- jne ret_nak ;return a NAK
- mov DX,ACK ;Memory resident LPTx answers with ACK
- push CS ;now set up ES to point to the resident
- pop ES ; data area
- ret_nak:
- iret ;return to calling program
- ;
- sleep17:pop BX ;restore BX before we go to sleep
- jmp dword ptr CS:old_17h ;jump immediate to original handler
- ;
- prt_17:
- push AX ; Start the print process.
- push BX ; Character is in AL.
- push CX
- push DX
- push DS
- push ES
- push SI
- push DI
- push BP
- ;
- push CS ; DS is used as the segment register
- pop DS ; for all data during the interrupt
- ;
- pushf
- cli
- mov SI,SS
- mov word ptr DS:stk1_save+2,SI ;save caller's stack pointer
- mov SI,SP
- mov word ptr DS:stk1_save,SI
- mov SI,CS
- mov SS,SI ;give me new bigger stack
- mov SI,offset stk1
- mov SP,SI
- popff
- mov DS:[BX].prt_status,P_NORMAL ;signal ready status
- ;prt_status is set before
- ;the call to prnt so that prnt
- ;can change it if the print to
- ;disk fails
- call prnt ;print the character
- ;
- pushf
- cli
- mov SI,word ptr DS:stk1_save
- mov SP,SI ;restore caller's stack pointer
- mov SI,word ptr DS:stk1_save+2
- mov SS,SI
- popff
-
- pop BP
- pop DI
- pop SI
- pop ES
- pop DS
- pop DX
- pop CX
- pop BX
- pop AX
- jmp do_nix
- int_17h endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 21h
- ;
- int_21h proc far
- sti ;interrupts on
- push BX
- cmp AH,5 ;is this a DOS printer call?
- je int_21h_5 ;yes
- cmp AH,40h ;is this a DOS write call?
- je int_21h_40 ;yes
- jmp sleep21 ;no - go on to real DOS
- ; DOS Function 40h - Write to File or Device. DS:DX contains the address
- ;of data to write. CX contains the byte count. Return AX = byte count.
- int_21h_40:
- cmp BX,0004 ;Standard Printer?
- jne sleep21 ;no - go on to real DOS
- ; set up BX to point to the data area for the requested printer
- ; Since we don't know what the standard printer device is, we
- ; use LPT1
- mov BX,offset lpt1 ;offset to LPT1
- cmp CS:[BX].active,OFF ;are we active?
- je sleep21 ;no
- push AX ;now do it
- push BX
- push CX
- push DX
- mov CS:byte_count,CX ;save byte count
- mov BX,DX
- ;DS:BX points to buffer, CX has byte count
- cmp CX,EMPTY ;check for zero byte count
- je prt_21_done
- loop21_40:
- mov AL,[BX] ;get a character
- mov AH,0 ;set up for call to interrupt 17h
- int 17h ;note : int17h returns a printer status
- ;in AH but DOS does not define a way
- ;to return that status
- inc BX
- loop loop21_40
- prt_21_done:
- pop DX
- pop CX
- pop BX
- pop AX
- mov AX,CS:byte_count ;DOS returns byte count
- jmp exit21 ;to return it to the user.
- ;
- int_21h_5:
- ; DOS Function 5 Printer Output. The Character in DL is output to the
- ; standard printer device.
- ;
- ; set up BX to point to the data area for the requested printer
- ; Since we don't know what the standard printer device is, we
- ; use LPT1
- mov BX,offset lpt1 ;offset to LPT1
- cmp CS:[BX].active,OFF ;are we active?
- je sleep21 ;no
-
- push AX
- mov AH,0 ;set up for call to interrupt 17h
- mov AL,DL ;the character
- int 17h
- pop AX
- ;note : int17h returns a printer status
- ;in AH but DOS does not define a way
- ;to return it to the user.
- exit21: pop BX
- popff ;restore flags
- clc ;never an error from us
- ret ;return to caller (regular FAR return)
- ;
- sleep21:pop BX ;restore BX before we go to sleep
- jmp dword ptr CS:old_21h
- int_21h endp
- ;
- ;-----------------------------------------------------------------
- ;
- ; PRNT - Print a character in AL
- ;
- prnt proc near
- push DS
- cmp DS:[BX].active,OFF
- je prtext ;nothing there?
- push AX
- cmp DS:[BX].bufcntr,BUFSIZE/2 ;buffer half full?
- jne intadd ;no
- ;
- ; set write request but don't actually write anything out.
- ; we hope that the write can take place before the buffer fills up
- ;
- mov DS:[BX].request,ON
- cmp DS:sound,OFF ;sound on?
- je intadd ;no
- call horn ;sound horn to indicate buffer
- ; write request has been made
- ;
- intadd: pop AX
- cmp AL,LF ;is it a linefeed?
- jne intnolf ;no
- cmp DS:[BX].linefeed,OFF ;we are stripping linefeeds?
- je prtext ;yes
- intnolf:
- mov DI,BX ;offset of this printer's allocation
- add DI,offset lpt1.buffer ;add in offset of buffer
- add DI,DS:[BX].bufcntr ;add in current byte count
- mov DS:[DI],AL ;stuff it
- inc DS:[BX].bufcntr
- cmp DS:[BX].bufcntr,BUFSIZE ;buffer overflow?
- jne prtext ;no
- mov DS:[BX].active,OFF ;yes, nothing to do but deactivate
- ; LPTx
- cmp DS:sound,OFF ;sound on?
- je prtext ;no
- call beep ;sound beep twice to indicate that
- call beep ;we have been deactivated
- prtext: pop DS
- ret ;done
- prnt endp
- ;-----------------------------------------------------------------
- ;
- ; Critical Error Handler
- ;
- crit_int proc far ;got critical error
- mov CS:crit_flag,ON ; set flag
- mov AL,0 ;tells DOS to ignore the
- iret ;error
- crit_int endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 08h - clock ticks
- ;
- ; This function is installed as a handler for hardware interrupt
- ; type 8. It first calls the previous int 08h handler to service
- ; the INTEL 8259 Programmable Interrupt Controller. Then it checks
- ; to see if any write requests are pending. If so, it calls do_save
- ; and flush to write the buffer to the disk. Note that int_08h
- ; checks the DOS critical section flag : do_save is called only if
- ; DOS is available.
- ;
- ; This function protects itself against secondary invocations by
- ; means of the global busy flag.
- ;
- int_08h proc far
- ; call original int 8h handler - ALWAYS
- pushf
- call dword ptr CS:old_08h
- ; now we can process if possible
- pushf
- cli
- cmp CS:busy,OFF ;can we process this?
- jne i08_exit ;no
- cmp CS:flag_10h,0 ;video flag set?
- jne dectime ;yes, then exit
- cmp CS:flag_13h,0 ;disk flag set?
- jne dectime ;yes, then exit
- ; if DOS is in its critical section, we skip the write for now and
- ; hope that we can write before the buffer fills
- push DS ; check the critical section flag
- push SI
- push BX
- cmp CS:cs_switch,OFF ;is checking off?
- je no_cs ;yes, don't check the flag
- lds SI,dword ptr CS:csect_off
- cmp byte ptr [SI],OFF
- jne poptime ;DOS in critical section
- ;this indicates that we cannot
- ;do any disk operations at this
- ;time
- lds SI,dword ptr CS:cerrf_off
- cmp byte ptr [SI],OFF
- jne poptime ;DOS in critical error
- ;this indicates that we cannot
- ;do any disk operations at this
- ;time
- no_cs:
- cmp CS:request_popup,0
- je no_popup
- call do_popup
- no_popup:
- mov BX,offset lpt1 ;offset to LPT1
- cmp DS:[BX].request,ON ;write LPT1 request?
- jne no_lpt1 ;no
- call do_save
- no_lpt1:
- mov BX,offset lpt2 ;offset to LPT2
- cmp DS:[BX].request,ON ;write LPT2 request?
- jne no_lpt2 ;no
- call do_save
- no_lpt2:
- mov BX,offset lpt3 ;offset to LPT3
- cmp DS:[BX].request,ON ;write LPT3 request?
- jne poptime ;no
- call do_save
- poptime:
- pop BX
- pop SI
- pop DS
- dectime:
- cmp request_popup,0
- je i08_exit
- dec request_popup
- i08_exit:
- popff
- iret
-
- int_08h endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 28h - idle
- ;
- ; This function is installed as a handler for hardware interrupt
- ; type 28h. It first calls the previous int 28h handler. Then it checks
- ; to see if any write requests are pending. If so, it calls do_save
- ; and flush to write the buffer to the disk. It does not check the
- ; Critical Section Flag as int 28h handlers are allowed to perform
- ; DOS disk I/O but not keyboard I/O since most of the time int 28h
- ; is called by the keyboard I/O routines when they are waiting
- ; for a key press.
- ;
- ; This function protects itself against secondary invocations by
- ; means of the global busy flag.
- ;
- int_28h proc far
- ; call original int 28h handler - ALWAYS
- pushf
- call dword ptr CS:old_28h
- ; now we can process if possible
- pushf
- cli
- cmp CS:busy,OFF ;can we process this?
- jne i28_exit ;no
- cmp CS:flag_10h,0 ;video flag set?
- jne i28_exit ;yes, then exit
- cmp CS:flag_13h,0 ;disk flag set?
- jne i28_exit ;yes, then exit
- cmp CS:cs_switch,OFF ;is checking off?
- je i28_no_cs ;yes, don't check the flag
- push DS
- push SI
- lds SI,dword ptr CS:cerrf_off
- cmp byte ptr [SI],OFF
- pop SI
- pop DS
- jne i28_exit ;DOS in critical error
- ;this indicates that we cannot
- ;do any disk operations at this
- ;time
- i28_no_cs:
- cmp CS:request_popup,0
- je i28_nopopup
- call do_popup
- i28_nopopup:
- call do_save
- i28_exit:
- popff
- iret
- int_28h endp
- ;-----------------------------------------------------------------
- ;
- do_popup proc near
- mov CS:busy,ON
- mov CS:request_popup,0
- cli
- mov CS:stk3_ss,SS
- mov CS:stk3_sp,SP
- push cs
- pop ss
- mov sp,offset stk3
- sti ;interrupts on
- push AX ; Save everything
- push BX
- push CX
- push DX
- push DS
- push ES
- push SI
- push DI
- push BP
- pushf
- ;
- mov ah,15 ;get video mode and page
- int 10h
- cmp al,3 ;mode 0, 1, 2, or 3?
- jbe pu_main1 ;yes, then continue
- cmp al,7 ;mode 7?
- je pu_main1 ;yes, then continue
- ;no, we must be in graphics, and
- ;I don't know how to open a window
- ;while in graphics...
- ;
- ;Restore registers and stack before exit.
- ;
- do_pop_exit:
- popff
- pop BP
- pop DI
- pop SI
- pop ES
- pop DS
- pop DX
- pop CX
- pop BX
- pop AX
- cli
- mov ss,CS:stk3_ss
- mov sp,CS:stk3_sp
- sti ;interrupts on
- mov CS:busy,OFF
- ret
- ;
- ;Set DS and ES segment registers.
- ;
- pu_main1: push cs ;set DS to code segment
- pop ds
- assume ds:cseg
- mov ax,bios_data ;point ES to BIOS data
- mov es,ax
- assume es:bios_data
- cmp crt_cols,80 ;at least 80 columns displayed?
- jb do_pop_exit ;no, then exit
- ;
- ;Save needed video parameters.
- ;
- mov video_page,bh ;active video page
- mov ah,3 ;get cursor mode and location
- int 10h
- mov cursor_mode,cx
- mov cursor_pos,dx
- mov dx,addr_6845 ;get CRTC base address
- push dx ;save it for later
- mov al,14 ;specify register number
- out dx,al
- inc dx ;point DX to data port
- in al,dx ;read high byte of address
- mov ah,al ;save it
- dec dx ;back to index register
- mov al,15 ;specify register number
- out dx,al
- inc dx ;back to data port
- in al,dx ;read low byte of address
- mov cursor_addr,ax ;save cursor address
- ;
- ;Determine whether an EGA is present and active in the system.
- ;
- mov ah,12h ;see if EGA is present
- mov bl,10h
- int 10h
- cmp bl,10h ;did BL return unchanged?
- je pu_main2 ;yes, then there's no EGA here
- test ega_info,8 ;is the EGA currently active?
- jnz pu_main2 ;no, then branch
- mov adapter,2 ;set ADAPTER for EGA
- push bx ;save BX
- mov ax,1130h ;get number of scan lines per char
- int 10h
- dec cl ;form cursor definition in CX
- mov ch,cl
- sub ch,2
- mov new_cursor,cx ;save cursor definition
- mov si,offset color_attr ;point SI to color parms
- pop bx ;retrieve BX
- or bh,bh ;EGA attached to color monitor?
- je pu_hascolor ;yes, then branch
- mov si,offset mono_attr ;no, then point SI to mono parms
- jmp short pu_main4
- pu_hascolor: cmp nocolors,0 ;use monochrome only ?
- je pu_main4 ; no, use color
- mov si,offset nocolor_attr ;color card with mono screen
- jmp short pu_main4
- ;
- ;Determine whether the active video adapter is a CGA or an MDA.
- ;
- pu_main2: test addr_6845,40h ;is bit 6 of the CRTC address set?
- jz pu_main3 ;no, then it's monochrome
- mov adapter,1 ;set ADAPTER for a CGA
- mov new_cursor,0607h ;define cursor shape
- mov si,offset color_attr ;point SI to color parms
- jmp short pu_hascolor
- pu_main3: mov adapter,0 ;set ADAPTER for an MDA
- mov new_cursor,0B0Ch ;define monochrome cursor
- mov si,offset mono_attr ;point SI to mono parms
- ;
- ;Set video parameters for color or monochrome.
- ;
- pu_main4: push cs ;set ES to the code segment
- pop es
- assume es:cseg
- mov di,offset video_segment ;point DI to destination
- mov cx,5 ;5 bytes to move
- cld ;clear DF
- rep movsb ;transfer the values
- ;
- cmp adapter,1 ;disable CGA video
- jne pu_main7
- call disable_cga
- pu_main7: call save_screen ;save memory to be overwritten
- call make_screen ;open the Pop-up window
- call make_status ;update status of the redirection
- cmp adapter,1 ;enable CGA video
- jne pu_main8
- call enable_cga
- pu_main8: mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- ;
- ;Wait for a keystroke and return when ESC is pressed.
- ;
- pu_mainA: call getkey ;wait for a keypress
- or al,al ;extended code entered?
- je pu_main12 ;yes, then branch
- cmp al,32 ;SPACE pressed?
- je toggle ;yes, toggle line
- cmp al,13 ;ENTER pressed?
- je escape ;yes, then get out
- cmp al,27 ;ESC pressed?
- je escape ;yes, then close window and return
- jmp pu_mainA ;no, then ignore keypress
- ;
- ;An extended code was entered. Check for an Alt-character key combination.
- ;
- pu_main12: cmp ah,72 ;UpArrow?
- je upone ;yes, then process it
- cmp ah,80 ;DownArrow?
- je downone ;yes, then process it
- cmp ah,75 ;LeftArrow?
- je toggle ;toggle line
- cmp ah,77 ;RightArrow?
- je toggle ;toggle line
- jmp pu_mainA ;return for another keypress
- ;
- upone: cmp menu_choice,0 ;are we at the top ?
- jne upone1 ; no, decrement it
- mov menu_choice,3 ; yes, wrap around
- upone1: dec menu_choice
- call make_status ;update status of the redirection
- jmp pu_mainA
-
- downone: cmp menu_choice,2 ;are we at the bottom ?
- jne downone1 ; no, increment
- mov menu_choice,-1 ; yes, wrap around
- downone1: inc menu_choice
- call make_status ;update status of the redirection
- jmp pu_mainA
-
- toggle: call make_change ;change the state
- call make_status ;update status of the redirection
- jmp pu_mainA
- ;
- ;Close the Pop-up window in preparation for return.
- ;
- escape:
- cmp adapter,1 ;disable CGA video
- jne esc1
- call disable_cga
- esc1: call restore_screen ;restore screen contents
- cmp adapter,1 ;enable CGA video
- jne esc2
- call enable_cga
- ;
- ;Restore the cursor's former position in the BIOS data area and the CRTC.
- ;
- esc2: mov ah,2 ;set cursor position thru BIOS
- mov bh,video_page
- mov dx,cursor_pos
- int 10h
- pop dx ;recover CRTC base address
- mov cx,cursor_addr ;restore cursor address
- mov al,14 ;CRTC register number
- out dx,al
- inc dx
- mov al,ch
- out dx,al ;write high byte of address
- dec dx
- mov al,15 ;CRTC register number
- out dx,al
- inc dx
- mov al,cl
- out dx,al ;write low byte
- ;
- ;Display the cursor, bypassing EGA cursor emulation logic, and return.
- ;
- cmp adapter,2 ;EGA on board?
- jne esc3 ;no, then branch
- call show_cursor ;retain current shape
- jmp do_pop_exit ; exit from popup
- esc3: mov ah,1 ;restore cursor shape
- mov cx,cursor_mode
- int 10h
- jmp do_pop_exit ; exit from popup
- do_popup endp
- ;
- ;------------------------------------------------------------
- ;
- ; Writes buffer to disk
- ;
- do_save proc near
- mov CS:busy,ON ; set busy flag
- push AX ; Start the print process.
- push BX ; Character is in AL.
- push CX
- push DX
- push DS
- push ES
- push SI
- push DI
- push BP
- pushf
- sti ;interrupts on
- ;
- push CS ; DS is used as the segment register
- pop DS ; for all data during the interrupt
- ;
- pushf
- cli
- mov SI,SS
- mov word ptr DS:stk2_save+2,SI ;save caller's stack pointer
- mov SI,SP
- mov word ptr DS:stk2_save,SI
- mov SI,CS
- mov SS,SI ;give me new bigger stack
- mov SI,offset stk2
- mov SP,SI
- popff
- ;
- ; check to see if any write requests are active.
- ; we do not look at the active flag since the print redirection
- ; may have been inactivated by the time, we are able to write to
- ; the disk.
- ;
- ; set up BX to point to the data area for the requested printer
- mov BX,offset lpt1 ;offset to LPT1
- cmp DS:[BX].request,ON ;write LPT1 request?
- jne c28_lpt2 ;no
- call flush
- mov DS:[BX].request,OFF
- c28_lpt2:
- mov BX,offset lpt2 ;offset to LPT2
- cmp DS:[BX].request,ON ;write LPT2 request?
- jne c28_lpt3 ;no
- call flush
- mov DS:[BX].request,OFF
- c28_lpt3:
- mov BX,offset lpt3 ;offset to LPT3
- cmp DS:[BX].request,ON ;write LPT3 request?
- jne i28_done ;no
- call flush
- mov DS:[BX].request,OFF
- i28_done:
- pushf
- cli
- mov SI,word ptr DS:stk2_save
- mov SP,SI ;restore caller's stack pointer
- mov SI,word ptr DS:stk2_save+2
- mov SS,SI
- popff
- ;
- popff
- pop BP
- pop DI
- pop SI
- pop ES
- pop DS
- pop DX
- pop CX
- pop BX
- pop AX
- mov CS:busy,OFF
- ret
- do_save endp
- ;
- ;------------------------------------------------------------
- ;
- ; FLUSH - Flush print buffer to disk file
- ;
- flush proc near
- cmp DS:[BX].bufcntr,EMPTY ;buffer empty?
- jne flush_buf ;no, write it to disk
- ret ;exit
- flush_buf:
- call disk_out
- ret
- flush endp
- ;------------------------------------------------------------
- ;
- ; DISK_OUT - write to disk
- ;
- disk_out proc near
- ;PSP
- ; push BX
- ; mov AH,51h ;get current PSP
- ; call_dos
- ; mov DS:save_psp,BX ;and save it
- ; mov BX,DS:lptx_psp ;get our PSP
- ; mov AH,50h
- ; call_dos ;set it into DOS
- ; pop BX
- ;
- push ES
- push DS
- mov AX,DS ;set up ES
- mov ES,AX
- push BX
- push ES
- mov AX,3524h ;get old critical error vector
- call_dos
- mov DS:off_crit,BX
- mov DS:seg_crit,ES
- mov DX,offset crit_int
- mov AX,2524h
- call_dos ;trap critical error vector
- mov DS:crit_flag,OFF ;clear critical error flag
- pop ES
- pop BX
- mov DX,BX ;open file
- add DX,offset lpt1.filen ;filename
- mov AL,1 ;open for writing
- mov AH,open_FILE
- call_dos
- mov DS:[BX].handle,AX ;file handle
- jc disk_err ;error
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- push BX
- mov AH,lseek_FILE
- mov AL,2 ;end of file
- mov CX,0 ;offset 0
- mov DX,0
- mov BX,DS:[BX].handle
- call_dos
- pop BX
- jc disk_err ;some seek error
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- mov CX,DS:[BX].bufcntr ;buffer size
- mov DX,BX ;offset of structure allocation
- add DX,offset lpt1.buffer ;add offset of buffer within the
- ; allocation
- push BX
- mov AH,write_FILE
- mov BX,DS:[BX].handle ;file handle
- call_dos ;buffer address is DS:DX
- pop BX
- jnc disk_ok
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- cmp AX,DS:[BX].bufcntr ;did DOS write it all?
- je disk_ok ;yes
- disk_err:
- call beep ;ring bell 4 times
- call beep
- call beep
- call beep
- mov DS:[BX].active,OFF ;turn us off
- mov DS:crit_flag,OFF ;clear error flag
- mov DS:[BX].prt_status,P_TIMEOUT ;signal time out error
- ;then try to close the file
- ;to save what we can
- jmp disk_close
- disk_ok:
- mov DS:[BX].bufcntr,EMPTY ;set buffer empty
- disk_close:
- push BX
- mov BX,DS:[BX].handle
- mov AH,close_FILE ;close the file
- call_dos
- pop BX
- disk_exit:
- pop DS
- pop ES
- push DS
- lds DX,dword ptr DS:off_crit
- mov AX,2524h ;restore critical error vector
- call_dos
- pop DS
- ; PSP
- ; push BX
- ; mov BX,DS:save_psp ;get user's PSP
- ; mov AH,50h
- ; call_dos ;set it back into DOS
- ; pop BX
- ;
- ret
- disk_out endp
- ;
- ;--------------------------------------------------------------
- ;
- ; Routine to sound the beeper
- ;
- note equ 0a98h ;2712 = 1193180. / 440Hz
- beep proc near
- push AX
- push BX
- push CX
- push DX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,note ;get note
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,07FFFh
- beep_lp:loop beep_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,03FFFh
- beep1_lp:loop beep1_lp
- pop DX
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- beep endp
- ;-------------------------------------------------------------------
- ;
- ; Routine to sound a key click
- ;
- key_clk equ 036h ;59 = 1193180. / 20,000Hz
- click proc near
- push AX
- push BX
- push CX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,key_clk ;get note
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,0FFh
- key_lp:loop key_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,0FFh
- key1_lp:loop key1_lp
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- click endp
- ;--------------------------------------------------------------
- ;
- ; Routine to honk the horn
- ;
- horn proc near
- push AX
- push BX
- push CX
- push DX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,2e9bh ;2712 = 1193180. / 100Hz
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,07FFFh
- horn_lp:loop horn_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,03FFFh
- horn1_lp:loop horn1_lp
- pop DX
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- horn endp
- ;--------------------------------------------------------------------
-
- ;------------------------------------------------------------------------------
- ;SAVE_SCREEN saves the contents of the screen that underlie the window.
- ;------------------------------------------------------------------------------
- video_address dw ? ;video address
- linesum dw ?
- ;
- save_screen proc near
- push ds ;save DS
- mov ax,bios_data ;point it to BIOS data area
- mov ds,ax
- assume ds:bios_data
- mov ax,crt_cols ;get number of display columns
- mov linesum,ax ;calculate distance from end of
- sub linesum,34 ; one line to start of next
- shl linesum,1 ; accounting for attribute bytes
- mov bl,6 ;calculate starting addrss (6 lines)
- mul bl ;result in AX
- add ax,18 ;add line offset (18 columns)
- shl ax,1 ;double result for attr bytes
- mov si,ax ;transfer to SI
- add si,crt_start ;add page offset
- mov video_address,si ;save offset address
- mov ds,video_segment ;then set DS to the video segment
- mov di,offset screen_buffer ;point DI to storage buffer
- mov cx,10 ;10 lines to save
- save_screen1: push cx ;save line count
- mov cx,34 ;34 characters per line
- rep movsw ;transfer one line to storage
- pop cx ;retrieve line count
- add si,linesum ;point SI to next video line
- loop save_screen1 ;loop until all lines are saved
- pop ds ;restore DS
- assume ds:cseg
- ret ;exit
- save_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;RESTORE_SCREEN writes the stored screen image to video memory.
- ;------------------------------------------------------------------------------
- restore_screen proc near
- push es ;save ES register value
- mov di,video_address ;point DI to starting video offset
- mov es,video_segment ;point ES to video memory
- mov si,offset screen_buffer ;point DS:SI to screen image
- mov cx,10 ;10 lines to restore
- restore1: push cx ;save line count
- mov cx,34 ;34 characters per line
- rep movsw ;restore one line
- pop cx ;retrieve line count
- add di,linesum ;set DI to next video line
- loop restore1 ;loop until done
- pop es ;restore ES
- ret
- restore_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;MAKE_SCREEN writes an image of the Pop-up window to video memory.
- ;------------------------------------------------------------------------------
- make_screen proc near
- push es ;save ES
- mov es,video_segment ;point ES:DI to video memory
- mov di,video_address
- mov si,offset window ;line 1
- mov cx,34 ;do 34 characters
- mov ah,border_attr ;this makes the top border
- make0: lodsb
- stosw
- loop make0
- add di,linesum
- mov cx,5 ;5 lines of user text
- make1: push cx
- call formline
- add di,linesum
- pop cx
- loop make1
- mov cx,4 ;4 lines of instructions on bottom
- mov ah,border_attr
- make2: push cx
- mov cx,34 ;do next 34 characters
- make3: lodsb
- stosw
- loop make3
- add di,linesum
- pop cx
- loop make2
- pop es ;restore ES
- ret
- make_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;MAKE_STATUS writes the new status of the redirection window to video memory.
- ;------------------------------------------------------------------------------
- make_status proc near
- push es ;save ES
- mov es,video_segment ;point ES:DI to video memory
- mov di,video_address ;this point to the beginning of w.
- add di,34 * 2 ;skip over the text
- add di,linesum ;skip to next line
- add di,34 * 2 ;skip over the text
- add di,linesum ;go down one line
-
- cmp adapter,1 ;disable CGA video
- jne msts0
- call disable_cga
- msts0:
- mov bx,offset lpt1 ;structure #1
- cmp ds:[bx].active,OFF ;printer redirected ?
- mov si,offset menuline1 ; no, text says PRINTER
- je msts1
- mov si,offset menufile1 ; yes, text says FILE
- msts1: cmp menu_choice,0 ;is this the highlighted choice?
- je msts2
- call formline ; no, display normal
- jmp short msts3
- msts2: call cursline ; yes, display highlighted
- msts3: add di,linesum ;go down one line
-
- mov bx,offset lpt2 ;structure #2
- cmp ds:[bx].active,OFF ;printer redirected ?
- mov si,offset menuline2 ; no, text says PRINTER
- je msts4
- mov si,offset menufile2 ; yes, text says FILE
- msts4: cmp menu_choice,1 ;is this the highlighted choice?
- je msts5
- call formline ; no, display normal
- jmp short msts6
- msts5: call cursline ; yes, display highlighted
- msts6: add di,linesum ;go down one line
-
- mov bx,offset lpt3 ;structure #3
- cmp ds:[bx].active,OFF ;printer redirected ?
- mov si,offset menuline3 ; no, text says PRINTER
- je msts7
- mov si,offset menufile3 ; yes, text says FILE
- msts7: cmp menu_choice,2 ;is this the highlighted choice?
- je msts8
- call formline ; no, display normal
- jmp short msts9
- msts8: call cursline ; yes, display highlighted
- msts9:
- cmp adapter,1 ;enable CGA video
- jne msts10
- call enable_cga
- msts10:
- pop es ;restore ES
- ret
- make_status endp
- ;
- ;------------------------------------------------------------------------------
- ;MAKE_CHANGE changes the status of the redirection.
- ;------------------------------------------------------------------------------
- make_change proc near
- push es ;save ES
-
- cmp menu_choice,0 ;is this the highlighted choice?
- jne mkchg1
- mov bx,offset lpt1 ;structure #1
- mkchg1:
- cmp menu_choice,1 ;is this the highlighted choice?
- jne mkchg2
- mov bx,offset lpt2 ;structure #2
- mkchg2:
- cmp menu_choice,2 ;is this the highlighted choice?
- jne mkchg3
- mov bx,offset lpt3 ;structure #3
- mkchg3:
- cmp ds:[bx].active,OFF ;flip printer redirection
- je mkchg4
- mov ds:[bx].active,OFF ;turn redirection OFF
- mov ax,ds:[bx].bufcntr ;look at the buffer size
- or ah,al ;is there something in it ?
- jz mkchg5 ; no, buffer was empty
- mov ds:[bx].request,ON ; yes, request a buffer flush.
- jmp short mkchg5
- mkchg4: mov ax,ds:[bx].handle ;get the file handle to check it
- or ah,al ;if it has ever been used.
- jz mkchg5 ; no, don't activate
- mov ds:[bx].active,ON ; yes, activate redirection
- mkchg5: call click ;give a little noisy feedback
- pop es ;restore ES
- ret
- make_change endp
- ;
- ;------------------------------------------------------------------------------
- ;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
- ;------------------------------------------------------------------------------
- formline proc near
- mov ah,border_attr
- lodsb
- stosw
- mov cx,32 ;do next 32 characters
- mov ah,text_attr
- form1: lodsb
- stosw
- loop form1
- mov ah,border_attr
- lodsb
- stosw
- ret
- formline endp
- ;
- ;
- ;------------------------------------------------------------------------------
- ;CURSLINE is called by MAKE_SCREEN to help with the dirty work.
- ;------------------------------------------------------------------------------
- cursline proc near
- mov ah,border_attr
- lodsb
- stosw
- mov cx,32 ;do next 32 characters
- mov ah,menu_attr
- curs1: lodsb
- stosw
- loop curs1
- mov ah,border_attr
- lodsb
- stosw
- ret
- cursline endp
- ;
- ;
- ;------------------------------------------------------------------------------
- ;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
- ;------------------------------------------------------------------------------
- disable_cga proc near
- mov dx,3DAh ;address of Status Register
- disable1: in al,dx ;get status
- test al,8 ;vertical retrace active?
- je disable1 ;no, then wait
- sub dx,2 ;MSR address in DX
- mov al,25h ;value to disable video
- out dx,al ;disable video output
- ret
- disable_cga endp
- ;
- enable_cga proc near
- mov ah,15 ;get video mode
- int 10h
- mov bx,offset enable_values ;get value to enable display
- xlat ;value in AL
- mov dx,3D8h ;MSR address
- out dx,al ;enable video output
- ret
- enable_cga endp
- ;
- ;------------------------------------------------------------------------------
- ;GETKEY waits for a keypress and returns the keycode in AX.
- ;Exit: AX - keycode
- ;This function is careful to generate int28 for other TSR that may need them
- ;while the user is waiting to press a key.
- ;------------------------------------------------------------------------------
- getkey proc near
- mov ah,1 ;check keyboard buffer
- int 16h
- jne getkey1 ;jump if buffer contains a keycode
- int 28h ;no key pressed - issue int 28h
- jmp getkey ;loop back to try again
- getkey1: mov ah,0 ;get keycode from buffer
- int 16h
- ret ;exit with keycode in AX
- getkey endp
- ;
- ;
- ;------------------------------------------------------------------------------
- ;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
- ;Entry: NEW_CURSOR - starting and ending scan lines
- ;------------------------------------------------------------------------------
- show_cursor proc near
- cmp adapter,2 ;is an EGA currently active?
- jne cursor1 ;no, then branch
- push es ;save ES
- mov ax,bios_data ;point ES to BIOS data area
- mov es,ax
- assume es:bios_data
- push infobyte ;save EGA info byte
- or ega_info,1 ;disable EGA cursor emulation
- cursor1: mov ah,1 ;display the cursor
- mov cx,new_cursor
- int 10h
- cmp adapter,2 ;is an EGA active?
- jne cursor_exit ;no, then exit
- pop infobyte ;restore EGA info byte
- pop es ;restore ES
- assume es:nothing
- cursor_exit: ret
- show_cursor endp
- ;
-
- ;--------------------------------------------------------------------
- end_res db 0
- ;
- ; This is the end of the memory resident portion of LPTx
- ;
- ;--------------------------------------------------------------------
- ;
- ; All of the following data is in the Code Segment
- ;
- mach_type db 0
- DOS_version db 0 ;Major Version Number
- db 0 ;Minor Version Number
- lfeed db ON ;linefeed enable switch
- appending db 0 ;appending to an existing file
- drive db 0 ;default drive number 0=A etc.
- flag_27 db OFF ; 1=make this copy resident
- wrong_dos db 'DOS 2.0 or later required for LPTx',LF,CR,DOLLAR
- up_msg db 'LPTx - Line Printer Redirection Program - V7.00'
- db LF,CR,' Copyright 1987 Mark C. DiVecchio'
- db LF,CR,' Copyright 1987 Kepa Zubeldia',LF,CR
- db DOLLAR
- lptx_resident db LF,CR,'Resident Portion of LPTx Loaded',LF,CR
- db 'The pop-up window will be activated by Alt-PrtSc'
- db LF,LF,CR
- db DOLLAR
- lptx_err_3 db 'Could not delete file',LF,CR,DOLLAR
- lptx_over db CR,LF,'File already exists. Do you want to overwrite '
- db 'it? (y or n) :',DOLLAR
- lptx_nc db 'File selection canceled',CR,LF,DOLLAR
- lptx_lf db 'Stripping Linefeed Characters',CR,LF,DOLLAR
- lptx_sd_on db 'Sound Enabled',CR,LF,DOLLAR
- lptx_mono db 'Monochrome only, graphic card ignored',CR,LF,DOLLAR
- lptx_cs_off db 'Critical Section Checking Disabled',CR,LF,DOLLAR
- lptx_del db 'File is being overwritten',LF,CR,DOLLAR
- lptx_cr db LF,CR,DOLLAR
- lptx_bad db 'Invalid Option',LF,CR
- db 'Calling sequence:',LF,CR
- db 'lptx [?] [-m] [-x] [-l] [-i] {-1,-2,-3} {-c -o -a <d:[pathname]filename>}'
- db LF,CR,DOLLAR
- lptx_on db LF,CR,'Redirection started. Disk file opened.'
- db LF,CR,DOLLAR
- lptx_off db LF,CR,'Redirection ended. Disk file closed.'
- db LF,CR,DOLLAR
- lptx_creat db 'Could not create the disk file',LF,CR,DOLLAR
- lptx_open db 'Could not open the disk file',LF,CR,DOLLAR
- lptx_gone db LF,'LPTx - Resident portion inactivated',CR,LF,DOLLAR
- ; HELP screen
- help_msg db LF,CR,'Calling sequence : ',LF,LF,CR
- db 'LPTx [?] [-m] [-x] [-l] [-i] -p -f <[d:][\pathname\pathname]filename>'
- db LF,LF,CR
- db ' where p = printer number : 1, 2, or 3',LF,CR
- db ' f = function : o for open a print file'
- db LF,CR
- db ' a for append to a print file'
- db LF,CR
- db ' c for close a print file'
- db LF,CR
- db ' drive letter & pathname are optional'
- db LF,CR
- db ' m = monochrome mode only, even with graphics cards'
- db LF,CR
- db ' x = disable check of Critical Section Flag'
- db LF,CR
- db ' l = strip Linefeed characters from output'
- db LF,CR
- db ' i = inactivate LPTx',LF,CR
- db ' defaults : p = 1',LF,CR
- db ' f = o',LF,CR
- db ' The pop-up window is activated with Alt-PrtSc'
- db LF,CR
- db DOLLAR
- ;
- stat_stat db CR,LF,'LPTx Status :',CR,LF,DOLLAR
- stat_lp db 'lpt'
- stat_ptr db ' : ',DOLLAR
- stat_off db ' not redirected',CR,LF,DOLLAR
- stat_dir db ' redirected to disk file '
- stat_fn db 60 dup (BLANK)
- ;
- yn_max db 2 ;max # of char
- yn_act db 0
- yn_in db 2 dup (0)
- ;
- ;--------------------------------------------------------------------
- ;
- ; This is the main routine which is executed each time that LPTx is
- ; called. In this routine, DS points to the data segment which is
- ; transient. ES points to the data segment which is permanently
- ; resident. ES:BX points to the data structure for the selected
- ; line printer, 1, 2, or 3.
- ; The offsets are the same for both. If this is the first
- ; time that LPTx is run, then ES=DS.
- ;
- lptx_start:
- push DS ;Save DS
- xor AX,AX ;clear AX for return IP
- push AX ;put 0 on stack
- ;
- ;to check for machine type look at
- ; F000:FFFE ; I don't use this currently
- ; = FF IBM PC
- ; = FE IBM XT or Portable
- ; = FD IBM PCjr
- ; = FC IBM PC AT
- ; = F9 IBM Convertible
- mov AX,0F000h
- mov ES,AX
- mov BX,0FFFEh
- mov CL,ES:[BX] ;get machine type
- mov mach_type,CL ;save machine type
- ;
- ;PSP
- mov lptx_psp,DS ;put away our PSP Segment address
- ;
- ; get the DOS version number
- ; returns zero for pre DOS 2.0 releases
- mov AH,30h
- int DOS_CALL ;call DOS
- mov word ptr DOS_version,AX
- ; Requires at least version 2.0 and may or may not work
- ; with versions above 2.1
- cmp DOS_version,2 ;is it DOS 2.+
- jge dos_ok ;yes
- display wrong_dos ;print error message
- mov AH,0
- int DOS_CALL ;terminate
- dos_ok: mov AH,def_drive ;get current default drive
- int DOS_CALL
- mov drive,AL ;save the drive number
- display up_msg ;print program ID
- mov flag_27,OFF ;to not make resident
- ; is a copy of LPTx already resident in memory?
- mov DX,REQ ;check if LPTx is already resident
- mov AH,3 ;get status - special call
- int 17h ;call int 17h - BIOS
- cmp DX,ACK ;my handler sets DX to ACK
- ;and sets ES
- je in_core ;LPTx is resident - ES loaded with
- ; segment address
- mov flag_27,ON ;to make this copy resident
- push CS
- pop ES ;set ES to CS for segment address
- mov AL,drive
- add AL,'a' ;make it a letter
- mov BX,offset lpt1
- mov ES:[BX].filen,AL ;put it into the filename
- mov BX,offset lpt2
- mov ES:[BX].filen,AL ;put it into the filename
- mov BX,offset lpt3
- mov ES:[BX].filen,AL ;put it into the filename
- ; ----------------------------------------------------
- in_core: ;ES is ok
- ; ES now points to resident data area
- ; set up ES:BX to point to default data structure
- mov BX,offset lpt1 ;offset - default to LPT1
- ;get options and file name
- ;scan input line for line printer number
- mov SI,81h ;starting offset
- mov CL,DS:80h ;length of input line
- mov CH,0
- cmp CX,0 ;nothing?
- jne cont_scan ;no
- jmp make_res ;yes, then just make LPTx resident
- ;if it isn't already
-
- ;
- ; [?]
- ; HELP printer
- ;
- help: display help_msg ;display the HELP screen
- jmp bail_out
- ;
- ; [-m]
- ; Monochrome monitor, even on graphic card
- ;
- mono_only:
- mov ES:nocolors,1
- display lptx_mono
- jmp short inp_ret
- ;
- ; [-a]
- ; appending to a file, similar to open.
- ;
- append:
- mov appending,1
- jmp file_op
- ;
- ;
- cont_scan:
- cmp byte ptr DS:[SI],'?' ;a ? ?
- je help ;yes
- cmp byte ptr DS:[SI],dash ;a dash ?
- je got_opt ;yes
- cmp byte ptr DS:[SI],CR ;a carriage return?
- je scan_done ;yes
- cmp byte ptr DS:[SI],BLANK ;a blank?
- je inp_ret ;yes
- jmp no_b ;assume that we got a file name
- ;without the -o option
- inp_ret:
- inc SI ;ignore blanks
- loop cont_scan ;continue to scan
- ;
- ; Scan of whole line is complete without a "-o", "-a", "-c" or filename
- scan_done:
- jmp make_res
- ;
- got_opt: ;we got an option
- inc SI ;to option
- cmp byte ptr DS:[SI],'1' ;LPT1?
- jne chk_2
- mov BX,offset lpt1 ;offset from ES
- jmp short inp_ret
- chk_2: cmp byte ptr DS:[SI],'2' ;LPT2?
- jne chk_3
- mov BX,offset lpt2 ;offset from ES
- jmp short inp_ret
- chk_3: cmp byte ptr DS:[SI],'3' ;LPT3?
- jne chk_fil
- mov BX,offset lpt3 ;offset from ES
- jmp short inp_ret
- chk_fil: ;is it file?
- cmp byte ptr DS:[SI],'?' ;help ?
- je help ;yes
- cmp byte ptr DS:[SI],'o' ;open a file
- je file_op ;yes
- cmp byte ptr DS:[SI],'a' ;append to a file
- je append ;yes
- cmp byte ptr DS:[SI],'c' ;close a file
- je file_cl ;yes
- cmp byte ptr DS:[SI],'m' ;monochrome only ?
- je mono_only ;yes
- cmp byte ptr DS:[SI],'x' ;inhibit check for Critical Section?
- je cs_check_off ;yes
- cmp byte ptr DS:[SI],'l' ;linefeed switch ?
- je lf_off ;yes
- cmp byte ptr DS:[SI],'s' ;enable sound?
- je sound_on ;yes
- cmp byte ptr DS:[SI],'i' ;inactivate?
- jne bad_opt
- jmp inactivate
- bad_opt:
- display lptx_bad ;incorrect option
- jmp nor_ex
- ;
- ; [-x]
- ; turn OFF Critical Section check
- ;
- cs_check_off:
- mov ES:cs_switch,OFF
- display lptx_cs_off
- jmp inp_ret
- ;
- ;[-l]
- ; Turn linefeeds off in captured file
- ;
- lf_off: mov lfeed,OFF ;turn LFs off
- display lptx_lf
- jmp inp_ret ;continue the scan
- ;
- ; [-s]
- ; turn ON Sound
- ;
- sound_on:
- mov ES:sound,ON
- display lptx_sd_on
- jmp inp_ret
- ;
- ; [-c]
- ; close output file
- ;
- file_cl:cmp ES:[BX].active,ON ;are we active?
- jne no_close ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- ; call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;redirection off message
- no_close:
- jmp nor_exit ;nothing to close so exit
- ;
- ; [-o]
- ; open a file for ouput
- ;
- file_op: ;get the file name
- inc SI ;to next chracter
- cmp byte ptr DS:[SI],BLANK ;a blank?
- jne no_b ;no
- inc SI ;skip over blank
- no_b:
- ; at this point, we have found a new file name. We close the old
- ; file if one was open
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- ; call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;redirection off message
- no_cl: mov DI,BX ;base of structure
- add DI,offset lpt1.filen ;add offset of destination
- push SI ;save pointer to file name
- ; search for a drive letter
- inc SI ;should point to a colon if
- ;one is there
- cmp byte ptr [SI],COLON ;?
- je got_drive ;yes
- get_drive:
- mov AL,drive ;get drive letter
- add AL,'a' ;make it a letter
- mov ES:[DI],AL ;put it in file name
- inc DI
- mov byte ptr ES:[DI],COLON ;put in a colon
- inc DI
- jmp path_search
- got_drive:
- pop SI ;move pointer back to start
- mov AL,[SI] ;get the given drive
- mov ES:[DI],AL ;move it
- sub AL,'a' ;make it a number
- mov drive,AL ;save the drive number
- inc SI
- inc DI
- mov byte ptr ES:[DI],COLON
- inc DI
- inc SI
- push SI ;save new start pointer
- path_search:
- ; now search for a backslash which says that a pathname was given
- bk_s_lp:cmp byte ptr [SI],BACKSLASH
- je got_path ;a path
- cmp byte ptr [SI],CR ;end of the file name?
- je get_path ;yes with no path
- inc SI
- jmp short bk_s_lp ;loop
- get_path:
- mov byte ptr ES:[DI],BACKSLASH ;create the path
- inc DI
- mov DL,drive ;the current drive
- inc DL ;bump it for DOS
- push DS
- push ES
- pop DS ;set up DS for DOS
- mov SI,DI ;set up SI for pathname
- mov AH,def_path ;get current directory
- int DOS_CALL ;path goes into DS:SI
- pop DS ;restore DS
- cmp byte ptr ES:[SI],NULL ;null path?
- je null_path ;yes - root directory
- path_lp: ;now find the end of the string
- cmp byte ptr ES:[SI],NULL ;null byte marks end of pathname
- je end_path ;now append the file name
- inc SI
- jmp short path_lp
- end_path:
- mov byte ptr ES:[SI],BACKSLASH
- inc SI
- null_path:
- mov DI,SI ;DI is destination
- got_path:
- pop SI ;restore source of filename
- ; pick up everything to next blank
- get_lp:
- mov AL,DS:[SI] ;character
- mov ES:[DI],AL ;put it away
- cmp AL,CR ;was it a Carriage Return?
- je end_line
- cmp AL,BLANK ;was it a space?
- je end_line
- inc SI
- inc DI
- jmp short get_lp ;no so get next character
- end_line:
- mov byte ptr ES:[DI],NULL ;zero out the CR or blank
- ;at the end of the filename
- ;it becomes an ASCIIZ string
- sub DI,BX ;now take out the base and
- cmp DI,offset lpt1.filen ; make sure that we got something
- jne lptx_make ;file name was ok
- display lptx_creat ;could not understand the file name
- jmp nor_exit ;don't stay resident
- nor_ex: jmp nor_exit
-
- lptx_make:
- ; default DTA used by Find File is set by DOS to an offset of
- ; 80h into this program's Program Segment Prefix
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX
- add DX,offset lpt1.filen ;file name
- mov AH,find_FILE
- mov CX,0 ;normal files only
- int DOS_CALL ;find first match
- pop DS
- jnc lptx_d ;file was found
- jmp lptx_create ;not there - which is ok
- ;file already exists
- lptx_d: cmp appending,1 ;are we in append mode?
- je lptx_x ; yes
- display lptx_over
- mov DX,offset yn_max;input buffer
- mov AH,0AH
- int DOS_CALL
- cmp yn_act,0 ;anything typed?
- display lptx_cr
- je lptx_x ;no - try to append
- cmp yn_in,'y' ;a yes?
- je lptx_d_yes ;yes
- cmp yn_in,'Y' ;a yes?
- je lptx_d_yes ;yes
- lptx_x: push DS ;we can't overwrite, try to append
- push ES
- pop DS ;uses DS:DX
- mov DX,BX ;base of this LPT's structure
- add DX,offset lpt1.filen ;file name
- mov AL,1 ;open for writing
- mov AH,open_FILE
- mov CX,0 ;normal files only
- int DOS_CALL ;find first match
- pop DS
- jnc creat_ok
- display lptx_open ;could not open the file
- display lptx_nc
- jmp nor_exit ;don't stay resident
-
- lptx_d_yes:
- display lptx_del
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX
- add DX,offset lpt1.filen ;file name
- mov AH,delete_FILE
- int DOS_CALL ;delete file
- pop DS
- jnc lptx_create ;ok its gone
- display lptx_err_3 ;can't delete it
- jmp nor_exit
- lptx_create: ; create the file
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX ;base of this LPT's structure
- add DX,offset lpt1.filen ;file name
- mov AH,create_FILE
- mov CX,0 ;normal files only
- int DOS_CALL ;find first match
- pop DS
- jnc creat_ok
- display lptx_creat ;could not create the file
- jmp nor_exit ;don't stay resident
- creat_ok: ;now close the file
- push BX
- mov ES:[BX].handle,AX ;save the handle, for popup to know.
- mov BX,AX ;AX was loaded by the create file
- ; call
- mov AH,close_FILE ;close the file
- int DOS_CALL
- pop BX
- display lptx_on
- ; set the program up for writing
- mov ES:[BX].bufcntr,EMPTY ;set buffer empty
- mov ES:[BX].active,ON ;set us on
- mov AL,lfeed
- mov ES:[BX].linefeed,AL ;save linefeed switch
- make_res:
- cmp flag_27,ON ;make this one resident?
- je resident ;yes
- jmp nor_exit ;no
- ;
- resident:
- push ES
- push BX
- ; get old interrupt handler addressses
- mov AL,17h ;get current vector address for 17h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_17h,BX
- mov word ptr old_17h[2],ES ;save it for later use
-
- mov AL,08h ;get current vector address for 08h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_08h,BX
- mov word ptr old_08h[2],ES ;save it for later use
-
- mov AL,09h ;get current vector address for 09h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_09h,BX
- mov word ptr old_09h[2],ES ;save it for later use
-
- mov AL,10h ;get current vector address for 10h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_10h,BX
- mov word ptr old_10h[2],ES ;save it for later use
-
- mov AL,13h ;get current vector address for 13h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_13h,BX
- mov word ptr old_13h[2],ES ;save it for later use
-
- mov AL,DOS_CALL ;get current vector address for 21h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_21h,BX
- mov word ptr old_21h[2],ES ;save it for later use
-
- mov AL,28h ;get current vector address for 28h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_28h,BX
- mov word ptr old_28h[2],ES ;save it for later use
-
- ;
- ; Set LPTx up as the new int 17h interrupt handler
- mov AX,2517h ;set interrupt vector
- mov DX,offset int_17h ;BIOS printer
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 08h interrupt handler
- mov AX,2508h ;set interrupt vector
- mov DX,offset int_08h ;Timer
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 09h interrupt handler
- mov AX,2509h ;set interrupt vector
- mov DX,offset keyboard ;Keyboard
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 10h interrupt handler
- mov AX,2510h ;set interrupt vector
- mov DX,offset video ;Video
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 13h interrupt handler
- mov AX,2513h ;set interrupt vector
- mov DX,offset bdisk ;Disk
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 21h interrupt handler
- ; mov AX,2521h ;set interrupt vector
- ; mov DX,offset int_21h ;DOS Functions
- ; int DOS_CALL
- ;
- ; Set LPTx up as the new int 28h interrupt handler
- mov AX,2528h ;set interrupt vector
- mov DX,offset int_28h ;Idle
- int DOS_CALL
- ;
- ; get the address of the critical section flag
- ;
- mov AH,34h
- int DOS_CALL ;Call Special DOS interrupt
- ;returns pointer to critical
- ;section flag in ES:BX
- ;With DOS 2.1, this returns
- ;00EC:012D. I used the XRAY
- ;program to look at this
- ;byte while DOS was running.
- mov csect_seg,ES ;save the pointer
- mov csect_off,BX
- ;
- ; get the address of the critical error flag. This piece of code comes from
- ; PC Magazine, October 13, 1987, page 416, CARDFILE.ASM, by Jeff Prosise.
- ;
- mov cerrf_seg,ES ;save the pointer for critical error
- mov ax,3E80h ;CMP opcode
- mov cx,2000h ;max search length
- mov di,bx ;start at critical section address
- ce_init4: repne scasw ;do the search
- jcxz ce_init5 ;branch if search failed
- cmp byte ptr es:[di+5],0BCh ;verify this is it
- je ce_found ;branch if it is
- jmp ce_init4 ;resume loop if it's not
- ce_init5: mov cx,2000h ;search again
- inc bx ;search odd addresses this time
- mov di,bx
- ce_init6: repne scasw ;look for the opcode
- jcxz ce_notfound ;not found if loop expires
- cmp byte ptr es:[di+5],0BCh ;verify this is it
- je ce_found
- jmp ce_init6
- ce_notfound: mov ax,csect_off ;flag not found, fake it
- jmp ce_end
- ce_found: mov ax,es:[di] ;get flag offset address
- ce_end: mov cerrf_off,ax ;save it
- ;
- pop BX
- pop ES
- display lptx_resident ;resident loaded message
- call stat ;display status
- mov DX,offset end_res
- int 27h ;terminate but stay resident
- ;
- ; Normal exit for transient copy of LPTx
- nor_exit:
- call stat ;display status
- bail_out:
- mov AH,0
- int DOS_CALL ;terminate
- ;
- ; [-i]
- ; unhook LPTx from interrupt vectors 08h, 09h, 17h, 21h, and 28h
- inactivate:
- ;
- cmp word ptr ES:old_17h,0 ;is it sill 0?
- je bail_out ;yes, we weren't installed yet
- ; flush all buffers
- mov BX,offset lpt1
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl1 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- ; call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- ;
- no_cl1:
- mov BX,offset lpt2
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl2 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- ; call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- ;
- no_cl2:
- mov BX,offset lpt3
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl3 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- ; call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- no_cl3:
- push DS
- mov DX,word ptr ES:old_17h ;original vector, offset
- mov AX,word ptr ES:old_17h[2];original vector, segment
- mov DS,AX
- mov AX,2517h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
- push DS
- mov DX,word ptr ES:old_21h ;original vector, offset
- mov AX,word ptr ES:old_21h[2];original vector, segment
- mov DS,AX
- mov AX,2521h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_08h ;original vector, offset
- mov AX,word ptr ES:old_08h[2];original vector, segment
- mov DS,AX
- mov AX,2508h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_09h ;original vector, offset
- mov AX,word ptr ES:old_09h[2] ;original vector, segment
- mov DS,AX
- mov AX,2509h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_10h ;original vector, offset
- mov AX,word ptr ES:old_10h[2] ;original vector, segment
- mov DS,AX
- mov AX,2510h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_13h ;original vector, offset
- mov AX,word ptr ES:old_13h[2] ;original vector, segment
- mov DS,AX
- mov AX,2513h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_28h ;original vector, offset
- mov AX,word ptr ES:old_28h[2];original vector, segment
- mov DS,AX
- mov AX,2528h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
- display lptx_gone ;inactivated
- jmp bail_out
- ;------------------------------------------------------------------------
- ;
- ; displays the status of each of the three line printers
- ;
- stat proc near
- ; display each LPTx with a message "not redirected"
- ; or redirected to <filename>
- push AX
- push BX
- push DX
- push SI
- push DI
- display stat_stat
- stat_1: mov BX,offset lpt1 ;first printer
- mov stat_ptr,'1'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_1_a ;yes
- display stat_off
- jmp short stat_2
- stat_1_a:
- mov SI,BX ;base
- add SI,offset lpt1.filen ;offset
- mov DI,offset stat_fn
- stat_1_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_1_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_2:
- mov BX,offset lpt2 ;second printer
- mov stat_ptr,'2'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_2_a ;yes
- display stat_off
- jmp short stat_3
- stat_2_a:
- mov SI,BX ;base
- add SI,offset lpt1.filen ;offset
- mov DI,offset stat_fn
- stat_2_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_2_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_3: mov BX,offset lpt3 ;third printer
- mov stat_ptr,'3'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_3_a ;yes
- display stat_off
- jmp short stat_done
- stat_3_a:
- mov SI,BX ;base
- add SI,offset lpt1.filen ;offset
- mov DI,offset stat_fn
- stat_3_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_3_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_done:
- pop DI
- pop SI
- pop DX
- pop BX
- pop AX
- ret
- stat endp
- ;
- cseg ends
- %out EOF
- end lptx
-