        .XLIST
        PAGE    ,132
        TITLE   PALET2A.ASM
        .LIST
name palet

; Program sets the EGA palette registers from parameters given on the command
; line.
; Release 2 of palette.asm by Charles Lazo III.
; Enhanced, debugged and recompiled by:
;       Charles Lazo III  [72210,10]  and  Tim Worley  [71336,730]
;
; Detail of changes:
;       'E' switch now traps changes to EGA registers in all display modes
;       'T' switch added to trap changes to EGA registers in text mode only
;       'D' parameter added to return EGA registers to default values
;       'X' switch unchanged (turns off both E and T switches)
; Entire on-screen usage text rewritten.
; Current switch status is displayed each time program is called.
; Switch settings now remain in effect until changed on the command line.

; Release 2a of palette.asm by Lew Paper
;
; Detail of changes:
;       'B' switch now modifies the blink attribute from the starting
;           intense background.
;           'B' toggles it from last time palette reset it.
;           'B+' turns on blinking.
;           'B-' turns on intense background colors.
;       'U' switch now modifies underlining from the starting OFF.
;           'U' toggles it from last time palette reset it, underlining at
;               the bottom of a character.
;           'U+' turns on underlining at the bottom of a character.
;           'U-' turns off underlining.
;           'U<n>' underlines at row n, where n is decimal.  For an 25 line
;                display, 0 <= n <= 13.  For a 43 line display, 0 <= n <= 8.
;       'F' switch now disables palet.  ARCMASTER apparently changes the
;           mode of an EGA, and palet's resetting makes it unusable.
;       'N' switch now enables palet again.  Use it if you have disabled
;           palet with an F switch and want to enable it with no changes.
;       Changed octal palette values to decimal.
; All changes are controlled by the variable LP_Version_2A.

LP_Version_2A   EQU     1               ; Use Version 3 changes

rt              equ     0dh
lf              equ     0ah
of              equ     offset
farr            equ     dword ptr

                IF      LP_Version_2A
no_underline_row EQU    1FH             ; Underline out of display range
blink_on        EQU     1               ; Turn blinking on
blink_off       EQU     0               ; Turn intense background on



BIOS_seg        segment at 40H

                org     63H
addr_6845       label   word            ; Port to select register for
                                        ; CRT controller

                org     85H
points          label   word            ; Height of character matrix in lines.
                                        ; 25 rows gives points = 14
                                        ; 43 rows gives points = 8
                                        ; 50 rows gives points = 7
BIOS_seg         ends
                ENDIF                   ; LP_Version_2A
                code    segment
                assume  cs:code
                IF      LP_Version_2A
                assume  ds:nothing, es:nothing
                                        ;    This line doesn't change the
                                        ; original program.  In either
                                        ; case, all memory references which
                                        ; would normally use DS have a CS
                                        ; override.
                ENDIF                   ; LP_Version_2A

                org     100h

begin:          jmp     start

key1            dw      0cadeh          ; key values stored in code to monitor
key2            dw      0d1bah          ;   TSR resident status

                IF      LP_Version_2A
underline_line  DB      no_underline_row
                                        ; Underline row
start_of_EGA_settings EQU (of underline_line)
length_of_EGA_settings EQU ((of old_int_10) - start_of_EGA_settings)
blink_value     DB      blink_off       ; INT 10H BL value for blinking
                ENDIF                   ; LP_Version_2A
set_values      db      16 dup(0ffh)    ; attribute values to place in palette

; old_int_10 must immediately follow last byte of set_values since its offset
; is used later to detect overflow

old_int_10      dw      ?,?             ; for segment and offset of old int 10h

our_call        db      0               ; flag that lets us only change palette

set_palette     proc    near
                inc     es:our_call     ; lets our set palette requests go thru
                push    bx              ; save registers used
                push    cx
                IF      LP_Version_2A
                push    dx
                ENDIF                   ; LP_Version_2A
                push    si
                mov     cx,16           ; up to 16 palette registers to set
                mov     si,of set_values; point to new attributes
