
TITLE   DISPLAY
;  by Douglas Clark and William C. Parke (c) Copyright 1987
;
; Quick display of a page of a file on screen with special attributes
;
PUBLIC  START,BEGIN

CODE    SEGMENT
        ASSUME  CS:CODE,DS:CODE
        ORG     100H
;
CR      EQU     0DH
LF      EQU     0AH
;
START:  JMP     BEGIN
;
PAG_MAR DB      '^'             ; page marker
ATR_SYM DB      '\'             ; attribute symbol with start/stop codes

        DB      14 DUP(0)
        DB      1AH
FILNAM  DB      80 DUP(0)
PAGIDF  DB      0
        DB      0
PAGIDS  DW      0
PAGID   DB      32 DUP(0)
FHAN    DW      0
PAG_START       DW      0
PAG_SIZ         DW      0
VID_SEG DW      0B000H                  ; mono addr for direct video
PGPTR   DW      0
PGADR   DB      256 DUP(0)

HELP:   AND     AL,AL                   ; any error messages?
        JZ      HELP1
        XOR     AH,AH
        PUSH    AX
        DEC     AL
        SHL     AX,1
        MOV     BX,AX
        MOV     DX,WORD PTR ERR_TBL[BX]
        MOV     AH,9H
        INT     21H
        POP     AX
        MOV     AH,4CH
        INT     21H                     ; exit

HELP1:  MOV     DX,OFFSET DHELP
        MOV     AH,9
        INT     21H
        MOV     AX,4C00H
        INT     21H                     ; EXIT clean

BEGIN:  CALL    COMMAND_LN              ; get screen file name and page id
        JC      HELP
        CALL    OPENF                   ; open screen file
        JC      HELP
        CALL    VID_MEM                 ; get video memory address
        CALL    READF
        JC      HELP
        MOV     SI,OFFSET PAGID
        MOV     DI,OFFSET FILBUF
        MOV     PAG_START,DI            ; default begin address
        MOV     CX,WORD PTR FILBUFL
        MOV     PAG_SIZ,CX              ; default size
        TEST    BYTE PTR PAGIDF,1       ; test if page id is present
        JZ      VID5                    ; show whole file
        CALL    STRSEARCH               ; look for page id
        JC      HELP
        MOV     PAG_START,DX            ; save addr. of hit from search
        MOV     AX,DI
        SUB     AX,DX                   ; new size
        JC      HELP1
        MOV     PAG_SIZ,AX              ; save new size
VID5:   MOV     SI,PAG_START            ; SI->filbuf (or page therein)
        MOV     AX,SI
        MOV     DI,OFFSET PGADR
        STOSW
        XOR     AX,AX
        MOV     CX,126
        REP     STOSW                   ; zero beyond first addr
        MOV     WORD PTR PGPTR,AX       ; zero the initial page ptr
        MOV     AX,VID_SEG
        MOV     ES,AX
VIDR:   MOV     BX,PGPTR                ; current page index into pgadr
        MOV     SI,WORD PTR PGADR[BX]   ; get address of page
        AND     SI,SI
        JNZ     VIDRN
        SUB     BX,2
        MOV     PGPTR,BX
        MOV     SI,WORD PTR PGADR[BX]
VIDRN:  CALL    CLRSCN
        MOV     BX,DI                   ; save di
        MOV     DX,23                   ; maximum lines
VID7:   LODSB
VID7C:  CMP     AL,LF                   ; skip Line Feeds
        JZ      VID7
        CMP     AL,CR                   ; chk Carr.Ret.
        JNZ     VID8                    ;  no
        MOV     DI,BX                   ; yes
        ADD     DI,(80*2)               ; bump to next line on screen
        MOV     BX,DI
        DEC     DX                      ; 23-row count
        JNZ     VID7
        JMP     SHORT VID9
VID8:   CMP     AL,1AH                  ; chk e-o-f
        JZ      VID9F
        CMP     AL,'\'                  ; control code?
        JNZ     VIDS
        CMP     BYTE PTR [SI],'\'       ; cancel?
        JZ      VIDSC
        CALL    CODES
        JMP     SHORT VID7C
