         PAGE    60,132
         TITLE   LIST --- Replace TYPE and MORE commands
;==============================================================================
; Name:     LIST, display contents of an ASCII file.
; Syntax:
;           LIST  <[d:][path]filename[.ext]>
; Input:
;           An ASCII file of any size may be listed, however only the
;           first 80 bytes of each record is displayed.
;
;           After the 'More?' prompt, enter a CR to continue, or
;           any other character to terminate.
; Output:
;           Logical records (ending in LF and/or CR) are placed into
;           the screen buffer.
; Notes:
;           Written for the IBM PC by Vernon Buerg, November 1983,
;           and is supplied for public domain use.
;
; Revised:  Robert S. Russell, Bootstrap Creations, Walnut Creek, Calif.
;           December 3, 1983 to allow enough space in buffer for filename
;           so that a path may also be specified.  Also removed a bug which
;           caused the system to lock if a carriage return is entered in
;           response to the filename prompt.
;
;==============================================================================
;
_STACK   SEGMENT PARA STACK 'STACK'
         DB      128 DUP (0)
_STACK   ENDS
;
DATA     SEGMENT PUBLIC PARA 'DATA'
ASKFILE  DB      13,10,'Enter [d:][path]filename[.ext]:$'             ;RSR
CLEAR    DB      27,'[2J$'
PROMPT   DB      27,'[25;1H','More?$'
EOFMSG   DB      27,'[25;1HEnd-of-file$'
CODE2    DB      13,10,'File not found$'                              ;RSR
CODE4    DB      13,10,'Too many open files$'                         ;RSR
KEYIN    DB      0            ;keyboard buffer size
KEYOUT   DB      0            ;keyboard length read
FILENAME DB      45 DUP (0)   ;drive:\path\filename.ext               ;RSR
HANDLE   DW      0            ;file handle from open
COL      DW      1            ;current display column
ROW      DW      2            ;current display row
INDEX    DW      0            ;offset in buffer to record
;
OPENMSG  DB      13,10,'Open code: '                                  ;RSR
OPENCODE DW      '00'
         DB      '  $'
RECLEN   DW      0            ;length of current record
RECADDR  DW      0            ;addr of i/o buffer
;
SWITCH1  DB      0
EOR      EQU     1            ;end-of-record
SWITCH2  DB      0
NODATA   EQU     2            ;null record
NUMLF    DB      0            ;line feed count
NUMCR    DB      0            ;C/R count
WORK     DB      256 DUP (?)  ;current logical record
DATA     ENDS
;
ZBUFFER  SEGMENT PARA PUBLIC 'BUFFER'
RECORDS  DB      65535 DUP (?)
ZBUFFER  ENDS
;
BIOS     SEGMENT AT 40H       ;set up labels to determine
         ORG     10H          ;color or monochrome card
EQFLAG   LABEL   WORD
         ORG     4AH          ;40 or 80 column display
NCLMS    LABEL   WORD
         ORG     63H
A6845    LABEL   WORD         ;points to video card ports
BIOS     ENDS
;
         PAGE
CSEG     SEGMENT PARA PUBLIC 'CODE'
         ASSUME  CS:CSEG,DS:DATA,SS:_STACK,ES:ZBUFFER
LIST     PROC    FAR
         PUSH    DS           ;save for linkage
         XOR     AX,AX        ;clear for return
         PUSH    AX           ;put in stack
;
         MOV     AX,DATA      ;Addr of work areas
         MOV     DS,AX        ;Set data segment reg
;
         PUSH    DS           ;Save DS
         XOR     CX,CX        ;clear hi-byte
         MOV     CL,BYTE PTR ES:[80H]  ;Length of command parm
         DEC     CL           ;For ending CR
         CMP     CL,0         ;Any parm string?
         JLE     GETNAME      ;No, ask for it
;
         MOV     SI,82H       ;Offset to command parm string
         MOV     DI,OFFSET FILENAME
         MOV     AX,DS        ;Swap DS/ES
         MOV     BX,ES
         MOV     DS,BX        ;Copy command string
         MOV     ES,AX
         REP     MOVSB
         POP     DS           ;Restore DS
         JMP     OPEN
         PAGE
;  No filename supplied with command
;
GETNAME: POP     DS
RETRYNAME:                                                              ;RSR
         MOV     DX,OFFSET ASKFILE    ;Prompt for file name
         MOV     AH,9
         INT     21H
         MOV     AH,0AH       ;Buffered kybd input DOS req
         MOV     DX,OFFSET KEYIN
         MOV     KEYIN,44     ;Size of buffer                           ;RSR
         INT     21H
;
         XOR     BX,BX
         MOV     BL,KEYOUT    ;Number of chars read
         CMP     BL,0
         JE      RETRYNAME                                              ;RSR
         MOV     FILENAME[BX],0 ;overlay CR
         PAGE