next_attribute: mov     bx,16           ; compute palette register for attribute
                sub     bx,cx
                lodsb                   ; get attribute to set
                cmp     al,0ffh         ; if ff here, then don't set
                jne     set_register
                loop    next_attribute  ; set all specified palette registers
                jmp     short set_done  ; done
set_register:   mov     bh,al           ; attribute to bh
                mov     ax,1000h        ; set palette register function
                int     10h             ; of ROM BIOS video service
                loop    next_attribute  ; set all specified palette registers

                IF      LP_Version_2A
set_done:
                mov     bl,blink_value  ; Set blinking through BIOS
                mov     ax,1003H
                int     10H

                push    ds              ; Set underlining through direct
                                        ; hardware accesses
                assume  ds:BIOS_seg     ; Get address of CRT Controller
                mov     ax,BIOS_seg
                mov     ds,ax
                mov     dx,addr_6845    ; Selector port for CRT Controller
                mov     al,14h          ; Underline register location
                out     dx,al           ; Select underline register
                inc     dx              ; Data port for CRT Controller
                assume  ds:nothing
                pop     ds
                mov     al,underline_line
                                        ; location of the underline.  Note
                                        ; that underline off has 1fh, which
                                        ; is usually too big to show

                out     dx,al
                dec     es:our_call     ; disallow palette register sets
                pop     si              ; restore registers
                pop     dx
                ELSE                    ; LP_Version_2A
set_done:       dec     es:our_call     ; disallow palette register sets
                pop     si              ; restore registers
                ENDIF                   ; LP_Version_2A
                pop     cx
                pop     bx
                ret
set_palette     endp

graphics        db      0               ; =1 if graphics, =0 if text
exclude         db      0               ; =1 text & graphx mode changes excluded
txt_exclude     db      0               ; =1 text mode changes only excluded
                IF      LP_Version_2A
palet_off       db      0               ; =1 disable palet entirely
                ENDIF                   ; LP_Version_2A

new_int_10      proc    far             ; routine modifies the int10h interrupt
                IF      LP_Version_2A
                cmp     palet_off,1     ; Is palet disabled?
                je      go_on           ; Yes.  Bypass it.
                ENDIF                   ; LP_Version_2A
                cmp     ah,0            ; a mode set request?
                je      mode_set        ; yeah, check it out
                cmp     ah,11h          ; SPECTRUM makes this choice; it resets
                                        ;   the EGA environment
                je      reset           ; reset palette registers after the call
                cmp     ah,12h          ; CodeView uses this call
                je      reset
                cmp     ah,10h          ; is it a set palette registers call?
                je      func_10         ; yes, must pass our filter
go_on:          jmp     farr old_int_10 ; pass execution to old routine

mode_set:       cmp     al,3            ; an attempt to set a text mode?
                jbe     text_mode       ; yeah, set the mode, then reset palette
                cmp     al,7            ; text mode 7?
                je      text_mode       ; same

                mov     graphics,1      ; note the setting of a graphics mode
                cmp     txt_exclude,1   ; allow graphics mode palette changes?
                je      go_on           ; yes, allow to pass without reset
                jmp     short reset     ; else, reset palette after mode set

text_mode:      mov     graphics,0      ; note the setting of a text mode

reset:          pushf                   ; simulate an interrupt
                call    farr old_int_10 ;   and set requested text mode
                sti                     ; interrupts ok
                push    ax              ; our data is in current cs
                push    ds
                push    es
                mov     ax,cs
                mov     ds,ax
                mov     es,ax
                call    set_palette     ; reset the palette in case set by above
                pop     es
                pop     ds
                pop     ax
                iret                    ; return to our caller

func_10:        cmp     txt_exclude,1   ; is text exclude variable set?
                jne     no_txt_exclude  ; no, not considerable
                cmp     graphics,1      ; well, then is it a graphics mode?
                je      go_on           ; yes, allow palette changes to pass