VIDSC:  INC     SI
VIDS:   OR      AL,0
OCMASK  EQU     $-1
        STOSB
        MOV     AL,ATTRIB               ; get attribute
        STOSB                           ; store attrib.
        JMP     SHORT VID7              ; loop
VID9F:  XOR     SI,SI                   ; no more
        MOV     BX,PGPTR
        AND     BX,BX
        JZ      VID10
        TEST    BYTE PTR PAGIDF,1
        JNZ     VID10
VID9:   MOV     BX,PGPTR
        INC     BX                      ; next page
        INC     BX
        MOV     PGPTR,BX
        MOV     WORD PTR PGADR[BX],SI   ; save ptr to next page
        JMP     SHORT VID16
VID9U:  MOV     BX,PGPTR
        SUB     BX,4
        JNC     VID9V
        XOR     BX,BX
VID9V:  MOV     PGPTR,BX
        JMP     VIDR
VID10:  MOV     AX,CS
        MOV     ES,AX                   ; restore ES
        MOV     AX,DI                   ; current screen byte count
        XOR     DX,DX
        MOV     CX,80*2                 ; bytes for rows
        DIV     CX                      ; ax= rows, dx= remainder
        SHR     DX,1                    ; column in dl
        MOV     DH,AL                   ; row in dh
        MOV     AH,02H                  ; locate
        MOV     BH,00H                  ; curr screen
        INT     10H
        MOV     AX,4C00H
        INT     21H                     ; terminate program

VID16:  MOV     AH,0
        INT     16H
        CMP     AX,5100H                ; PgDn
        JZ      VID16R
        CMP     AX,4900H                ; PgUp
        JZ      VID9U
        CMP     AX,011BH                ; esc
        JZ      VID10
        CMP     AX,2E03H                ; ^C
        JZ      VID10
        CMP     AX,4700H                ; home
        JZ      VIDHOM
        CMP     AX,4F00H                ; end
        JZ      VIDEND
        JMP     SHORT VID16
VID16R: JMP     VIDR
VIDHOM: MOV     WORD PTR PGPTR,0
        JMP     VIDR
VIDEND: XOR     AX,AX
        MOV     BX,AX
        SUB     BX,2
        MOV     CX,129
VIDENS: ADD     BX,2
        CMP     WORD PTR PGADR[BX],AX   ; look for first zero address
        LOOPNZ  VIDENS
        JCXZ    VID10
        SUB     BX,2                    ; addr just before is 'end' one
        MOV     PGPTR,BX                ; use counter for ptr
        JMP     VIDR
;
;---------------------------------------------------------------
STRSEARCH:
; Input: SI= pagid string       Output: DX= found page position
;        DI= file buffer                DI= end of page pointer
;        CX= file buffer size
;---------------------------------------------------------------
        CLD                             ;forward direction
STRSR0: CALL    SYMSEARCH               ; search for pag symbol
        JNC     STRSR1
        MOV     AL,3                    ; error: no page symbol
        RET
STRSR1: PUSH    CX                      ; save buffer length
        MOV     CX,PAGIDS
        INC     CX
        PUSH    SI
        REPZ    CMPSB                   ; search for page id
        POP     SI
        AND     CX,CX                   ; did we find it?
        POP     CX                      ; get back file length remaining
        JNZ     STRSR0                  ; not yet
        MOV     DX,DI                   ; save address of first page
        CALL    SYMSEARCH
        DEC     DI
        MOV     WORD PTR [DI-1],1A1AH
        XOR     AX,AX
        RET

SYMSEARCH:
; find page break symbol in buffer
        MOV     AL,PAG_MAR
SYMSR0: REPNZ   SCASB
        AND     CX,CX
        JNZ     SYMSR2
SYMSR1:
        STC
        RET
SYMSR2:
        DEC     CX
        JZ      SYMSR1
        SCASB
        JNZ     SYMSR0
        RET

;---------------------------------------------------------------
COMMAND_LN:
; Input: none           Output: Command line file name in FILNAM
;                               Page code in PAGID
;---------------------------------------------------------------
        MOV     SI,80H                  ; get command string buffer
        LODSB                           ; get command string size
        AND     AL,AL                   ; anything there?
        JNZ     CMDLN1                  ; ok, there is a string
        XOR     AL,AL                   ; no error message
        STC
        RET