;
OPEN:    MOV     DX,OFFSET FILENAME      ;file to open
         MOV     AX,0         ;for read only                            ;RSR
         MOV     AH,3DH       ;open a file
         INT     21H
         MOV     HANDLE,AX    ;save file handle
;
         JNC     INIT         ;if OPEN okay
         MOV     DX,OFFSET CODE2
         CMP     AL,2         ;is it 'file not found'?
         JE      ERROR
         MOV     DX,OFFSET CODE4                                        ;RSR
         CMP     AL,4         ;is it 'too many open files'?             ;RSR
         JE      ERROR
;
         AAM
         XCHG    AL,AH
         OR      OPENCODE,AX
         MOV     DX,OFFSET OPENMSG
ERROR:   MOV     AH,9
         INT     21H          ;say OPEN FAILED
         RET
         PAGE
;
; Initialize buffer to EOF stoppers
;
INIT:    MOV     BX,ZBUFFER   ;addr of I/O area
         MOV     RECADDR,BX   ;save it
         MOV     DX,OFFSET CLEAR
         MOV     AH,9
         INT     21H          ;to clear screen
;
READAGN: MOV     CX,65535     ;number of bytes to clear
         MOV     ES,RECADDR
;
STOPPER: MOV     DI,CX
         MOV     ES:BYTE PTR[DI],1AH    ;fill with stoppers
         LOOP    STOPPER
         PAGE
;
; Read a block  (64K)
;
         MOV     BX,HANDLE       ;get file handle from open
         MOV     DX,RECADDR      ;offset to record buffer
         PUSH    DS
         MOV     DS,DX           ;set data segment ptr
         SUB     DX,DX           ; with zero offset
         MOV     CX,65534        ;number of bytes to read
         MOV     AH,3FH          ;read from a file
         INT     21H
;
         POP     DS
;        MOV     BX,AX           ;Save length read
         MOV     SWITCH1,0       ;reset EOR flag
         MOV     INDEX,0         ;offset into buffer
         CMP     AX,0            ;Any bytes read?
         JNE     READ            ;Yes, list the buffer
         JMP     CLOSE           ;No, all done
;
; Set next row and column for next display line
;
READ:    MOV     CX,RECLEN       ;set column and row
         INC     CX              ; for next record
         MOV     AX,ROW
         DEC     AX
         CMP     NUMLF,0         ;record ended in LF?
         JE      SET             ;no, have col/row
         INC     AX              ;yes, row stays where it is
         MOV     CX,1            ; and in column 1
;
SET:     MOV     ROW,AX          ;set row
         MOV     COL,CX          ;set column
;
; Extract next logical record from display
;
GETNEXT: CALL    SCAN_BUF        ;Scan for logical record
         MOV     CX,RECLEN       ;Record size
         SUB     CL,NUMLF        ;for LF
         SUB     CL,NUMCR        ;for CR
         MOV     RECLEN,CX
         CMP     CX,0            ;blank line?
         JE      GETROW          ;yes, increment row only
;
         LEA     SI,WORK         ;addr of record
         MOV     AX,ROW          ;destination row
         CALL    PRINT           ;put into screen buffer
;
GETROW:  MOV     AX,ROW          ;get row again
         INC     AX              ;bump to next row
         MOV     ROW,AX          ;save row number
         CMP     AL,25           ;exceeded screen?
         JNE     TESTEOR         ;no, read next record
;
         MOV     DX,OFFSET PROMPT
         MOV     AH,9
         INT     21h             ;say 'More?'
;
; Wait for keyboard input
;
         MOV     AH,12           ;clear console
         MOV     AL,7            ;and get a char
         INT     21H             ;pause for enter
         CMP     AL,0DH          ;want to quit?
         JNE     CLOSE           ;yes, clean up
;
         MOV     ROW,2           ;no, reset to first row
         MOV     AX,ROW
;
         MOV     DX,OFFSET CLEAR
         MOV     AH,9
         INT     21H             ;to clear screen
;
         LEA     SI,WORK         ;addr of record
         MOV     AX,1            ;put last line on top
         MOV     CX,RECLEN
         CALL    PRINT           ;put into screen buffer
;
TESTEOR: TEST    SWITCH1,EOR     ;end-of-records?
         JZ      READ
         JMP     READAGN         ;yes, read next block
;
CLOSE:   MOV     BX,HANDLE       ;file handle from open
         MOV     AH,3EH          ;close a file handle
         INT     21H
;
         MOV     DX,OFFSET EOFMSG
         MOV     AH,9
         INT     21H             ;to say done
;
         RET
         PAGE