no_txt_exclude: cmp     exclude,1       ; exclude other palette changes?
                jne     go_on           ; no, let the palette change go through
                cmp     our_call,1      ; if it is our call let it go through,
                je      go_on
                iret                    ;   else do nothing
new_int_10      endp

; End of resident portion of palet

error:          mov     ah,9            ; let DOS send it
                int     21h
                mov     ax,4c01h        ; terminate with errorlevel 1
                int     21h

wrong_DOS       db      rt,lf,'Wrong DOS version; must use DOS 2.0 or higher.'
                db      rt,lf,'$'

no_EGA          db      rt,lf,'You must have an EGA installed to use this '
                db      'program.',rt,lf,'$'

                IF      LP_Version_2A
not_installed   db      rt,lf,'palet must be installed before you use the '
                db      '"F" or "N" command',rt,lf,'$'
                ENDIF                   ; LP_Version_2A
; This routine is used to detect the prior load of the program as a TSR.  If
; there has been no prior load, then the routine will return with the zero flag
; set.  ZF will be reset if there has been a prior load and in that case the
; ES register will point to the PSP of the prior load.

TSR_detect      proc    near            ; proc will detect a prior load as a TSR
                mov     cx,cs           ; start at PSP and look at memory below
                dec     cx              ; don't hang on this PSP
                mov     ax,20cdh        ; "backwords" int 20h instruction
                mov     bx,key1         ; first key to test
                mov     dx,key2         ; second key to test
next_paragraph: mov     es,cx           ; address candidate PSP
                cmp     es:[0],ax       ; make sure a PSP not some DOS buffer
                je      int_20_found    ; found int 20h signature
                loop    next_paragraph  ; continue till all paragraphs checked
                jmp     short no_load   ; no prior load; indicate and return
int_20_found:   cmp     es:key1,bx      ; match our first key?
                je      key1_found      ; found key1; maybe key2 too?
                loop    next_paragraph  ; continue till all paragraphs checked
                jmp     short no_load   ; no prior load; indicate and return
key1_found:     cmp     es:key2,dx      ; match our second key?
                je      prior_load      ; we're already installed; exit
                loop    next_paragraph  ; continue till all paragraphs checked
no_load:        xor     ax,ax           ; set zero flag to indicate not now TSR
                ret
prior_load:     or      ax,ax           ; reset zero flag to show prior load
                ret
TSR_detect      endp

set_msg         db      rt,lf,'Switch set is $'
x_msg           db      'X',rt,lf,'$'
t_msg           db      'T',rt,lf,'$'
e_msg           db      'E',rt,lf,'$'
                IF      LP_Version_2A
f_msg           db      'F',rt,lf,'$'
                ENDIF                   ; LP_Version_2A

tell_switch     proc    near            ; informs user which switches are set
                mov     dx,of set_msg   ; address switches set message
                mov     ah,9            ; send it with DOS function 9
                int     21h
                IF      LP_Version_2A
                mov     dx,of f_msg     ; prepare 'F' switch set message
                cmp     es:palet_off,1  ; is palet_off flag set?
                jz      tell_set        ; yes, send 'F' switch set message
                ENDIF                   ; LP_Version_2A
                mov     dx,of x_msg     ; prepare 'X' switch set message
                cmp     es:exclude,1    ; is exclude flag set?
                jne     tell_set        ; no, send 'X' switch set message
                mov     dx,of t_msg     ; prepare 'T' set message
                cmp     es:txt_exclude,1; is 'T' switch set?
                je      tell_set        ; yes, say 'T' set
                mov     dx,of e_msg     ; else, it's just 'E' switch set
tell_set:       mov     ah,9            ; send it with DOS function 9
                int     21h
                ret
tell_switch     endp

syntax_msg      db      rt,lf

                IF      LP_Version_2A