CMDLN1: XOR     CH,CH                   ; zero ch
        MOV     CL,AL                   ; put size in cx
        INC     CX
        MOV     DI,OFFSET FILNAM        ; buffer for asciz filename
CMDLN2: LODSB                           ; get byte from command string
        CMP     AL,20H                  ; see if its a space
        LOOPZ   CMDLN2                  ; skip if so
        AND     CX,CX                   ; are we at end of string?
        JNZ     CMDLNL                  ; not yet
CMDLNS: XOR     AL,AL                   ; no error message
        STC
        RET
CMDLNL: STOSB                           ; save file name byte
        LODSB                           ; get next byte
        CMP     AL,'/'                  ; switch?
        JNZ     CMDLN4                  ; no
        XOR     AL,AL
        STOSB
        DEC     CX
        JMP     SHORT CMDLNA            ; look for page number
CMDLNT: XOR     AL,AL
        STOSB
        RET
CMDLN4: CMP     AL,20H                  ; space?
        JZ      CMDLN5
        CMP     AL,CR
        JZ      CMDLNT
        CMP     AL,';'
        LOOPNZ  CMDLNL
        JMP     SHORT CMDLNT
CMDLN5: XOR     AL,AL
        STOSB
        JCXZ    CMDLNT
CMDLN8: LODSB
        CMP     AL,20H
        JZ      CMDLN9
        CMP     AL,';'
        JZ      CMDLNT
        CMP     AL,CR
        JZ      CMDLNT
        CMP     AL,'/'
        JZ      CMDLNA
CMDLN9: LOOP    CMDLN8
        JMP     SHORT CMDLNT
CMDLNA: CMP     CX,3
        JC      CMDLNM
CMDLNC: LODSW                           ; get '=p'
        SUB     CX,2
        AND     AL,5FH
        CMP     AX,3D50H
        JZ      CMDLND
CMDLNM: MOV     AL,1                    ; invalid switch
        STC
        RET
CMDLND: MOV     DI,OFFSET PAGID
        XOR     BX,BX                   ; count of pagid
CMDLNF: LODSB
        CMP     AL,' '
        JZ      CMDLNE
        CMP     AL,CR
        JZ      CMDLNE
        CMP     AL,';'
        JZ      CMDLNE
        INC     BX
        STOSB
        LOOP    CMDLNF                  ; save page id
CMDLNE: MOV     AL,PAG_MAR
        STOSB                           ; add ^^ to end
        INC     BX
        STOSB
        INC     BX
        MOV     PAGIDS,BX               ; save size of id
        MOV     BYTE PTR PAGIDF,1       ; set flag
        XOR     AX,AX
        STOSB
        RET

;---------------------------------------------------------------
OPENF:
; Input: none           Output:  File handle in FHAN
;---------------------------------------------------------------
        MOV     DX,OFFSET FILNAM        ; DX -> input file name
        MOV     AX,3D00H                ; open for input
        INT     21H
        JNC     OPN1
        MOV     AL,2                    ; error opening file
        RET
OPN1:   MOV     FHAN,AX                 ; save handle
        RET

;---------------------------------------------------------------
CLRSCN:
; Input: none           Output:  none
;---------------------------------------------------------------
        MOV     CX,0000H                ; row,col
        MOV     DX,184FH                ; row,col
        MOV     AX,0600H                ; CLS clear screen
        MOV     BH,07H                  ; normal
        INT     10H
        MOV     DX,1800H                ; column in dl, row in dh
        MOV     AH,02H                  ; locate
        MOV     BH,00H                  ; curr screen
        INT     10H
        XOR     DI,DI                   ; start at top of screen
        RET

;---------------------------------------------------------------
VID_MEM:
; Input: none           Output:  Active video memory address in VID_SEG
;---------------------------------------------------------------
        MOV     AX,40H                  ; bios data segment
        PUSH    DS
        MOV     DS,AX                   ; DS -> bios data seg.
        CMP     WORD PTR DS:63H,03B4H   ; If Mono...    (everex-cga=03D4 )
        POP     DS
        JZ      VIDM1
        ADD     WORD PTR VID_SEG,0800H  ; adj. for CGA
VIDM1:  RET

