home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1989
/
10
/
setup2.asm
< prev
next >
Wrap
Assembly Source File
|
1989-03-06
|
42KB
|
1,355 lines
;=============================================================================
; SETUP 2.0 allows text and control codes to be sent directly to a printer
; from the command line or from within a popup menu window. Syntax is:
;
; SETUP2 [d:][path][filename] | [/C codes] | [/U]
;
; where filename = Name of PMF file
; /C = Codes to be sent from the command line
; /U = Uninstall the program
;=============================================================================
code segment para public 'code'
assume cs:code
org 100h
begin: jmp initialize
program db "SETUP 2.0 "
copyright db "(c) 1989 Ziff Communications Co.",13,10
author db "PC Magazine ",254," Jeff Prosise",13,10
hotkey db "Hotkey is Ctrl-Rt/Shift",13,10,"$",1Ah
videocols db ? ;number of columns displayed
videopage db ? ;active video page
videoseg dw ? ;video segment
videostart dw ? ;starting video address
videocursormode dw ? ;cursor description
videocursorpos dw ? ;BIOS cursor position
pname db 26 dup (20h) ;menu window title
lpt_number dw 0 ;LPT port number
status db 0 ;program status flag
int9h dd ? ;interrupt 9h vector
window_start label word
window_x db ? ;starting window column
window_y db 1 ;starting window row
window_end dw ? ;lower right window corner
border_attr db ? ;border color
menu_attr db ? ;window color
hilite_attr db ? ;highlight color
cursor_def dw ? ;default cursor definition
index db 0 ;menu selection index
ten db 10 ;base 10 divisor
linecount dw 0 ;number of menu lines
pagecount db 1 ;number of menu pages
menupage db 0 ;current menu page
code_table dw offset menu_table ;address of control code table
end_offset dw offset menu_table ;ending program address
;=============================================================================
; KBINT receives control when an interrupt 9 is generated.
;=============================================================================
kbint proc far
pushf ;call BIOS keyboard routine
call int9h
sti ;enable interrupts
push ax
mov ah,2 ;get shift key status
int 16h
and al,0Fh ;mask off upper four bits
cmp al,5 ;was the hotkey combo pressed?
pop ax
jne kb_exit ;no, then exit
cmp status,0 ;check program status
jne kb_exit ;exit if it's already up
call main ;pop up the window
kb_exit: iret ;exit
kbint endp
;=============================================================================
; MAIN is the main body of the program.
;=============================================================================
main proc near
mov status,1 ;set program status flag
push ax ;save all registers
push bx
push cx
push dx
push bp
push si
push di
push ds
push es
mov ah,15 ;abort if the current video
int 10h ; mode is not a text mode
cmp al,7
je main1
cmp al,4
jb main1
;
;Restore register values and return to caller.
;
main_exit: pop es ;restore registers
pop ds
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
mov status,0 ;clear program status flag
ret
;
;Save video parameters and read the cursor address from the CRT controller.
;
main1: push cs ;establish DS addressability
pop ds ; by pointing it to the
assume ds:code ; code segment
cld ;clear DF for string ops
mov videocols,ah ;save columns displayed
mov videopage,bh ;save active video page
mov ah,3 ;get cursor information
int 10h
mov videocursormode,cx ;save cursor mode
mov videocursorpos,dx ;save cursor position
mov ax,40h ;point ES to the BIOS
mov es,ax ; data area
mov dx,es:[4Eh] ;save video start address
mov videostart,dx
;
;Define monochrome or color video attributes.
;
test byte ptr es:[63h],40h ;branch if this is
jnz colorvideo ; a color system
mov videoseg,0B000h ;monochrome attributes
mov border_attr,70h
mov menu_attr,07h
mov hilite_attr,70h
mov cursor_def,0C0Dh
jmp short vsave
colorvideo: mov videoseg,0B800h ;color attributes
mov border_attr,70h
mov menu_attr,4Fh
mov hilite_attr,70h
mov cursor_def,0607h
;
;Save video memory underlying the menu window, then open the window.
;
vsave: mov ah,1 ;hide the cursor
mov ch,20h
int 10h
mov cl,videocols ;determine window position
sub cl,32
mov window_x,cl ;save starting column number
mov ch,window_y
mov dx,cx
add dx,101Dh ;save coordinates of lower
mov window_end,dx ; right window corner
push cs ;point ES:DI to screen buffer
pop es
mov di,offset screen_buffer
mov ax,offset udr_vio2mem ;call SCANREGION routine to
mov cx,window_start ; buffer the contents of
mov dx,window_end ; video memory
call scanregion
call openwindow ;open printer menu window
mov al,hilite_attr ;draw menu selection bar
call drawmenubar
;
;Monitor the keyboard for keystrokes and act upon the ones received.
;
keyloop: mov ah,0 ;get a keystroke
int 16h
or al,al ;branch on extended keycodes
jz functionkey
;
;Output control codes if ENTER was pressed.
;
cmp al,13 ;check for ENTER keycode
jne escape
call outputlpt ;output indexed control codes
jmp keyloop ;return to input loop
;
;Close the window and exit if ESC was pressed.
;
escape: cmp al,27 ;check for ESC keycode
jne slash
jmp close ;jump to exit routines
;
;Jump down to the input line if the slash key was pressed.
;
slash: cmp al,"/" ;check for slash character
jne keyloop ;ignore anything else
mov al,menu_attr ;blank the menu bar
call drawmenubar
call scanline ;read input and send to LPT
mov al,hilite_attr ;redraw the menu bar
call drawmenubar
jmp keyloop ;loop back for more
;
;Send the corresponding control codes if a function key was pressed.
;
functionkey: cmp ah,59 ;determine whether or not a
jb keyloop ; function key was pressed
cmp ah,68
ja up_arrow
push ax ;save extended keycode
mov al,menu_attr ;erase the menu bar
call drawmenubar
pop ax ;recover keycode
sub ah,59 ;calculate new INDEX value
mov index,ah
mov al,hilite_attr ;draw new menu bar
call drawmenubar
call outputlpt ;output corresponding codes
jmp keyloop ;return to input loop
;
;Move the menu bar up one line if up-arrow was pressed.
;
up_arrow: cmp ah,72 ;check for up-arrow
jne dn_arrow
mov al,menu_attr ;erase the menu bar
call drawmenubar
dec index ;decrement INDEX and wrap
jns newbar ; if necessary
mov index,9
newbar: mov al,hilite_attr ;redraw the menu bar
call drawmenubar
jmp keyloop ;return to input loop
;
;Move the menu bar down one line if down-arrow was pressed.
;
dn_arrow: cmp ah,80 ;check for down-arrow
jne pgup
mov al,menu_attr ;erase the menu bar
call drawmenubar
inc index ;increment INDEX and wrap
cmp index,10 ; around if necessary
jne newbar ;jump to finish up
mov index,0
jmp newbar
;
;Flip to the preceding menu page if PgUp was pressed.
;
pgup: cmp ah,73 ;check for PgUp
jne pgdn
cmp pagecount,1 ;ignore if there is only
je retkey ; one menu
dec menupage ;set MENUPAGE to previous
jns newpage ; page and wrap around
mov al,pagecount ; if necessary
dec al
mov menupage,al
newpage: call writemenu ;write text of page to memory
mov al,hilite_attr ;redraw the menu bar
call drawmenubar
retkey: jmp keyloop ;return to input loop
;
;Flip to the next page if PgDn was pressed.
;
pgdn: cmp ah,81 ;check for PgDn
jne retkey
cmp pagecount,1 ;ignore if there is only
je retkey ; one menu
inc menupage ;adjust MENUPAGE
mov al,pagecount
cmp menupage,al
jne newpage ;jump to finish up
mov menupage,0
jmp newpage
;
;Close the menu window.
;
close: mov si,offset screen_buffer ;point SI to buffer
mov ax,offset udr_mem2vio ;call SCANREGION routine to
mov cx,window_start ; restore the contents of
mov dx,window_end ; video memory
call scanregion
;
;Restore the cursor mode and position, then exit.
;
restore: mov ah,2 ;restore position
mov bh,videopage
mov dx,videocursorpos
int 10h
mov ah,1 ;restore mode
mov cx,videocursormode
int 10h
jmp main_exit ;return from interrupt
main endp
;-----------------------------------------------------------------------------
; SCANREGION scans the cursor over the indicated region and calls a
; user-defined routine at each stop.
; Entry: AX - offset address of user-defined routine
; CH,CL - upper left corner of region
; DH,DL - lower right corner of region
;-----------------------------------------------------------------------------
addr_udr dw ? ;routine address
columns dw 0 ;number of columns in region
scanregion proc near
mov addr_udr,ax ;save address
push cx ;save starting cursor position
sub dl,cl ;calculate number of columns
inc dl
mov byte ptr columns,dl
sub dh,ch ;calculate number of rows
inc dh
mov cl,dh
xor ch,ch
pop dx ;retrieve cursor position
mov bh,videopage ;page number in BH
scanreg1: push cx ;save row counter
push dx ;save cursor position
mov cx,columns ;load column counter
scanreg2: mov ah,2 ;position cursor
int 10h
call word ptr cs:[addr_udr] ;call user-defined
inc dl ; routine and
loop scanreg2 ; advance the cursor
pop dx ;advance cursor to next row
inc dh ; and loop until all rows
pop cx ; are done
loop scanreg1
ret
scanregion endp
;-----------------------------------------------------------------------------
; UDR_VIO2MEM is called by SCANREGION to save the contents of a screen area.
; Entry: ES:DI - buffer address
;-----------------------------------------------------------------------------
udr_vio2mem proc near
mov ah,8 ;get character and attribute
int 10h ; under the cursor
stosw ;buffer them
ret
udr_vio2mem endp
;-----------------------------------------------------------------------------
; UDR_MEM2VIO is called by SCANREGION to write to a screen area.
; Entry: DS:SI - buffer address
;-----------------------------------------------------------------------------
udr_mem2vio proc near
push cx ;save CX
lodsw ;get character and attribute
mov bl,ah ;attribute to BL
mov ah,9 ;write character/attribute
mov cx,1
int 10h
pop cx ;restore CX and exit
ret
udr_mem2vio endp
;-----------------------------------------------------------------------------
; OPENWINDOW displays the printer control window.
;-----------------------------------------------------------------------------
ftext db "1 2 3 4 5 6 7 8 9 10"
openwindow proc near
mov ax,0600h ;blank window region
mov bh,menu_attr
mov cx,window_start
mov dx,window_end
int 10h
mov cx,window_start ;draw box around region to
mov dx,window_end ; form window border
mov bl,border_attr
call textbox
mov dx,window_start ;display window title
add dx,0102h
push dx
mov si,offset pname
mov cx,26
call writeln
pop dx
inc dh
push dx ;draw first horizontal
mov cx,26 ; divider
mov bl,menu_attr
call drawhorizontal
pop dx
inc dh
mov cx,10 ;draw "F1".."F10" designators
mov si,offset ftext
open1: push cx
push dx
mov ah,2
int 10h
mov ax,0E46h
int 10h
inc dl
mov cx,2
call writeln
pop dx
inc dh
pop cx
loop open1
push dx ;draw second horizontal
mov cx,26 ; divider
mov bl,menu_attr
call drawhorizontal
pop dx
inc dh
push dx ;draw input line
mov al,hilite_attr
mov cx,26
call writeattr
pop dx
inc dh
mov si,offset menutxt ;display menu line
mov cx,24
call writeln
call writemenu ;display current menu
ret
openwindow endp
;-----------------------------------------------------------------------------
; WRITELN displays a text string of known length.
; Entry: DS:SI - string address
; DH,DL - starting row and column
; CX - string length
;-----------------------------------------------------------------------------
writeln proc near
mov ah,2 ;position cursor
mov bh,videopage
int 10h
wln1: lodsb ;get a byte
mov ah,0Eh ;display it and advance the
int 10h ; cursor one column
loop wln1 ;loop until done
ret
writeln endp
;-----------------------------------------------------------------------------
; TEXTBOX draws a box of specified color around a region.
; Entry: CH,CL - upper left corner row and column
; DH,DL - lower right corner row and column
; BL - attribute
;-----------------------------------------------------------------------------
wide dw 0 ;region width
height dw 0 ;region height
upleft dw ? ;upper left row and column
textbox proc near
mov upleft,cx ;save coordinates
sub dh,ch ;calculate height
dec dh
mov byte ptr height,dh
sub dl,cl ;calculate width
dec dl
mov byte ptr wide,dl
mov bh,videopage ;set BH for video calls
mov ah,2 ;draw upper left corner
mov dx,upleft
int 10h
mov ax,09DAh
mov cx,1
int 10h
inc dl ;draw top horizontal line
mov cx,wide
call drawhorizontal
mov ah,2 ;draw upper right corner
add dl,byte ptr wide
int 10h
mov ax,09BFh
mov cx,1
int 10h
mov ah,2 ;draw lower left corner
mov dx,upleft
add dh,byte ptr height
inc dh
int 10h
mov ax,09C0h
mov cx,1
int 10h
inc dl ;draw bottom horizontal line
mov cx,wide
call drawhorizontal
mov ah,2 ;draw lower right corner
add dl,byte ptr wide
int 10h
mov ax,09D9h
mov cx,1
int 10h
mov dx,upleft ;draw left vertical
inc dh
push dx
mov cx,height
call drawvertical
pop dx
add dl,byte ptr wide ;draw right vertical
inc dl
mov cx,height
call drawvertical
ret
textbox endp
;-----------------------------------------------------------------------------
; DRAWHORIZONTAL draws a horizontal line of specified length.
; Entry: DH,DL - starting row and column
; CX - length
; BL - attribute
;-----------------------------------------------------------------------------
drawhorizontal proc near
mov ah,2 ;set cursor position
mov bh,videopage
int 10h
mov ax,09C4h ;draw line
int 10h
ret
drawhorizontal endp
;-----------------------------------------------------------------------------
; DRAWVERTICAL draws a vertical line of specified length.
; Entry: DH,DL - starting row and column
; CX - length
; BL - attribute
;-----------------------------------------------------------------------------
drawvertical proc near
mov bh,videopage
vdraw1: push cx
mov ah,2 ;position cursor
int 10h
mov ax,09B3h ;draw one character
mov cx,1
int 10h
inc dh ;move cursor to next line
pop cx
loop vdraw1 ;loop until done
ret
drawvertical endp
;-----------------------------------------------------------------------------
; WRITEMENU displays a page of menu text.
; Entry: MENUPAGE - menu page number
;-----------------------------------------------------------------------------
writemenu proc near
mov al,menupage ;point SI to menu text
mov bl,200
mul bl
mov si,ax
add si,offset menu_table
mov ax,0600h ;blank current menu
mov bh,menu_attr
mov cx,window_start
add cx,0308h
push cx
mov dx,cx
add dx,0913h
int 10h
pop dx
mov cx,10 ;determine how many lines are
mov al,pagecount ; to be written
dec al
cmp al,menupage
jne wmloop
mul ten
mov cx,linecount
sub cx,ax
jcxz nomenu
wmloop: push cx ;save line counter
push dx ;save cursor position
mov cx,20 ;display one line of menu text
call writeln
pop dx ;advance cursor to next line
inc dh
pop cx
loop wmloop ;loop until done
nomenu: ret
writemenu endp
;-----------------------------------------------------------------------------
; WRITEATTR writes a series of attribute bytes to video memory. Writing is
; performed during the vertical retrace on color adapters.
; Entry: AL - attribute
; CX - number of attributes to write
; DH,DL - starting row and column
;-----------------------------------------------------------------------------
writeattr proc near
push ax ;save attribute
mov al,videocols ;calculate address of the
mul dh ; indicated character cell
xor dh,dh ; in video memory
add ax,dx
shl ax,1
add ax,videostart
mov di,ax
inc di
mov es,videoseg ;point ES to video memory
cmp videoseg,0B000h ;don't wait if display
je nowait ; is monochrome
mov dx,3DAh ;address CRTC status register
wait_for_vert: in al,dx ;wait for vertical retrace
test al,8
jz wait_for_vert
nowait: pop ax ;retrieve attribute
attrloop: stosb ;write attributes
inc di
loop attrloop
ret
writeattr endp
;-----------------------------------------------------------------------------
; DRAWMENUBAR draws or erases the menu selection bar.
; Entry: AL - attribute
; INDEX - selection index number
;-----------------------------------------------------------------------------
drawmenubar proc near
mov dx,window_start ;calculate starting row and
add dh,index ; column
add dx,0302h
mov cx,26 ;26 character cells to alter
call writeattr ;write the attribute bytes
ret
drawmenubar endp
;-----------------------------------------------------------------------------
; SCANLINE reads an input string from the keyboard, converts ASCII numbers
; to binary, and sends them to the designated printer port.
;-----------------------------------------------------------------------------
input_pos dw ? ;row and column of input line
scanline proc near
push cs ;point ES:DI to input buffer
pop es
mov di,offset input_buffer
mov dx,window_start ;position the cursor
add dx,0E02h
mov input_pos,dx ;save coordinates
mov ah,2
mov bh,videopage
int 10h
mov ah,1 ;unblank the cursor
mov cx,cursor_def
int 10h
xor cl,cl ;zero character count
;
;Read and buffer keystrokes until ENTER or ESC is pressed.
;
scanloop: mov ah,0 ;wait for a keystroke
int 16h
cmp al,8 ;check for backspace
jne scan1
or cl,cl ;ignore backspace if count
jz scanloop ; is zero
call backspace ;perform backspace
jmp scanloop ;return to input loop
scan1: cmp al,13 ;branch if ENTER pressed
je endscan
cmp al,27 ;branch if ESC pressed
je esckey
cmp al,32 ;ignore control codes
jb scanloop
cmp cl,255 ;ignore the character if
je scanloop ; input buffer is full
call insert_char ;buffer the character
jmp scanloop ;return to input loop
;
;Parse the text just entered and output binary codes to the printer.
;
endscan: mov es:[di],al ;buffer EOL character
push bx ;save registers
push cx
push di
mov si,offset input_buffer ;point SI to text
mov di,offset output_buffer ;point DI to output buffer
call asc2bin ;convert ASCII to binary
jnc checkstat ;continue if no error
mov si,offset errtxt1 ;display error message if
scan2: call win_error ; code string is invalid
pop di ;restore registers
pop cx
pop bx
jmp scanloop ;return to input loop
checkstat: call lptstatus ;check printer status
jnc scan3 ;continue if printer ready
mov si,offset errtxt2 ;display error message
jmp scan2
scan3: mov si,offset output_buffer ;point SI to codes
call sendlptcodes ;output them
add sp,6 ;clean up the stack
;
;Clear the input line and exit.
;
esckey: mov ah,1 ;blank the cursor
mov ch,20h
int 10h
mov ah,2 ;position cursor on input line
mov dx,input_pos
mov bh,videopage
int 10h
mov ax,0A20h ;blank the input line
mov cx,25
int 10h
ret ;and exit
scanline endp
;-----------------------------------------------------------------------------
; BACKSPACE deletes the character left of the cursor.
;-----------------------------------------------------------------------------
backspace proc near
dec cl ;decrement character count
dec di ;decrement buffer pointer
cmp cl,24 ;branch if count > 24
ja refresh
push cx ;save character count
mov ah,0Eh ;move the cursor back one
int 10h ; space
mov ax,0A20h ;overwrite character under the
mov cx,1 ; cursor with a space
int 10h
pop cx ;restore count
ret
refresh: push cx ;save character count
mov si,di ;scroll the input line one
sub si,25 ; character to the right to
mov cx,25 ; blank the last character
mov dx,input_pos
call writeln
pop cx ;restore count
ret
backspace endp
;-----------------------------------------------------------------------------
; INSERT_CHAR inserts a character into the input buffer.
;-----------------------------------------------------------------------------
insert_char proc near
stosb ;buffer the character
inc cl ;increment character count
cmp cl,25 ;branch if count > 25
ja refresh
mov ah,0Eh ;display the character
int 10h
ret
insert_char endp
;-----------------------------------------------------------------------------
; ASC2BIN converts an ASCII text string into a string of binary bytes.
; Entry: DS:SI - text string address
; ES:DI - binary buffer address
; Exit: CF clear = no error, CF set = error
; CL - number of codes converted
;-----------------------------------------------------------------------------
asc2bin proc near
push di ;save count byte address
inc di ;advance past count byte
xor cl,cl ;zero count
xor bh,bh ;zero BH
a2bloop: mov dx,0A00h ;initialize DH (base) and
; DL (accumulator)
;
;Search until the first character of an entry or EOL marker is encountered.
;
nextchar: lodsb ;get a character
call check_20_2c ;skip spaces, commas, and tabs
jz nextchar
cmp al,0Dh ;done if EOL encountered
je endconvert
cmp al,"/" ;done if slash encountered
je endconvert
call check_22_27 ;check for " or ' mark
jnz isdigit ;branch if neither
;
;Buffer everything between quotation marks or apostrophes.
;
inquotes: lodsb ;get next character
call check_22_27 ;exit loop if ending quote
jz nextchar ; symbol is encountered
cmp al,0Dh ;exit if line terminator is
je endconvert ; is encountered
stosb ;buffer the character
inc cl ;increment count
jz a2berror ;error if count > 255
jmp inquotes ;loop back for more
;
;Convert a numeric entry to binary.
;
digitloop: lodsb ;get next character
call check_20_2c ;check for delimiter marking
jz endnumtext ; end of the current number
call check_22_27
jz endnumtext
cmp al,0Dh ;check for end-of-line
je endnumtext
isdigit: cmp al,30h ;digit is valid if it lies
jb a2berror ; between "0" and "9"
cmp al,3Ah
jb ascii_adjust
and al,0DFh ;capitalize presumed alpha
cmp al,"X" ;change base to 16 for hex
jne check_hex ; numbers if "X" is found
mov dh,16
jmp digitloop
check_hex: cmp dh,16 ;error if this isn't base 16
jne a2berror
cmp al,41h ;digit is valid if it lies
jb a2berror ; between "A" and "F"
cmp al,46h
ja a2berror
sub al,7 ;hex conversion
ascii_adjust: sub al,30h ;ASCII to binary conversion
mov bl,al ;save digit
mov al,dl ;multiply accumulator by base
mul dh
add ax,bx ;add new digit to result
or ah,ah ;error if result > 255
jnz a2berror
mov dl,al ;put new value in accumulator
jmp digitloop ;get next digit
a2berror: pop bx ;clean up the stack
xor cl,cl ;zero CX on error
mov es:[bx],cl ;store zero in buffer
stc ;set CF for error
ret
endnumtext: mov al,dl ;write accumulator value to
stosb ; binary buffer
inc cl ;increment count
jz a2berror ;error if count > 255
dec si ;point SI to terminator
jmp a2bloop ;search for next number
;
;Do housekeeping and exit.
;
endconvert: pop bx ;recover count byte address
mov es:[bx],cl ;store count in buffer
clc ;clear CF for exit
ret
asc2bin endp
;-----------------------------------------------------------------------------
; CHECK_20_2C returns a flag if AL holds an ASCII space, comma, or tab.
; Entry: AL - character
; Exit: ZF clear = no match, ZF set = space or comma
;-----------------------------------------------------------------------------
check_20_2c proc near
cmp al,20h ;check for ASCII space
je ischar1
cmp al,2Ch ;check for ASCII comma
je ischar1
cmp al,9 ;check for ASCII tab
ischar1: ret
check_20_2c endp
;-----------------------------------------------------------------------------
; CHECK_22_27 returns a flag if AL holds an ASCII quote mark or apostrophe.
; Entry: AL - character
; Exit: ZF clear = no match, ZF set = space or comma
;-----------------------------------------------------------------------------
check_22_27 proc near
cmp al,22h ;check for quotation mark
je ischar2
cmp al,27h ;check for apostrophe
ischar2: ret
check_22_27 endp
;-----------------------------------------------------------------------------
; LPTSTATUS checks the status of the indicated printer.
; Entry: LPT_NUMBER - printer number (0-2)
; Exit: CF clear = printer ready, CF set = printer not ready
;-----------------------------------------------------------------------------
lptstatus proc near
mov ah,2 ;get status byte from BIOS
mov dx,lpt_number
int 17h
test ah,29h ;check bits 0, 3, and 5
jnz notready ;error if one is set
test ah,0F9h ;check all but bits 1 and 2
jz notready ;error if all are zero
clc ;clear CF for return
ret
notready: stc ;set CF for return
ret
lptstatus endp
;-----------------------------------------------------------------------------
; SENDLPTCODES sends a string of bytes to the designated printer.
; Entry: DS:SI - string (first byte = length)
; LPT_NUMBER - printer number (0-2)
;-----------------------------------------------------------------------------
sendlptcodes proc near
lodsb ;get string length in CX
mov cl,al
xor ch,ch
jcxz nosend ;exit if length is zero
mov dx,lpt_number ;initialize DX
sendloop: lodsb ;loop until all bytes are
mov ah,0 ; output
int 17h
loop sendloop
nosend: ret
sendlptcodes endp
;-----------------------------------------------------------------------------
; OUTPUTLPT sends the string of control codes indexed by INDEX and MENUPAGE
; to the printer designated by LPT_NUMBER.
;-----------------------------------------------------------------------------
outputlpt proc near
call lptstatus ;check printer status
jnc isready
mov si,offset errtxt2 ;error if printer is not
call win_error ; ready
no_output: ret
isready: mov al,menupage ;calculate offset address
mul ten ; of control code string
add al,index ; from MENUPAGE and INDEX
cmp ax,linecount ;make sure a control code
jae no_output ; string is defined
mov cx,ax
mov si,code_table ;find offset address of the
jcxz nocalc ; corresponding code string
outloop: mov al,[si] ; by scanning the linked
inc al ; list of control codes
add si,ax
loop outloop
nocalc: call sendlptcodes ;output the code string
ret
outputlpt endp
;-----------------------------------------------------------------------------
; WIN_ERROR displays an error message and waits for a keystroke.
; Entry: DS:SI - text address
;-----------------------------------------------------------------------------
menutxt db "Esc Enter /",20h,18h,19h,20h,"PgUp PgDn"
errtxt1 db "Error: Invalid entry",4 dup (20h)
errtxt2 db "Error: Printer not ready"
win_error proc near
call disp_err_msg ;display error message
mov ax,0E07h ;beep
int 10h
win1: mov ah,1 ;loop until a key is
int 16h ; pressed
jz win1
mov si,offset menutxt ;restore original text
call disp_err_msg
ret
win_error endp
;-----------------------------------------------------------------------------
; DISP_ERR_MSG displays a window error message.
; Entry: DS:SI - text address
;-----------------------------------------------------------------------------
disp_err_msg proc near
mov ah,3 ;get cursor position
mov bh,videopage
int 10h
push dx ;save it
mov dx,window_start ;display error message
add dx,0F02h
mov cx,24
call writeln
mov ah,2 ;restore cursor position
pop dx
int 10h
ret
disp_err_msg endp
;=============================================================================
; INITIALIZE handles command line directives and installation/deinstallation.
;=============================================================================
errmsg1 db "Usage: SETUP2 [d:][path][filename] | [/C codes] | [/U]$"
errmsg2 db "Already installed$"
errmsg3 db "Cannot uninstall$"
errmsg4 db "Not installed$"
errmsg6 db "Invalid code string$"
errmsg7 db "Printer not ready$"
errmsg8 db "File not found$"
errmsg9 db "File too large$"
errmsg10 db "Insufficient memory$"
errmsg11 db "Make file error - line $"
initmsg1 db "Uninstalled$"
installed db 0
initialize proc near
assume cs:code, ds:code
;
;See if a copy is already resident in memory.
;
cld ;clear DF
mov word ptr [begin],0 ;initialize fingerprint
xor bx,bx ;zero BX for start
mov ax,cs ;keep CS value in AX
init1: inc bx ;increment search segment value
mov es,bx
cmp ax,bx ;not installed if current
je parse ; segment is looped back to
mov si,offset begin ;search this segment for ASCII
mov di,si ; fingerprint
mov cx,16
repe cmpsb
jne init1 ;loop back if not found
mov installed,1 ;set installed flag
;
;Parse the command line for entries and take appropriate action.
;
parse: mov si,81h ;point SI to command line
parseloop: lodsb ;get a character
cmp al,20h ;skip it if it's a space
je parseloop
cmp al,0Dh ;exit loop when a carriage
jne init2 ; return is encountered
jmp install
init2: cmp al,"/" ;check for "/" modifier
je init3 ;branch if found
mov dx,offset errmsg2 ;initialize error pointer
cmp installed,0 ;check installed flag
jne error_exit ;error if already installed
dec si ;point SI to filename
call make ;process printer make file
jmp setvec ;install
init3: lodsb ;get parameter
and al,0DFh ;capitalize
cmp al,"U" ;branch to handling routine
je uninstall
cmp al,"C"
je readcodes
;
;An error was encountered in parsing. Display error message and exit.
;
syntax_error: mov dx,offset errmsg1 ;display error message
error_exit: mov ah,9
int 21h
mov ax,4C01h ;exit with ERRORLEVEL = 1
int 21h
;
;Process a /U command line parameter.
;
uninstall: mov dx,offset errmsg4 ;error if not installed
cmp installed,1
jne error_exit
call remove ;call uninstall routine
mov dx,offset errmsg3 ;exit on error
jc error_exit
mov dx,offset initmsg1 ;display "Uninstalled"
mov ah,9 ; message
int 21h
mov ax,4C00h ;exit with ERRORLEVEL = 0
int 21h
;
;Process a /C command line parameter.
;
readcodes: push cs ;set ES to code segment
pop es
mov di,offset menu_table ;point DI to scratch area
call asc2bin ;convert text to binary
mov dx,offset errmsg6 ;exit on conversion error
jc error_exit
or cl,cl ;exit if no codes were entered
jz error_exit
call lptstatus ;check printer status
mov dx,offset errmsg7
jc error_exit ;error if printer not ready
mov si,offset menu_table ;point SI to output buffer
call sendlptcodes ;output control codes
read_exit: mov ax,4C00h ;exit with ERRORLEVEL = 0
int 21h
;
;Make sure a copy isn't already loaded before installing this one.
;
install: mov dx,offset errmsg2 ;initialize error pointer
cmp installed,0 ;check installed flag
jne error_exit ;error if already installed
;
;Reset the interrupt 9h vector to an internal handler.
;
setvec: mov ax,3509h ;save old vector
int 21h
mov word ptr int9h,bx
mov word ptr int9h[2],es
mov ax,2509h ;then set the new vector
mov dx,offset kbint
int 21h
;
;Deallocate the program's environment block.
;
mov ax,ds:[2Ch] ;get environment segment
mov es,ax
mov ah,49h ;free it
int 21h
;
;Display copyright notice, then terminate and remain resident in memory.
;
mov ah,9 ;display message
mov dx,offset program
int 21h
mov ax,3100h ;terminate with ERRORLEVEL = 0
mov dx,end_offset ;calculate amount of memory
sub dx,offset code - 15 ; to reserve in DX
mov cl,4 ;convert bytes to paragraphs
shr dx,cl
int 21h ;terminate
initialize endp
;-----------------------------------------------------------------------------
; REMOVE deallocates the memory block addressed by ES and restores the
; interrupt vector displaced on installation.
; Entry: ES - segment to release
; Exit: CF clear - program uninstalled
; CF set - can't uninstall
;-----------------------------------------------------------------------------
remove proc near
mov cx,es ;abort if the interrupt 9
mov ax,3509h ; vector has been altered
int 21h ; since installation
mov ax,es
cmp ax,cx
jne remove_error
mov es,cx
mov ah,49h ;free memory given to
int 21h ; original program block
jc remove_error ;branch on error
push ds ;restore interrupt vector
assume ds:nothing
mov ax,2509h
lds dx,es:[int9h]
int 21h
pop ds
assume ds:code
not word ptr es:[begin] ;destroy ASCII fingerprint
clc ;clear CF for exit
ret
remove_error: stc ;set CF to indicate program
ret ; couldn't be uninstalled
remove endp
;=============================================================================
; MAKE reads a make file and builds the program's menu and code tables.
;=============================================================================
handle dw ? ;file handle
filesize dw ? ;file size in bytes
fileseg dw ? ;file buffer segment
make proc near
mov dx,si ;save address of first char
make1: lodsb ;find end of filename
cmp al,0Dh
je make2
cmp al,20h
jne make1
make2: mov byte ptr [si-1],0 ;convert filename to ASCIIZ
;
;Open the printer make file and read it into memory.
;
mov ax,3D00h ;open the make file
int 21h
mov dx,offset errmsg8 ;error if call failed
jc make_error2
mov handle,ax ;save file handle
mov bx,ax ;determine the file's size
mov ax,4202h ; in bytes
xor cx,cx
xor dx,dx
int 21h
or dx,dx ;error if greater than 64K
jz make3
make_error1: mov dx,offset errmsg9
make_error2: jmp error_exit
make3: cmp ax,0FFD0H
ja make_error1
mov filesize,ax ;save file size
mov ah,4Ah ;shrink memory allocation
mov bx,1000h ; to 64K
push cs
pop es
int 21h
mov dx,offset errmsg10 ;insufficient memory if
jc make_error2 ; call failed
mov ah,48h ;request enough additional
mov bx,filesize ; memory to read in the
add bx,18 ; make file
mov cl,4
shr bx,cl
int 21h
mov dx,offset errmsg10 ;insufficient memory if
jc make_error2 ; call failed
mov fileseg,ax ;save segment address
mov ax,4200h ;reset file pointer
mov bx,handle
xor cx,cx
xor dx,dx
int 21h
mov ah,3Fh ;read make file into the
mov bx,handle ; portion of memory just
mov cx,filesize ; allocated
xor dx,dx
assume ds:nothing
mov ds,fileseg
int 21h
mov ah,3Eh ;close the file
mov bx,handle
int 21h
mov bx,filesize ;find the end of the file
cmp byte ptr [bx-1],1Ah ;delete last character if it
jne make4 ; is a Ctrl-Z
dec bx
make4: cmp word ptr [bx-2],0A0Dh ;add a carriage return/
je make5 ; line feed pair if the
mov word ptr [bx],0A0Dh ; file doesn't already
add bx,2 ; end with one
make5: mov byte ptr [bx],0 ;write terminating zero
;
;Copy the printer name from the printer make file.
;
push cs ;initialize DS:SI to address
pop es ; file buffer and ES:DI to
xor si,si ; address printer name
mov di,offset pname ; string
pname1: call skip_comment ;skip comment lines
pname2: cmp byte ptr [si],0 ;exit if EOF is reached
jne pname3
jmp make_exit
pname3: mov cx,26
pname4: lodsb ;get a character
cmp al,0Dh ;quit now if the character is
jne pname5 ; a carriage return
inc si
jmp short extract_text
pname5: stosb ;otherwise copy the character
loop pname4 ;copy up to 26 characters
call nextline ;advance to start of next line
;
;Extract the menu text entries from the printer make file.
;
extract_text: mov di,offset menu_table ;initialize DI
push si ;save starting address
text1: call skip_comment ;skip comment lines
text2: cmp byte ptr [si],0 ;exit if EOF is reached
je extract_codes
mov cx,20
text3: lodsb ;get a character
cmp al,0Dh ;finish this line and proceed
je text5 ; to the next if a semicolon
cmp al,";" ; or carriage return is
je text4 ; encountered
stosb ;copy the character
loop text3 ;loop back for another
text4: call add_spaces ;pad text with spaces
inc linecount ;register the entry
call nextline ;find start of next line
jmp text1
text5: call add_spaces ;pad text with spaces
inc linecount ;register the entry
inc si ;advance SI to start of
jmp text1 ; next line
;
;Extract the control codes from the printer make file.
;
extract_codes: mov code_table,di ;save code table address
pop si ;point SI to first line
mov cx,linecount ;initialize line counter
jcxz calc_pages ;skip if no lines
codes1: call skip_comment ;skip comment lines
codes2: lodsb ;get a character
cmp al,0Dh ;error if carriage return is
je code_error ; found before semicolon
cmp al,";" ;loop back for another if this
jne codes2 ; one isn't a semicolon
push cx ;if a semicolon was found, call
call asc2bin ; ASC2BIN to convert the text
pop cx ; string that follows to
jc code_error ; to binary
inc si ;advance SI to next line
loop codes1 ;loop until all lines are done
;
;Calculate the number of menu pages.
;
calc_pages: push cs ;restore DS
pop ds
assume ds:code
mov end_offset,di ;save ending address
mov ax,linecount ;exit now if there are
or ax,ax ; no entries
jz make_exit
dec ax ;calculate number of menu
div ten ; pages
inc al
mov pagecount,al ;store count in PAGECOUNT
make_exit: mov ah,49h ;free memory allocated for
mov es,fileseg ; the file buffer
int 21h
ret
;
;Display the line number where a make error occurred, then exit.
;
code_error: push cs ;reset DS
pop ds
mov ah,9 ;display error message
mov dx,offset errmsg11
int 21h
mov ax,linecount ;display line number
sub ax,cx
inc ax
call bin2asc
mov ax,4C01h ;exit with ERRORLEVEL = 1
int 21h
make endp
;-----------------------------------------------------------------------------
; BIN2ASC converts a binary value in AX to ASCII and displays it.
;-----------------------------------------------------------------------------
bin2asc proc near
mov bx,10 ;initialize divisor word and
xor cx,cx ; digit counter
b2a1: inc cx ;increment digit count
xor dx,dx ;divide by 10
div bx
push dx ;save remainder on stack
or ax,ax ;loop until quotient is zero
jnz b2a1
b2a2: pop dx ;retrieve a digit from stack
add dl,30h ;convert it to ASCII
mov ah,2 ;display it
int 21h
loop b2a2 ;loop until done
ret
bin2asc endp
;-----------------------------------------------------------------------------
; ADD_SPACES pads a menu text string with space characters.
;-----------------------------------------------------------------------------
add_spaces proc near
jcxz add_exit
mov al,20h
rep stosb
add_exit: ret
add_spaces endp
;-----------------------------------------------------------------------------
; SKIP_COMMENT advances SI to the first non-comment line.
;-----------------------------------------------------------------------------
skip_comment proc near
cmp byte ptr [si],"#"
jne skip_exit
call nextline
jmp skip_comment
skip_exit: ret
skip_comment endp
;-----------------------------------------------------------------------------
; NEXTLINE advances SI to the beginning of the next line.
;-----------------------------------------------------------------------------
nextline proc near
lodsb
cmp al,0Dh
jnz nextline
inc si
ret
nextline endp
;=============================================================================
; Buffer areas used after installation.
;=============================================================================
pc = $
screen_buffer = pc
pc = pc + 1020
input_buffer = pc
pc = pc + 256
output_buffer = pc
pc = pc + 256
menu_table = pc
code ends
end begin