SCAN_BUF PROC    NEAR
;
; Function: Scan the buffer for special characters and copy wanted
;        data to field WORK. A logical record ends in an LF and/or CR.
;
; Input: ZBUFFER (RECORDS) contains a block of data from the file
;        INDEX is the current offset to a logical record
; Output:
;        WORK contains a logical record
;        NUMLF contains number of line feeds (ignored)
;        NUMCR contains number of carriage returns (ignored)
;        RECLEN contains length of logical record
; Notes: Tabs are replaced by blanks;
;        lines beginning with hex-F are ignored
;
         PUSH    ES
         PUSH    CX
         PUSH    SI
         PUSH    DI
         TEST    SWITCH1,EOR
         JZ      SCAN1
         JMP     SCAN_END
;
SCAN1:   XOR     CX,CX
         XOR     DI,DI
         AND     SWITCH2,0FFH-NODATA
         MOV     NUMLF,0         ;reset LF indicator
         MOV     NUMCR,0         ;zero CR counter
         MOV     AX,ZBUFFER
         MOV     ES,AX           ;set addr of I/O buffer segment
;
SCAN2:   MOV     SI,INDEX
         MOV     AL,RECORDS[SI]  ;Get a byte
         CMP     AL,1AH          ;End of buffer?
         JNE     SCAN3
         MOV     RECLEN,CX
         OR      SWITCH1,EOR     ;Indicate end-of-records
         JMP     SCAN_END
;
SCAN3:   CMP     AL,9H           ;Is it TAB?
         JNE     SCAN4
         MOV     AL,' '          ;Yes, replace with blank
;
SCAN4:   MOV     WORK[DI],AL     ;Store character
         INC     DI              ;Increment pointer
         INC     CX              ;Increment counter
         INC     INDEX           ;Increment counter
;
         CMP     AL,0DH          ;Is it a CR?
         JNE     SCAN5
         INC     NUMCR           ;Yes, increment counter
SCAN5:   CMP     AL,' '
         JE      SCAN7
         CMP     AL,0AH          ;Is it line feed?
         JNE     SCAN6
         INC     NUMLF
         JMP     SCAN8
SCAN6:   OR      SWITCH2,NODATA  ;Non-space found
;
SCAN7:   CMP     CX,255          ;Record too big?
         JE      SCAN8           ;Chop record at 255 bytes
         JMP     SCAN2
;
SCAN8:   MOV     RECLEN,CX
         CMP     WORK,0FH        ;If record begins with "sun"
         JNE     SCAN9           ; symbol, skip it
         JMP     SCAN1
;
SCAN9:   TEST    SWITCH2,NODATA  ;If nothing but spaces found,
         JNZ     SCAN_END        ; read another record
         JMP     SCAN1
;
SCAN_END:
         POP     DI
         POP     SI
         POP     CX
         POP     ES
         RET
;
SCAN_BUF ENDP
;
         PAGE
         ASSUME  CS:CSEG,DS:DATA,ES:NOTHING
PRINT    PROC    NEAR
         PUSH    ES
         PUSH    DI
         PUSH    DX
         PUSH    SI
;
         MOV     DI,COL          ;set column
         DEC     DI              ;adjust for zero offset
         DEC     AX              ;adjust row too
         CMP     CL,0            ;null string?
         JE      EXIT            ;if so,do nothing, Else,
;
         MOV     BX,BIOS         ;get ready to determine card type
         MOV     ES,BX           ;and number of columns
         MUL     ES:NCLMS        ;AX = column * words per line
         ADD     DI,AX           ;DI = words from start of screen
         SHL     DI,1            ;adjust for attribute bytes
;
         MOV     DX,ES:A6845     ;point to 6845 base port
         ADD     DX,6            ;point to status port
;
;CX has the count of characters to write,
;SI points to the string data,
;DI points to a screen position
;
         MOV     AX,0B800H       ;default to color card
         MOV     BX,ES:EQFLAG
         AND     BX,30H
         CMP     BX,30H          ;is it monochrome?
         JNE     CARDOK          ;no, go
         MOV     AX,0B000H       ;yes, set for monochrome
CARDOK:  MOV     ES,AX           ;points ES to video
;
;  DS:SI => first character of string
;  ES:DI => screen memory to display it
;  CX    => number of characters to display
;  DX    => status port of video card
;
;-------- Wait for horzontal retrace
TESTLO:  IN      AL,DX           ;get status
         TEST    AL,1            ;is it low?
         JNZ     TESTLO          ;no, keep checking
         CLI                     ;turn off interrupts
TESTHI:  IN      AL,DX           ;get status
         TEST    AL,1            ;is it high?
         JZ      TESTHI          ;no, keep checking
;-------- Okay to write to screen now (no 'hash')
         MOVSB                   ;[DS:DI]->[ES:DI],DI++,SI++,CX--
         INC     DI              ;skip the attribute byte
         LOOP    TESTLO          ;do till end of string
         STI                     ;turn interrupts back on
;
EXIT:    POP     SI
         POP     DX
         POP     DI
         POP     ES
         RET
;
PRINT    ENDP
;
LIST     ENDP
CSEG     ENDS
;
         END     LIST