;---------------------------------------------------------------
READF:
; Input: none           Output:  FILBUF filled with file of length FILBUFL
;---------------------------------------------------------------
        MOV     DX,OFFSET FILBUF        ; DX -> file buffer
        MOV     AX,3F00H                ;
        MOV     BX,FHAN
        MOV     CX,0C000H               ; Read 48k
        INT     21H                     ;
        JNC     READ11
        MOV     AL,4                    ; bad read
        RET
READ11:
        MOV     WORD PTR FILBUFL,AX     ; save length of file
        ADD     AX,DX                   ; append
        DEC     AX                      ;   ^Z (eof)
        MOV     BX,AX                   ;     to the end
        MOV     WORD PTR [BX],1A1AH     ;       of the data.
        MOV     BX,FHAN
        MOV     AX,3E00H                ; close handle
        INT     21H
        RET

;---------------------------------------------------------------
CODES:
; Input: SI=file buffer at /+1          Output: set attribute of AL
;---------------------------------------------------------------
        MOV     AL,[SI]                 ; get /+1 char
        PUSH    CX                      ; save cx
        PUSH    DI                      ; save di
        PUSH    ES
        PUSH    DS
        POP     ES
        MOV     DI,OFFSET COD_TBL       ; point to / codes
        MOV     CX,17
        REPNZ   SCASB
        POP     ES
        POP     DI
        AND     CX,CX
        MOV     AH,CL                   ; save 16-count in ah
        POP     CX
        JNZ     CODE1                   ; jmp if we found one
        RET                             ; return with orig. char
CODE1:  INC     SI                      ; point to /+2
        PUSH    BX                      ; save bx
        MOV     BX,16
        SUB     BL,AH
        CMP     BX,8
        JNC     CODOFF                  ; must be a lower case off switch
        AND     BX,BX
        JZ      CODET                   ; if its zero, must be A switch
        CMP     BX,6
        JNC     CODEC                   ; if its above 5, must be color
        MOV     AL,COD_MSK[BX]          ; get mask
        CMP     BL,5
        JNC     CODAH                   ; a hide request
        CMP     BL,3
        JC      CODOA                   ; A, I, or B request
        SUB     BL,3
        JZ      CODAA                   ; process U request
        OR      BYTE PTR ATTRIB,AL
        MOV     AL,11111000B            ; and for reverse
CODAA:  AND     BYTE PTR ATTRIB,AL
        POP     BX
        LODSB                           ; get /+2 char
        RET
CODOA:  OR      BYTE PTR ATTRIB,AL      ; turn on attribute requested
        POP     BX
        LODSB
        RET

CODAH:  MOV     AL,BYTE PTR ATTRIB
        MOV     ATTRH,AL                ; save a copy of the attr byte
        MOV     BYTE PTR ATTRIB,0
        POP     BX
        LODSB
        RET

CODOH:  MOV     AL,BYTE PTR ATTRH
        AND     AL,AL                   ; test if non-zero
        JNZ     CODOH1
        MOV     AL,07H                  ; use default attribute
CODOH1: MOV     BYTE PTR ATTRIB,AL      ; restore copy of attr byte
        POP     BX
        LODSB
        RET

CODET:  MOV     BYTE PTR OCMASK,10000000B
        POP     BX
        LODSB
        RET
CODEU:  MOV     BYTE PTR OCMASK,00000000B
        POP     BX
        LODSB
        RET

CODOFF: SUB     BX,8                    ; get displacement for off switch
        JZ      CODEU                   ; request to turn off alter. char.
        CMP     BX,6
        JNC     CODEC                   ; color request
        MOV     AL,COD_MSK[BX]          ; get mask
        NOT     AL                      ; reverse bits
        CMP     BL,5
        JNC     CODOH                   ; or attribute to unhide
        CMP     BL,3
        JC      CODAA                   ; A, I, or B request
        SUB     BL,3
        JZ      CODOA                   ; process U request
        AND     BYTE PTR ATTRIB,AL
        MOV     AL,00000111B            ; or for reverse off
        JMP     SHORT CODOA

CODEC:  MOV     BYTE PTR SHIFT,0        ; assume foreground
        SUB     BL,6                    ; see if C or S
        JZ      CODESS                  ; do foreground Char. color
        MOV     BYTE PTR SHIFT,4        ; set up background S shift