db 'Usage:  palet1 [D] d1 d2 ... d16 [B[+|-]][U[+|-|<n>]][T][E][X]',rt,lf
db 'Where d1 through d16 are 16 two-digit decimal numbers.',rt,lf
                ELSE
db 'Usage:  palet1 [D] o1 o2 ... o16 [T][E][X]',rt,lf
db rt,lf
db 'Where o1 through o16 are 16 two-digit octal numbers.',rt,lf
                ENDIF                   ; LP_Version_2A
db 'A period leaves that register unchanged.',rt,lf
db 'Optional switches:',rt,lf
db '       [D] : Returns all registers to a default value.',rt,lf
db '       [T] : Traps EGA register changes in text mode only.',rt,lf
db '       [E] : Traps EGA register changes in all display modes.',rt,lf
db '       [X] : Turns off T & E switches (allows EGA register changes).',rt,lf

                IF      LP_Version_2A
DB '       [F] : Disable (turn oFf) palet.',rt,lf
DB '       [N] : Enable (turn oN) palet.',rt,lf
DB '       [B] : Blinking control, default intense background.',rt,lf
DB '             [B+] turns on blinking',rt,lf
DB '             [B-] turns on intense background',rt,lf
DB '             [B] is equivalent to [B+] if intense and to [B-] if '
DB                'blinking',rt,lf
DB '       [U] : Underlining control, default no underlining.',rt,lf
DB '             [U+] turns on underlining at bottom of character',rt,lf
DB '             [U<n>] turns on underlining at row n (decimal)',rt,lf
DB '             [U-] turns off underlining',rt,lf
DB '             [U] is equivalent to [U+] if underlining is off and to [U-] '
DB                  'if on',rt,lf
                ENDIF                   ; LP_Version_2A
db 'Switches T, E & X remain set unless changed on the command line.',rt,lf
db 'See docs for greater detail.',rt,lf
                IF      LP_Version_2A
DB '$'
                ELSE
db 'Palet is a public domain program.',rt,lf
db rt,lf,'$'
                ENDIF                   ; LP_Version_2A

set_switch      db      0       ; command line requests palette set? (=0 if no)
                                ; (not to be confused with switch_set variable)

switch_set      db      0       ; note any switch sets, 1=set
                                ; (not to be confused with set_switch variable)

                IF      LP_Version_2A
decimal_number  proc    near            ; Read a 1 or 2 digit decimal number
                                        ; from [SI] (the command line) to AL
                sub     al,'0'          ; To binary
                cmp     byte ptr [SI],'0'
                                       ; Check for second digit
                jb      decimal_number_exit
                cmp     byte ptr [SI],'9'
                ja      decimal_number_exit
                shl     al,1            ; 10 * AL => AH
                mov     ah,al
                shl     al,1
                shl     al,1
                add     ah,al
                lodsb                   ; second digit => AL
                                        ; Increment SI
                sub     al,'0'          ; To binary
                add     al,ah           ; Number => AL

decimal_number_exit:
                ret
decimal_number  endp
                ELSE                    ; LP_Version_2A
digit_cnt       db      0               ; number of parsed octal digits

store_num       proc    near            ; put octal attribute into set_values
                cmp     digit_cnt,0     ; have we any digits to store?
                je      no_none         ; no, not a one
                cmp     digit_cnt,1     ; is there only one digit?
                jne     two_digits      ; no, convert two digit octal to hex
                mov     al,bh           ; the one and only digit is in bh
                jmp     short try_store ; store attribute if able
two_digits:     mov     cl,3            ; a multiply by 8
                shl     bh,cl           ;   for the eights digit
                add     bh,bl           ; add in units digit
                mov     al,bh           ; store to set_values
try_store:      cmp     di,of old_int_10; if 16 attributes stored, then no more
                jne     store_it
                ret                     ;   (any given after 16 are ignored)
store_it:       inc     set_switch      ; indicate a palette reg is to be set
                stosb
                xor     bx,bx           ; reinitialize
                mov     digit_cnt,0
