home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
1
/
1026
/
nprint.asm
next >
Wrap
Assembly Source File
|
1990-12-28
|
17KB
|
681 lines
;****************************************************************************
; NPRINT.COM: A TSR to submit a file to PRINT.COM
;****************************************************************************
cseg segment para public 'CODE'
assume cs:cseg, ds:nothing, es:nothing, ss:nothing
org 100h
entpt: jmp install ; Jump to the Install code
VIDEO EQU 10h ; Interrupts used within NPRINT
KEYBOARD EQU 16h
PRINTER EQU 17h
MULTIPLEX EQU 2Fh
DOS EQU 21h
MONOSCR EQU 0B000h ; Monochrome Screen Memory Location
COLORSCR EQU 0B800h ; CGA (COLOR) Screen Memory Location
copyright db 'NPRINT v1.0: (c) Copyright 1990 by Christopher D. Orr',13,10,'$'
prompt db 'Enter Filename: ',0
no_print db 'Printer is not responding. Please correct. Hit any Key',0
printpack db 0,0,0,0,0
invoke_flag db 0 ; Flag set whenever a request for us in pending
cursor dw 0 ; Original cursor position
pr_attribute db 07h ; Attribute for the Prompt/Messages
scr_attribute db 07h ; Attribute for data entry
do_prtsc db 0 ; Flag to indicate whether to do a screen print
display_page db 0 ; Current Screen display page
tone dw 0 ; Storage for frequency of bell when rung
CritSectFlag dd 0 ; Critical Section Flag
old_int_5 dd 0 ; Address of original print screen handler
old_int_28 dd 0 ; Address of original DOS handler
pause_msg db ' ... ',0
errmsg db 'PRINT returned error code '
errcode db 0,0
db 'h: ',0
err_table dw errmsg1, errmsg2, errmsg3, errmsg4, errmsg5
dw e_unknown, e_unknown, errmsg8, e_unknown, e_unknown
dw e_unknown, errmsgc, e_unknown, e_unknown, errmsgf
errmsg1 db 'Function Invalid',0
errmsg2 db 'File not Found',0
errmsg3 db 'Path not Found',0
errmsg4 db 'Too many files open',0
errmsg5 db 'Access Denied',0
errmsg8 db 'PRINT Queue full',0
errmsgc db 'Filename too long',0
errmsgf db 'Drive invalid',0
e_unknown db 'Unknown Return Code',0
datasize = ($ - offset copyright)
;-----------------------------------------------------------------------------
; Interrupt Handlers - This procedure defines code to determine when/if we
; should invoke the NPRINT main routine.
;-----------------------------------------------------------------------------
nprint proc far
int28:
cmp cs:[invoke_flag], 0FFh ; Should we invoke ourselves ?
jnz short int_return ; No, so get out
call main ; Invoke NPRINT
pushf ; Push the flags
cli ; Disable interrupts
push cs ; Push the CS register
mov di,offset cs:int_return ; When we return, we want to exit
push di
jmp dword ptr cs:old_int_28 ; Transfer control to old int 28h
int5:
push bx
push es
mov bx,word ptr CritSectFlag[0] ; Look at the Crit. Sec. Flag
mov es,word ptr CritSectFlag[2]
cmp byte ptr es:[bx],0h ; If non-zero, DOS is busy
je ok2run ; Zero, so invoke NPRINT
pop es
pop bx
mov cs:[invoke_flag], 0FFh ; Leave a flag to tell us to
jmp short int_return
ok2run:
pop es
pop bx
call main ; Call NPRINT
int_return:
iret ; and we return ...
endp nprint
;-----------------------------------------------------------------------------
; Main Procedure - Responsible for processing user request
;-----------------------------------------------------------------------------
main proc near
sti ; Allow Interrupts
push bp ; Access to stack
mov bp,sp ; Before we push anything
pushf ; Save the state of the machine
push es ; because we're gonna make
push ds ; a mess of it
push di
push si
push dx
push cx
push bx
push ax
mov ax,cs ; Establish the proper segments
mov ds,ax
mov es,ax ; Make ES point to code segment
assume ds:cseg, es:cseg ; Tell the assembler
ok2load:
mov [invoke_flag], 0h ; Clear Invocation flag
mov ah,0fh ; Get the current Display Mode
int VIDEO
mov [display_page],bh ; Save current page
cmp al,07h ; Is this a Monochrome Monitor ?
je mono ; Yes, so we are okay
cmp al,03h ; Is this a CGA Monitor in 80 col mode?
je cga ; Yes, so we are okay
call ring_bell ; No - so don't execute. Just abort.
jmp done ; Exit NPRINT
mono:
mov ax,MONOSCR ; Monochrome Display
jmp short saveline
cga:
mov ax,COLORSCR ; CGA display
saveline:
mov ds,ax ; Set up the Data Segment
mov si,3840 ; Start at position row=25, column=1
mov cx,80 ; 80 Character lines
lea di, screenbuf
push es ; Save screen memory locations
push ds
push si
cld ; Make sure we copy from right to left
rep movsw ; Move character & Attribute
mov ax,cs ; Restore the Data Segment
mov ds,ax
mov ah,03h ; Get the Current Cursor Position
int VIDEO
mov [cursor], dx ; and save it.
call clear_25 ; Goto and Clear Line #25
lea si, prompt ; Display the filename prompt for the user
call wr_string
lea dx,filename ; Point to out filename buffer
mov ax,60 ; Limit filename to 60 characters
call rd_string ; Request the filename from the user
cmp ax,0 ; Did we get a file name ???
jne submit_file ; No, so don't do the print routine
mov ah,02h ; Let's see if the printer is busy
mov dx,0 ; Check printer number 0
int PRINTER
test ah,01101001B ; Clear bits 8,5,3,2 -> meaningless to us
jz prtsc_okay
lea si, no_print ; No, then there is a problem w/
call clear_25 ; the printer. Tell the user about it
call ring_bell
call wr_string
call pause
jmp restscreen ; No sense printing a screen now, so don't
prtsc_okay:
mov [do_prtsc],0FFh ; Set the Print Screen Flag
jmp restscreen
submit_file:
mov [do_prtsc],0h ; Clear the Print Screen Flag
mov word ptr [printpack]+3,ds ; Put the address into packet
mov word ptr [printpack]+1,offset filename
retry_file:
lea dx,printpack ; Point to the printer request packet
mov ax,0101h ; Submit packet to Print Spooler
int MULTIPLEX ; Invoke Multiplex Service Interrupt for PRINT
jnc restscreen ; If the carry flag is set, then we had an error
cmp ax,09h ; Is the spooler busy ? (NOTE: endless loop?)
je retry_file ; Yes, so try again
call display_errmsg ; Some other kind of error
restscreen:
lea si, screenbuf ; Point to our screen buffer
pop di ; Restore Screen Memory Locations
pop es
pop ds ; Restore the Data Segment
mov cx,80 ; Still name 80 character line
cld ; Make sure we copy from right to left
rep movsw
mov ax,cs ; Restore the Data and Extended Segment values
mov ds,ax
mov es,ax
mov dx,[cursor] ; Restore the cursor position to what it was
mov bh,[display_page]
mov ah,02h
int VIDEO
;----------------------------------------------------------------------
; Restore the state of the machine when Int 05 occured
;----------------------------------------------------------------------
done:
pop ax
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
popf
pop bp
IFDEF DEBUG
mov ax,4c00h
int DOS
ENDIF
assume ds:nothing, es:nothing
cmp cs:[do_prtsc],0FFh ; Is the Print Screen flag set ?
jne nprint_exit ; no, so we should just exit
pushf ; Push the flags
cli ; Disable interrupts
push cs ; Push the CS register
mov di,offset cs:formfeed
push di
jmp dword ptr cs:old_int_5 ; Transfer control to old int 05h
formfeed:
pushf ; Save the state of the machine yet again
push es
push ds
push di
push si
push dx
push cx
push bx
push ax
assume ds:cseg, es:cseg ;Tell the assembler
mov ah,00h ; Print a character
mov al,0ch ; Namely a Formfeed (^L)
mov dx,0 ; Printer number one
int PRINTER ; Invoke Print Interrupt
pop ax ; Restore everything again
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
popf
nprint_exit:
ret ; And we return ...
main endp
;======================================================================
; WR_STRING - write string to console at specified location.
; The string is ASCIIZ. All registers are preserved.
;----------------------------------------------------------------------
wr_string proc near
push si
push bx
push cx
push ax
wnext_char:
lodsb ; Load char in AL from DS:SI
or al,al ; If char is 0
jz end_string ; Then end of ASCIIZ string
mov ah,09h ; Else, write TTY
mov bh,[display_page]
mov bl,[pr_attribute]
mov cx,01h ; Only one
int VIDEO ; thru BIOS
mov al,1
call move_cursor ; Move the cursor to the right
jmp short wnext_char ; and do it all again
end_string:
pop ax
pop cx
pop bx
pop si
ret
wr_string endp
;-----------------------------------------------------------------------------
; Read a String from the Keyboard and returns a pointer to it
; Point to String using DS:DX. RETURNS: AX contains number of chars read
;-----------------------------------------------------------------------------
rd_string proc near
push bx
push cx
push di
push dx
mov di,dx ; Setup our buffer pointer
mov bx,ax ; Store the max length in BX
rnext_char:
mov ah,0h ; Read Keyboard Character Function
int KEYBOARD
cmp al,08h ; Backspace ?
jne check_enter ; No, so jump
pop dx ; Restore the head of buffer pointer
push dx
cmp di,dx ; Are we at the start of line?
jle rnext_char ; Yes, so ignore the backspace
dec di ; Decrement our buffer pointer
mov al,0 ; and move the cursor back
call move_cursor
push bx ; Now we have to erase the character
mov bh,[display_page]
mov cx,1
mov bl,[scr_attribute]
mov ah,09h ; Function for writing a character
mov al,20h ; Put a space on the screen
int VIDEO
pop bx
jmp short rnext_char
check_enter:
cmp al,0dh ; Did we get a return ?
jne letter
mov byte ptr [di],0h; Already at end of string, so add null
pop dx ; Restore pointer to start of buffer
sub di,dx ; How many chars did we read ?
mov ax,di ; Return that number in AX
pop di ; Restore the Data Index Register
pop cx
pop bx
ret
letter:
cmp al,20h ; Check for a valid character
jle rnext_char ; Ignore none printable characters/keys
cmp al,7eh
jg rnext_char
pop dx ; Restore the head of buffer pointer
push dx
add dx,bx ; Maximum of "bx" characters
cmp di,dx ; Yes, so are we at the end of buffer?
jne char_ok
call ring_bell ; Yes, so sound the alarm
jmp rnext_char
char_ok:
mov [di],al ; Store the character
inc di ; Increment our pointer
push bx
mov cx,1
mov bl,[scr_attribute]
mov ah,09h ; Display the character to the user
mov bh,[display_page]
int VIDEO
mov al,1 ; Increment the cursor
pop bx
call move_cursor
jmp rnext_char ; Get the next character
rd_string endp
;-----------------------------------------------------------------------------
; Increment or Decrement the current cursor position. AX=0 implies decrement
;-----------------------------------------------------------------------------
move_cursor proc near
push bx
push cx
push dx
mov ah,03h ; Get cursor position
mov bh,[display_page]
cmp al,0 ; If code 0, then decrement cursor
je dec_cursor
int VIDEO
inc dl
jmp short last_cur
dec_cursor:
int VIDEO
dec dl
last_cur:
mov ah,02h ; Set the Cursor Position
int VIDEO
pop dx
pop cx
pop bx
ret
move_cursor endp
;----------------------------------------------------------------------
; HEX2 - Convert the AL register to hexidecimal digits.
; The characters produced are stored at ES:DI.
; All regs preserved.
;----------------------------------------------------------------------
hex2 proc near
push ax
push bx
push cx
mov bx,ax
std ;String ptr decrement
add di,1 ;Point to end of string
mov cx,2
h10:
mov al,bl ;Want lower half
and al,0fh ; of this byte
add al,90h ;Convert AL to ASCII
daa
adc al,40h
daa
stosb ;Store at ES:DI
shr bx,1
shr bx,1
shr bx,1
shr bx,1
loop h10
pop cx
pop bx
pop ax
inc di
cld
ret
hex2 endp
;-----------------------------------------------------------------------------
; Erase the 25th line of the screen and position the cursor on that line
;-----------------------------------------------------------------------------
clear_25 proc near
push ax
push dx
push cx
push bx
mov ah,02 ; Set the Cursor Position
mov dh,24 ; Go to the 25th line
mov dl,0h ; column number 1.
int VIDEO
mov ah,09h ; Clear the line ...
mov al,20h ; using spaces
mov bh,[display_page]
mov bl,07h ; Change the attributes to white
mov cx,80 ; Write 80 characters
int VIDEO
pop bx
pop cx
pop dx
pop ax
ret
clear_25 endp
;-----------------------------------------------------------------------------
; Pause so the user can press a key ... any key ...
;-----------------------------------------------------------------------------
pause proc near
mov si, offset pause_msg
call wr_string
top_pause:
mov ah,01h ; Wait for a key to be pressed
int KEYBOARD
jz top_pause
mov ah,00h ; Eat the keystroke
int KEYBOARD
; cmp al,0dh ; Only continue with the [RETURN] key
; jne top_pause
ret
pause endp
;-----------------------------------------------------------------------------
; Display the Error Code and Message
;-----------------------------------------------------------------------------
display_errmsg proc near
call clear_25
call ring_bell
mov di,offset errcode ; Display the error code
call hex2
lea si, errmsg
call wr_string
cmp al,0fh ; Is the error off the scale ??
jle table
lea si,e_unknown ; Yes, so display "unknown" message
jmp short show_error
table:
xor bh,bh ; Build offset into error table
mov bl,al ; Can't use AX as a memory index ptr
dec bx ; Table is base 0, so reduce the index
shl bx,1 ; Make offset into table (*2)
mov si,err_table[bx]
show_error:
call wr_string ; Now display the error
call pause
ret
display_errmsg endp
;-----------------------------------------------------------------------------
; Ring the Bell to indicate that an error occured - we create a special tone
; so that the user knows it is NPRINT that did it.
;-----------------------------------------------------------------------------
ring_bell proc near
push ax
push cx
push dx
in al,61h ; Get port data
push ax ; and save it
cli ; Clear Interrupts
mov dx,0ch ; Length of bell tone
mov [tone],500h ; Frequency
call speaker
mov dx,0ch ; Length of bell tone
mov [tone],1000h ; Frequency
call speaker
pop ax ; Reset
out 61h,al ; port data
sti ; Reset Interrupts
pop dx
pop cx
pop ax
ret
ring_bell endp
;-----------------------------------------------------------------------------
; Activate the speaker for a specified time and tone.
;-----------------------------------------------------------------------------
speaker proc near
BELL30:
and al,11111100B ; Set bits 0 & 1 off
out 61h,al ; Transmit to speaker
mov cx,[tone] ; Set the length
BELL40:
loop BELL40 ; Time Delay
or al,00000010B ; Set bit 1 on
out 61h,al ; Transmit to speaker
mov cx,[tone] ; Set length
BELL50:
loop BELL50 ; Time Delay
dec dx ; Reduce Duration
jnz BELL30 ; Continue ?
ret ; Nope, we are all done.
speaker endp
filename db 61 DUP (?) ; Storage for user inputted filename
screenbuf db 80*2 DUP (?) ; Storage for screen line we clear
lastbyte = $
; ---------------------------------------------------------------------------
; Main routine to install NPRINT as a TSR
; ---------------------------------------------------------------------------
install proc near
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
lea dx,copyright
mov ah,09h ; Print a copyright message
int DOS
mov ah,01h ; PRINT Function
mov al,00h ; Print Installation Check Subfunction
int MULTIPLEX ; Multiplex Service Interrupt
cmp al,0FFh
je ok2inst ; If we get FFh returned, then PRINT is there.
lea dx,noprint
mov ah,09h ; Print a failing message
int DOS
mov ax,4c01h ; Terminate with error code 1
int DOS
ok2inst:
IFDEF DEBUG
call main
ENDIF
mov ah,35h ; Determine Interrupt vector for PrintScreen
mov al,05h
int DOS
mov word ptr old_int_5[0],bx ;offset
mov word ptr old_int_5[2],es ;segment
mov ah,35h ; Determine Interrupt vector for DOS call
mov al,28h
int DOS
mov word ptr old_int_28[0],bx ;offset
mov word ptr old_int_28[2],es ;segment
lea si,copyright ; Lets see if we are already installed.
mov di,bx ; Put the offset into the DI register
sub di,datasize ; Position ourselves to the start of the data
mov cx,6 ; Compare 6 bytes (NPRINT)
repe cmpsb ; Repeat as long as they match
jne not_installed ; If it doesn't match, then we aren't installed
lea dx,inst_err ; OOPS, they match. Tell the user about it.
mov ah,09h
int DOS
mov ax,4c02h ; Return to DOS with errorlevel 2
int DOS
not_installed:
mov ah,34h ; Locate the Critical Sec. Flag
int 21h
mov word ptr CritSectFlag[0],bx ;offset
mov word ptr CritSectFlag[2],es ;segment
mov ah,09h ; Tell the user that we are installing
lea dx,inst_msg
int DOS
mov ah,25h ; Set Interrupt Vector for Print Screen
mov al,05h
lea dx,int5
int DOS
mov ah,25h ; Set Interrupt Vector for DOS Check
mov al,28h
lea dx,int28
int DOS
mov dx,code_pars ; Tell DOS how much memory we require
mov ax,3100h ; and become a TSR
int DOS
install endp
noprint db 'DOS PRINT.COM is not installed.',13,10,'$'
inst_err db 'NPRINT already installed.',7,13,10,'$'
inst_msg db 'NPRINT installed successfully.',13,10,'$'
code_size = (offset lastbyte - offset entpt)
code_pars = (code_size / 16) + 32
cseg ends
end entpt