CODESS: MOV     AL,[SI]                 ; get /+2
        OR      AL,' '                  ; make lower case
        PUSH    DI
        PUSH    ES
        PUSH    DS
        POP     ES
        PUSH    CX
        MOV     DI,OFFSET COLOR_T
        MOV     CX,8
        REPNZ   SCASB
        AND     CX,CX
        MOV     AH,CL
        POP     CX
        POP     ES
        POP     DI
        JZ      CODESE
        INC     SI                      ; point to /+3
        MOV     BX,7
        SUB     BL,AH
        MOV     AL,COLOR_M[BX]          ; get color bit mix
        MOV     AH,11111000B            ; mask for foreground
        TEST    BYTE PTR SHIFT,4
        JZ      CODESU                  ; no shift needed for foreground
        PUSH    CX
        XOR     CX,CX
        MOV     CL,SHIFT
        SHL     AL,CL
        POP     CX
        MOV     AH,10001111B            ; mask for background
CODESU: AND     BYTE PTR ATTRIB,AH
        OR      BYTE PTR ATTRIB,AL
        POP     BX
        LODSB                           ; get next real character
        RET
CODESE: DEC     SI
        POP     BX
        MOV     AL,[SI]                 ; restore /+1 char.
        RET
ATTRIB  DB      7                       ; normal attribute
ATTRH   DB      0

COD_TBL DB      'AIBURHCS'
        DB      'aiburhcs',0
COLOR_T DB      'bgtrvpw',0,0
COD_MSK DB      10000000B               ; alternate char. set bit or
        DB      00001000B               ; intensity bit or
        DB      10000000B               ; blinking bit or
        DB      11111001B               ; underline bit and
        DB      01110000B               ; reverse video bits and
        DB      00000000B               ; hide byte and
        DB      00000111B               ; foreground bits
        DB      01110000B               ; background bits

COLOR_M DB      00000001B               ; blue
        DB      00000010B               ; green
        DB      00000011B               ; turquoise
        DB      00000100B               ; red
        DB      00000101B               ; violet
        DB      00000110B               ; pink
        DB      00000111B               ; white
SHIFT   DB      0
        DW      0

ERR_TBL DW      ERRSW
        DW      NOFILE
        DW      NOPAGE
        DW      ERREAD

ERRSW   DB      CR,LF,'Invalid switch on command line.',CR,LF,'$'
NOFILE  DB      CR,LF,'Cannot open file.',CR,LF,'$'
NOPAGE  DB      CR,LF,'Page Not Found.',CR,LF,'$'
ERREAD  DB      CR,LF,'Error reading file.',CR,LF,'$'

MARKEND EQU     $
DHELP   DB      CR,LF
 DB '            DISPLAY  Version 1.1',CR,LF
 DB ' ',CR,LF
 DB '          A fast file to screen displayer',CR,LF
 DB '          by Douglas Clark and W.C. Parke',CR,LF
 DB '                  (c) 1987',CR,LF
 DB ' ',CR,LF
 DB 'Syntax: DISPLAY filename [/P=pageid]',CR,LF
 DB '      where  filename is a valid file to display,',CR,LF
 DB '             pageid   is a page identification string',CR,LF
 DB '                embedded in the file, with a pair of',CR,LF
 DB '                carots (^^) on prefix and suffix.',CR,LF
 DB '      Embed ''\x'' controls in text for enhanced text:',CR,LF
 DB '      Monochrome:  Start Stop    Color: Character Screen',CR,LF
 DB '       hide           \H   \h      blue       \cb    \sb',CR,LF
 DB '       underline      \U   \u      green      \cg    \sg',CR,LF
 DB '       reverse video  \R   \r      turquoise  \ct    \st',CR,LF
 DB '       blinking       \B   \b      red        \cr    \sr',CR,LF
 DB '       intense        \I   \i      violet     \cv    \sv',CR,LF
 DB '       alternate ibm-              pink       \cp    \sp',CR,LF
 DB '        character set \A   \a      white      \cw    \sw',CR,LF,'$'

FILBUFL EQU     MARKEND                ; length of file
FILBUF  EQU     FILBUFL+2              ; 1st 48k of file
;
CODE    ENDS
        END     START