no_none:        ret
store_num       endp

do_digit        proc    near            ; make octal digit eights or units
                cmp     digit_cnt,0     ; have we a prior digit?
                jne     units           ; yes, have done eights so do units
                mov     bh,al           ; set eights digit into bh
                inc     digit_cnt       ; signify eights digit obtained
                ret
units:          mov     bl,al           ; units into bl
                inc     digit_cnt
                call    store_num       ; got two digits, so store octal attrib
                ret
do_digit        endp

                ENDIF                   ; LP_Version_2A

                IF      LP_Version_2A
resident_ES     DW      0               ; 0 also means palet is not yet
                                        ; resident

                org     0A00H           ; To give assured debug locations
                                        ; for default values, no matter what
                                        ; the future changes are:
                                        ; Default underline line - 0a00h
                                        ; Default blink value    - 0a01h
                                        ; Default palette values -
                                        ;               0a02h thru 0a11h
start_of_default_settings EQU (of default_underline_line)
default_underline_line  DB      no_underline_row
                                        ; Start by assuming no underlining
default_blink_value     DB      blink_off
                                        ; Start by assuming intense background
                ENDIF                   ; LP_Version_2A
deflt_vals      db      0               ; default values for EGA registers
                db      1               ; 0 through 15, change these values
                db      2               ; to customize the default values to
                db      3               ; your preference
                db      4               ; any value of 0 through 63 is valid
                db      5               ; this table as it comes has the
                db      20              ; default (on power-up) values for
                db      7               ; a Tandy 3000HL with their EGA
                db      56              ; board configured for the EGM-1
                db      57              ; monitor, yours may be different
                db      58              ; see docs for debug patching
                db      59              ; instructions
                db      60              ;
                db      61              ;
                db      62              ;
                db      63              ; end of default table


                IF      LP_Version_2A
; Error exit for "F" and "N" commands if palet is not installed
CHECK_INSTALLED MACRO
                LOCAL   is_installed
                cmp     resident_ES,0   ;; Is palet installed
                jne     is_installed    ;; Yes
                mov     dx,of not_installed
                                        ;; Tell user it must be installed
                jmp     error
is_installed:
                ENDM                    ; CHECK_INSTALLED
                ENDIF                   ; LP_Version_2A
start:          mov     ah,30h          ; find DOS version
                int     21h
                cmp     al,2            ; must be version 2.0 or higher
                jae     version_ok

                mov     dx,of wrong_DOS ; tell user this is wrong DOS version
                jmp     error

version_ok:     mov     ah,12h          ; EGA alternate select
                mov     bl,10h          ; get EGA information
                mov     bh,0ffh         ; shall return changed if EGA present
                int     10h             ; EGA ROM BIOS
                cmp     bh,1            ; 0 for color, 1 for monochrome
                jbe     EGA_here        ; test concludes EGA is present
                mov     dx,of no_EGA    ; tell that EGA is not present
                jmp     error

EGA_here:       mov     ah,15           ; get video mode
                int     10h             ;   with call to video interrupt
                cmp     al,3            ; text modes 0 - 3?
                jbe     text            ; yes, continue
                cmp     al,7            ; monochrome text mode?
                je      text            ; yes, continue
                mov     graphics,1      ; indicate a graphics mode is in effect
                IF      LP_Version_2A
text:
                call    TSR_detect      ; Detect presence of prior load as TSR
                jz      start_parse     ; Not here
                mov     resident_es,es  ; Save segment of prior load
                mov     ax,word ptr es:underline_line
                                        ; Resident values of underline_line
                                        ; and blink_value
                mov     word ptr underline_line,ax
                                        ; Non-resident values of underline_line
                                        ; and blink_value match resident
start_parse:
                mov     ax,cs           ; Reestablish es as non-resident
                                        ; segment
                mov     es,ax

                mov     si,80h          ; reference command line parameters
                ELSE

