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