text:           mov     si,80h          ; reference command line parameters
                ENDIF                   ; LP_Version_2A
                mov     di,of set_values; address store for palette values
                IFE     LP_Version_2A
                xor     bx,bx           ; octal attribute accumulated in bx
                ENDIF                   ; IFE LP_Version_2A
                cld
                lodsb                   ; get command character count
                cmp     al,1            ; anything on command line?
                jae     next_value      ; yes, decode it

                IF      LP_Version_2A
                cmp     resident_ES,0   ; has the program been loaded as a TSR?
                ELSE
                call    TSR_detect      ; has the program been loaded as a TSR?
                ENDIF                   ; LP_Version_2A
                jz      just_syntax     ; no, just output syntax message
                IF      LP_Version_2A
                mov     es,resident_ES  ; Segment of resident version
                ENDIF                   ; LP_Version_2A
                call    tell_switch     ; report switch state

just_syntax:    mov     dx,of syntax_msg; address syntax message
                jmp     error

next_value:     lodsb                   ; get next entry from command line
                cmp     al,rt           ; end of command?
                jne     an_E?           ; is it the exclude command?
                IFE     LP_Version_2A
                call    store_num       ; store octal num in bh:bl as attribute
                ENDIF                   ; IFE LP_Version_2A
                jmp     parse_done

an_E?:          mov     cl,al           ; process in cl
                and     cl,0dfh         ; capitalize if letter
                cmp     cl,'E'          ; is it an "E"?
                IF      LP_Version_2A
                jne     an_F?           ; no, is it a "F"?
                ELSE                    ; LP_Version_2A
                jne     a_D?            ; no, is it a "D"?
                ENDIF                   ; LP_Version_2A
                mov     exclude,1       ; set exclude flag:  all modes trapped
                mov     txt_exclude,0   ; text exclude turned off
                inc     switch_set      ; note that switch turned on
                jmp     short next_value; continue till command parsed

                IF      LP_Version_2A
an_F?:
                cmp     cl,'F'          ; Is it an "F"?
                jne     an_N?           ; No.  Is it an "N"?
                CHECK_INSTALLED         ; Error exit if not installed
                mov     palet_off,1     ; Set disable flag
                jmp     short next_value
                                        ; continue until command parsed

an_N?:
                cmp     cl,'N'          ; Is it an "N"?
                jne     a_D?            ; No.  Is it a "D"?
                CHECK_INSTALLED         ; Error exit if not installed
                jmp     short next_value
                                        ; Since palet iniitializes palet_off,
                                        ; the disable flag, to 0, there is
                                        ; nothing to reset.  Continue until
                                        ; command parsed.
                ENDIF                   ; LP_Version_2A

a_D?:           cmp     cl,'D'          ; is it a D?
                jne     a_T?            ; go on if not
                inc     set_switch      ; indicate a palette reg change
                push    si              ; save critical registers
                push    di
                IF      LP_Version_2A
                mov     cx,length_of_EGA_settings
                mov     di,start_of_EGA_settings
                                        ; Values to actually use
                mov     si,start_of_default_settings
                ELSE
                mov     cx,16           ; number of palette registers
                mov     di,of set_values; point to reg values buffer area
                mov     si,of deflt_vals; load address of default table
                ENDIF                   ; LP_Version_2A
                rep     movsb           ; copy defaults to be set later
                pop     di              ; restore registers
                pop     si              ;
                jmp     short next_value; get next parameter (if any)

a_T?:           cmp     cl,'T'          ; is it a "T"?
                jne     an_X?           ; no, check for an "X"
                mov     exclude,1       ; set the exclude flag
                mov     txt_exclude,1   ; set the text flag, only txt trapped
                inc     switch_set      ; note that switch set
                jmp     next_value      ; continue till command parsed

an_X?:          cmp     cl,'X'          ; is it an "X"?
                IF      LP_Version_2A
                jne     a_B?            ; no, check for a "B"
                ELSE
                jne     a_period?       ; no, is it a period?
                ENDIF                   ; IF LP_Version_2A
                mov     exclude,0       ; reset exclude flag:  others can set
                mov     txt_exclude,0   ; reset text exclude flag
                inc     switch_set      ; note that switch set
                jmp     next_value      ; continue till command parsed
                IF      LP_Version_2A

a_B?:           cmp     cl, 'B'         ; Is it a "B"?
                jne     a_U?            ; No, check for a "U"
                inc     set_switch      ; indicate a palette reg is to be set
                cmp     byte ptr [si],'+'
                                        ; Set blinking on?
                je      request_blinking_on
                                        ; Yes
                cmp     byte ptr [si],'-'
                                        ; Set blinking off
                je      request_blinking_off
                                        ; Yes
                cmp     blink_value,blink_on
                                        ; Must want to switch
                jz      request_blinking_off_1
                jmp     short request_blinking_on_1
request_blinking_on:
                inc     si              ; Pass "+" on command line
request_blinking_on_1:
                mov     blink_value, blink_on
                jmp     next_value      ; Get next parameter (if any)
request_blinking_off:
                inc     si              ; Pass "-" on command line
request_blinking_off_1:
                mov     blink_value, blink_off
                jmp     next_value      ; Get next parameter (if any)

a_U?:           cmp     cl, 'U'         ; Is it a "U"?
                jne     a_period?       ; no, is it a period?
                inc     set_switch      ; indicate a palette reg is to be set
                cmp     byte ptr [si],'+'
                                        ; Set underlining on?
                je      request_underlining_on
                                        ; Yes
                cmp     byte ptr [si],'-'
                                        ; Set underlining off
                je      request_underlining_off
                                        ; Yes
                cmp     byte ptr [si],'0'
                                        ; Check for decimal digit to start
                                        ; underline row
                jb      underline_switch_request
                cmp     byte ptr [si],'9'
                ja      underline_switch_request
                lodsb                   ; First digit => AL
                                        ; Increment SI
                call    decimal_number  ; Set the underline row in AL
                                        ; Point SI at the following
                                        ; character
                mov     underline_line,al
                jmp     next_value      ; Get next parameter (if any)

underline_switch_request:
                cmp     es:underline_line,no_underline_row
                jz      request_underlining_on_1
                jmp     short request_underlining_off_1
request_underlining_on:
                inc     si              ; Pass "+" on command line
request_underlining_on_1:
                push    ds
                assume  ds:BIOS_seg
                mov     ax,BIOS_seg
                mov     ds,ax
                mov     ax,points       ; Number of lines in a character
                assume  ds:nothing
                pop     ds
                dec     ax              ; Line number of last line
                mov     underline_line, al
                                        ; Underline at last line
                jmp     next_value      ; Get next parameter (if any)
request_underlining_off:
                inc     si              ; Pass "-" on command line
request_underlining_off_1:
                mov     underline_line, no_underline_row
                jmp     next_value      ; Get next parameter (if any)

                ENDIF                   ; IF LP_Version_2A

a_period?:      cmp     al,'.'          ; a period?
                jne     a_space?        ; no, should be whitespace or octal num
                IFE     LP_Version_2A
                call    store_num       ; store octal num in bh:bl as attribute
                ENDIF                   ; IFE LP_Version_2A
                inc     di              ; a period says we skip one
                jmp     next_value      ; continue till command parsed

a_space?:       cmp     al,' '          ; a space?
                jne     a_tab?          ; no, is it a tab?
                IFE     LP_Version_2A
                call    store_num       ; store octal num in bh:bl as attribute
                ENDIF                   ; IFE LP_Version_2A
                jmp     next_value      ; continue till command parsed

a_tab?:         cmp     al,9            ; a tab?
                jne     a_digit?        ; no, an octal digit?
                IFE     LP_Version_2A
                call    store_num       ; store octal num in bh:bl as attribute
                ENDIF                   ; IFE LP_Version_2A
                jmp     next_value      ; continue till command parsed

a_digit?:       cmp     al,'0'          ; is it ASCII zero or greater?
                IF      LP_Version_2A
                jae     decimal_digit?
                ELSE
                jae     octal_digit?    ; yes, test if octal digit
                ENDIF                   ; IF LP_Version_2A
                mov     dx,of syntax_msg; address syntax message
                jmp     error           ; no, must be a syntax error
                IF      LP_Version_2A
decimal_digit?: cmp     al,'9'          ; is it 9 or less?
                jbe     is_decimal      ; yes, convert to binary
                ELSE
octal_digit?:   cmp     al,'7'          ; is it 7 or less?
                jbe     is_octal        ; yes, convert to binary
                ENDIF                   ; IF LP_Version_2A
                mov     dx,of syntax_msg; address syntax message
                jmp     error           ; no, must be a syntax error
                IF      LP_Version_2A
is_decimal:     call    decimal_number  ; Set the palette value in AL
                                        ; Point SI at the following
                                        ; character
                cmp     di,of old_int_10; if 16 attributes stored, then no more
                jne     store_it
                jmp     next_value
store_it:       inc     set_switch      ; indicate a palette reg is to be set
                stosb

                ELSE
is_octal:       sub     al,'0'          ; make it binary
                call    do_digit        ; place in bh or bl or store number
                ENDIF                   ; IF LP_Version_2A
                jmp     next_value      ; continue till command parsed

                IF LP_Version_2A
parse_done:     cmp     resident_ES,0   ; detect presence of prior load as TSR
                ELSE
parse_done:     call    TSR_detect      ; detect presence of prior load as TSR
                ENDIF                   ; LP_Version_2A
                jz      not_here        ; ZF set on return => no prior load

                IF      LP_Version_2A
                mov     es,resident_ES  ; Segment of resident version
                mov     al,palet_off    ; Always reset disable flag
                mov     es:palet_off,al
                ENDIF                   ; LP_Version_2A
                cmp     set_switch,0    ; has palette registers to set changed?
                je      no_set          ; no, don't copy to resident part
                IF      LP_Version_2A
                mov     si,start_of_EGA_settings
                                        ; transfer new values to our resident
                mov     di,si           ;   TSR routine
                mov     cx,length_of_EGA_settings
                ELSE
                mov     si,of set_values; transfer new values to our resident
                mov     di,si           ;   TSR routine
                mov     cx,16
                ENDIF                   ;LP_Version_2A
                rep     movsb
no_set:         call    set_palette     ; set palette registers as requested
                cmp     switch_set,0    ; check for switch setting change
                je      terminate       ; don't change switches--none entered
                mov     al,exclude      ; get exclude flag
                mov     es:exclude,al   ;   and place in TSR
                mov     al,txt_exclude  ; get text only exclude flag
                mov     es:txt_exclude,al       ; and place it in TSR
terminate:      call    tell_switch     ; tell user which switches are set
                mov     ax,4c00h        ; terminate with error level 0
                int     21h

                IF      LP_Version_2A
not_here:
                ELSE
not_here:       mov     ax,cs           ; reset es to our data
                mov     es,ax
                ENDIF                   ; LP_Version_2A
                call    set_palette     ; set palette registers as requested
                mov     ax,3510h        ; get current int 10h address
                int     21h
                mov     old_int_10,bx   ; store offset of current int 10h
                mov     old_int_10+2,es ; store segment of current int 10h
                mov     dx,of new_int_10; address our spliced-in routine
                mov     ax,2510h        ; tell DOS to use our int 10h routine
                int     21h
                mov     dx,of error     ; address first byte we can throw away
                add     dx,0fh          ; compute number of paragraphs to save
                shr     dx,1
                shr     dx,1
                shr     dx,1
                shr     dx,1
                mov     ax,3100h        ; make a TSR with error code 0
                int     21h
code            ends
                end     begin
