        name    plist
        page    78,132
        title   PLIST12 --- Print text file (version 1.2A)

;       Zider Brothers, San Francisco
;
;       Based on LIST.ASM by Ray Duncan
;
;6.27   Fixed output buffer bug.
;       Added version id on help screen.
;       Added PLIST id to error messages.
;       Fixed automatic computation of remaining available space
;         (courtesy Chris Dunford via Vern Buerg).
;
;6.5.86 Fixed title buffer init to conform to page offset, line
;         width parms.
;       Fixed end-of-input processing (now does not pump out extra
;         line with pg_offset pad plus line feed)
;
;6.4.86 Add /7 option to strip hi-bit (make ok 8-bit the default now)
;       Enlarged I/O buffers to max space available (64K assumed - may
;         blow system if full 64KB not available for code).
;       DEL char (07Fh or 127 decimal) is now treated as low-order control
;         character.
;       Add /b option for blanks substituted for low-order control chars
;         (Default is that non-special treatment control chars are discarded
;         from the output listing stream to keep output devices from
;         interpreting WordStar embedded print control chars).
;       Change default output file to zz.spl (from zz.lst).
;       Speed on AT 6/1 around 90-100K bps, and about 11-17,000 lines per minute.
;
;5.8.85 Add std error out for error messages
;       Disable code that toggles lpi, cpi on exit if parm was exercised
;       Change to COM file format
;       Input buffer moved to end, fill above program
;       Change input block size to 4096 bytes (for DOS 2.0 hard disk)
;       Conversion speed from 14K bps to 19K bps, depending on tabs expansion
;       Make ZZ.LST the default (file) output--21K-24K bps (bits per second)
;
;5.7.85 Make compressed, 8 lpi the default (using IBM PC Graphics printer)
;       Add /N option to get uncompressed print ("normal" print)
;       Exit print without changing settings if none set, toggle back if set
;       Disable FF bracketing, make no FF's at begin/end the default
;       Add /F switch to enable lead-in FF (tail end still disabled)
;       Add /S switch to print to std output device (so can redirect to file)
;       Change name to PLIST to avoid confusion with LIST545, etc by Vern Buerg
;       Add syntax, options help when null command line tail
;       Add page offset of 8 spaces
;       Added clarifying comments, code section identification breaks.
;
;5.6.85 Hack to add 8 Lines Per Inch option (/8)
;
;-----original documentation:
;
; LIST --- a utility to print out text files with titles and page
; numbers on  the current list device.  The high bit of all
; characters is  stripped [this option now must be specified on the command
; line with the /7 option], so that raw Wordstar or other word
; processing files can  be listed.  Embedded form feed codes are
; recognized, and tabs are  expanded.  Unknown control codes (such
; as the ^B and ^U codes found in Wordstar documents) are discarded.
; If using an Epson printer, compressed mode can be turned on with
; /C switch in command so that lines up to 128 characters long will
; fit on a normal page.  Requires PC-DOS 2.0 or MS-DOS 2.0.

; Used in the form:
; A>LIST path\filename.ext  ["title text"]  [/C]
; (items in square brackets are optional)

; version 1.0   February 28, 1984
; Copyright (c) 1984 by Ray Duncan
; May be freely reproduced for non-commercial use.

cr      equ     0dh             ;ASCII carriage return
lf      equ     0ah             ;ASCII line feed
ff      equ     0ch             ;ASCII form feed
eof     equ     01ah            ;End of file marker
tab     equ     09h             ;ASCII tab character
blank   equ     20h             ;space character

command         equ     80h     ;buffer for command tail

prog_size       =       offset end_code         ; s/b about 09f6h
end_segment     equ     0ffffh
stack_space     equ     100h
avail           =       end_segment-(offset end_code - cseg) - stack_space
;avail2         =       end_segment-prog_size-stack_space       ;gives error
                public  buf_size
;buf_size       equ     1024
buf_size        equ     avail/2
                public  output_buffer
output_buffer   equ     prog_size+buf_size
chk_stack       equ     output_buffer+buf_size+1
stack_start     equ     end_segment-stack_space+1

inblksize       equ     buf_size
outblksize      equ     buf_size
;inblksize      equ     8192    ;size of block reads from input file
;outblksize     equ     8192    ;size of block writes to output file
pg_offset       equ     8       ;set page offset to 8 spaces
linesize equ    132-pg_offset   ;maximum length of output line
page6lpi        equ     58      ;58 out of 66 lines
page8lpi        equ     80      ;80 of of 88 lines
heading_lines   equ     3       ;number of lines in page heading

std_out         equ     1       ;standard output
std_error       equ     2       ;standard error--not redirectable
std_printer     equ     4       ;standard printer
        page
cseg    segment para public 'CODE'

;old assume:
;       assume  cs:cseg,ds:data,es:data,ss:stack
        assume  cs:cseg,ds:cseg,es:cseg,ss:cseg
        org     100H
ENTRY:  jmp     start
;
;DATA area at end of the program.
;
who_am_i        db      'PLIST12: Zider Brothers, San Francisco'
start:
list    proc    far             ;entry point from PC-DOS

        push    ds              ;save DS:0000 for final
        xor     ax,ax           ;return to PC-DOS
        push    ax

list13:                         ;make sure we're running under DOS 2.0.
        mov     ah,30h
        int     21h
        cmp     al,2
        jae     list01          ;proceed, DOS 2.0 or greater
        mov     dx,offset msg3  ;DOS 1.x --- print error message
        mov     cx,msg3_len
        jmp     list9


;----------------------------------------------------------
;               Process command line

list01: call    get_title       ;get listing title from
                                ;command line tail.
        call    get_switch      ;look for /C, /N, /6, /8, etc switches, if any
        call    get_filename    ;get path and file spec. for
                                ;input file from command line tail.

        jnc     list15          ;jump, got acceptable name.
        mov     dx,offset msg2  ;missing or illegal filespec,
        mov     cx,msg2_len
        jmp     list9           ;print error message and exit.

;----------------------------------------------------------
;               Open input file

list15: call    open_input      ;now try to open input file
        jnc     list2           ;jump,opened input ok
        mov     dx,offset msg1  ;open of input file failed,
        mov     cx,msg1_len
        jmp     list9           ;print error msg and exit.

;----------------------------------------------------------
;               Open output file

list2:
        cmp     s_switch,0      ;output to std out?
        jne     list25          ;jump if DOS std output selected
        call    open_zzlst      ;open default output file
        jnc     list25          ;skip if ok open
        mov     dx,offset zzmsg ;opening default file error
        mov     cx,zzmsg_len
        jmp     list9           ;print error msg and xit.

;----------------------------------------------------------
;               Initialization

list25: call    init_buff       ;initialize input deblocking buffer

;----------------------------------------------------------
;               Set page, printer configuration

list20: test    compress_switch,-1 ;was /C switch found?
        jz      list21
        call    compress_on     ;yes,turn on compressed print mode
list21: test    ate_lpi,-1      ;/8 switch found?
        jz      list22
        call    ate_on
list22: test    six_lpi,-1      ;/6 switch found?
        jz      list23
        call    six_on
list23: test    norm_switch,-1  ;was /N switch found?
        jz      list3
        call    compress_off

;===============================================================;
;               Main program control loop                       ;
;                                                               ;

;----------------------------------------------------------
;               Process character input stream

list3:
        call    get_char        ;read 1 character from input.
        cmp     al,20h          ;is it a low-order control code?
        jb      short list30    ;yes, go check out what kind.
        cmp     al,07fh         ;not low-order, pivot on DEL char (127 decimal)
        jb      list4           ;ok char, write to list device.
        je      short list30    ;treat it like low-order control char.

mod1    label   word
        nop                     ;high bit is set on char = upper 128 chars.
        nop                     ;..two bytes here may be modified to
                                ;  'and  al,07h' by /7 option to strip hi-bit.
                                ;  Otherwise code falls through to jmp:
        jmp     list4           ;now write to list device.

list30: cmp     al,tab          ;is it a tab command?
        je      list5           ;yes,jump to special processing.
        cmp     al,cr           ;carriage return?
        jne     list31          ;
        mov     column,0        ;carriage return, store it into output
        jmp     list45          ;  string and initialize column count.
list31: cmp     al,lf           ;is it a line feed?
        je      list7           ;yes,jump to special processing. (force print)
        cmp     al,ff           ;is it a form feed?
        je      list6           ;yes, jump to special processing.
        cmp     al,eof          ;is it end of file marker?
        je      list8           ;yes,jump to close files.
        test    blank_sub,-1    ;substitute blank char for control char?
        jz      list32          ;no
        mov     al,blank        ;yes, replace ctl char with blank
        jmp     list4           ;now write to list device
list32: jmp     list3           ;none of the above--ignore it and get another

;----------------------------------------------------------
;               Special tab expansion

list5:                          ;process tab character
        mov     ax,column       ;let DX:AX=column count
        cwd
        mov     cx,8            ;divide it by eight...
        idiv    cx
        sub     cx,dx           ;remainder is in DX.
        add     column,cx       ;update column pointer.
list55:                         ;8 minus the remainder
        push    cx              ;gives us the number of
        mov     al,20h          ;spaces to send out to
        call    put_char        ;move to the next tab position
        pop     cx              ;restore space count
        loop    list55
        jmp     short list3     ;get next character

;----------------------------------------------------------
;               Form feed processing

list6:                          ;form feed detected
        call    write_maybe     ;if anything waiting in output
                                ;buffer, print it first
        call    print_heading   ;new page and print title
        jmp     list3           ;get next character from input

;----------------------------------------------------------
;               Put character into output line buffer

list4:
        inc     column          ;bump line char count

list45:                         ;write this character into
        call    put_char        ;forming output string.
                                ;is output buffer about to overflow?
        cmp     linput_ptr,linesize-1
        je      list7           ;yes, force print of buffer.
        jmp     list3           ;no, get next char. from input file.

;----------------------------------------------------------
;               Line feed  char or line full, flush line buffer

list7:                          ;line feed detected, interpreted
                                ;as print command.
        call    heading_maybe   ;print heading if needed
        call    write_line      ;print contents of text buffer
        jmp     list3           ;get more from input file

;----------------------------------------------------------
;               End of file processing

list8:                          ;end of file detected  (^Z, 1AH)
        call    close_input     ;close input file
        call    write_maybe     ;print anything that's waiting
                                ;in output buffer.

;disable end of job form feed check and form feed output:
;       cmp     ff_switch,0     ;see if FF's have been specified
;       je      list81          ;skip it if /F not set
;       mov     al,ff           ;send form feed to finish listing.
;list81:
;       call    put_char

;       call    write_line      ;why need? already called write_maybe
        call    flush_out       ;flush output buffer
        call    close_output    ;close output file
        jmp     list85          ;skip following code

;disable this exit code--leave printer in mode(s) selected by cmd line parms:
;                               ;turn off compressed print mode,
;                               ;if it was enabled.
;       test    compress_switch,-1
;       jz      list82
;       call    compress_off
;list82:        cmp     norm_switch,0
;       je      list83
;       call    compress_on
;list83:        cmp     ate_lpi,0
;       je      list84
;       call    six_on
;list84:        cmp     six_lpi,0
;       je      list85
;       call    ate_on

list85:
        ret                     ;now return to PC-DOS.

;----------------------------------------------------------
;               Error: program termination
;
;DX     offset to error message
;CX     length of error message

error_out:
list9:                          ;come here to print error message
        mov     bx,std_error
        mov     ah,40H
        int     21H
        mov     bx,std_error
        mov     cx,hlpmsg_len
        mov     dx,offset hlpmsg        ;help with syntax added here
        mov     ah,40H
        int     21H
        ret                     ;return to DOS

list    endp

;                                                               ;
;               End of main program control loop                ;
;===============================================================;

page

;----------------------------------------------------------
;               Get filename

get_filename proc near          ;process name of input file
                                ;DS:SI <- addr command line
        mov     si,offset command
                                ;ES:DI <- addr filespec buffer
        mov     di,offset input_name
        cld
        lodsb                   ;any command line present?
        or      al,al           ;return error status if not.
        jz      get_filename4
get_filename1:                  ;scan over leading blanks
        lodsb                   ;to file name
        cmp     al,cr           ;if we hit carriage return
        je      get_filename4
        cmp     al,'/'          ;or switch,
        je      get_filename4
        cmp     al,'"'          ;or quote mark, filename missing.
        je      get_filename4   ;so go return error flag.
        cmp     al,20h          ;is this a blank?
        jz      get_filename1   ;if so keep scanning.
get_filename2:                  ;found first char of name,
        stosb                   ;move last char. to output
                                ;file name buffer.
        lodsb                   ;check next character, found
        cmp     al,cr           ;carriage return yet?
        je      get_filename3   ;yes,exit with success code.
        cmp     al,'"'          ;same if quote encountered.
        je      get_filename3
        cmp     al,20h          ;is this a blank?
        jne     get_filename2   ;if not keep moving chars.
get_filename3:                  ;exit with carry =0
        clc                     ;for success flag
        ret
get_filename4:                  ;exit with carry =1
        stc                     ;for error flag
        ret
get_filename endp

;----------------------------------------------------------
;               Get title

get_title proc near             ;process title for listing
                                ;DS:SI <- addr command line
        mov     si,offset command
                                ;ES:DI <- addr page heading buffer
        mov     di,offset heading1
        add     di,pg_offset    ;mov pointer into buf by page offset amt
        cld
        lodsb                   ;any command line present?
        or      al,al           ;no,exit
        jz      get_title3
get_title1:                     ;scan for leading <"> to find title.
        lodsb
        cmp     al,cr           ;if we hit carriage return,
        je      get_title3      ;title text is missing.
        cmp     al,'"'          ;found delimiter?
        jne     get_title1      ;if so keep scanning.
get_title2:                     ;get next char. of title.
        lodsb
        cmp     al,'"'          ;terminate if 2nd <"> delimiter
        je      get_title3      ;or carriage return found
        cmp     al,cr
        je      get_title3
        stosb                   ;store this char. into page heading buffer
        jmp     get_title2      ;examine next char.
get_title3:
        ret
get_title endp

;----------------------------------------------------------
;               Get switch

get_switch proc near            ;Scan the input line for a "/"
                                ;delimiting a switch, then make
                                ;sure it is legal "/C" or "/c".
                                ;If legal switch found, set
                                ;variable COMPRESS_SWITCH true.
                                ;Also check for /8 for 8 lines per inch
                                ;               /6 for 6 lines per inch
                                ;               /N for normal (uncompressed)
                                ;               /S for std out
        mov     ax,std_printer  ;set default output device to printer
        mov     output_handle,ax
        mov     si,offset command+1  ; DS:SI = addr of command line
get_switch1:                    ;look for "/" character
        lodsb
        cmp     al,cr           ;if we run into a carriage return,
        jnz     gsw1            ;not cr
        jmp     get_switch2     ;is cr,switch missing so take normal exit.
gsw1:   cmp     al,'/'
        jne     get_switch1     ;not '/' yet, keep looking.
        lodsb                   ;found '/', pick up next char.
chk_8:  cmp     al,'8'          ;8 lines per inch?
        jne     chk_6
        mov     es:ate_lpi,-1   ;set 8 lines per inch switch
        jmp     get_switch1     ;check for more options
chk_6:  cmp     al,'6'          ;6 lines per inch?
        jne     chk_7
        mov     es:six_lpi,-1   ;set 6 lines per inch switch
        jmp     get_switch1     ;check for more options
chk_7:  cmp     al,'7'          ;7-bits only? (strip high bit)
        jne     chk_b
        mov     es:sept_bits,-1 ;set for 7-bit output only (flag not used..
                                ;  ..used self-modifying code instead:
        mov     ax,cs:and_w     ;move op to in-line code location
        mov     cs:mod1,ax      ;                                       )
        jmp     get_switch1     ;check for more options
and_w   label   word            ;and-operator
and_op: and     al,07fh         ;strip hi-bit op code bytes

chk_b:  cmp     al,'b'          ;b=blank sub for low control chars
        jne     chk_c
        mov     es:blank_sub,-1 ;set for blank
        jmp     get_switch1     ;check for more options
chk_c:  or      al,20h          ;and fold to lower case.
        cmp     al,'c'          ;c=compress
        jne     chk_n           ;not /C, check for /N
                                ;set compress switch
        mov     es:compress_switch,-1
        jmp     get_switch1     ;check for more options
chk_n:  cmp     al,'n'          ;n=normal
        jne     chk_f           ;not n, check for /F
        mov     es:norm_switch,-1
        jmp     get_switch1     ;check for more options
chk_f:  cmp     al,'f'          ;f=bracket print with FF's
        jne     chk_s
        mov     es:ff_switch,-1
        jmp     get_switch1     ;check for more options
chk_s:  cmp     al,'s'          ;/S
        jne     get_switch2     ;not f, jump to return
        mov     es:output_handle,std_out        ;set output to std out
        mov     es:s_switch,-1
        jmp     get_switch1     ;check for more options

get_switch2:
        ret                     ;exit
get_switch endp

;----------------------------------------------------------
;               Open input file

open_input proc near            ;open input file
                                ;DS:DX=addr filename
        mov     dx,offset input_name
        mov     al,0            ;AL=0 for read only
        mov     ah,3dh          ;function 3dh=open
        int     21h             ;handle returned in AX,
        mov     input_handle,ax ;save it for later.
        ret                     ;CY is set if error
open_input endp

;----------------------------------------------------------
;               Open default output file

open_zzlst      proc    near    ;open default output file
;This will open an existing file if it exists
        mov     dx,offset zzlst ;ASCIIZ string of default output file name
        mov     al,1            ;open file for writing
        mov     ah,3dh          ;open a file
        int     21h
        jc      ozz1            ;if CY, check if not found
savozz: mov     output_handle,ax
        mov     zzlst_handle,ax ;in case we need it
;move to the end of the file for default file append
        mov     bx,ax           ;handle to BX for LSEEK
        mov     cx,0
        mov     dx,0
        mov     al,2            ;to end of file plus offset of zero (CX:DX)
        mov     ah,42h          ;LSEEK call (what's an LSEEK???)
        int     21h             ;CY may be set here if invalid handle or function

ozzxit: ret                     ;carry will be set if error

        public ozz1
ozz1:   cmp     ax,2            ;if =2, then file not found and must be created
        jne     ozz9
        mov     dx,offset zzlst ;in case trashed by DOS
        mov     cx,20h          ;creating normal file
        mov     ah,3ch          ;create file call
        int     21h
        jnc     savozz          ;ok create if no CY

ozz9:   stc                     ;other error (too many handles or access denied)
        ret
open_zzlst      endp

;----------------------------------------------------------
;               Initialize buffers

init_buff proc near             ;initialize input buffer
        call    read_block      ;read 1st block of input file
        mov     linput_ptr,pg_offset    ;initialize pointer to output string
        ret
init_buff endp

;----------------------------------------------------------
;               Read input block

read_block proc near            ;read block of data from input file.
        mov     bx,input_handle
        mov     cx,inblksize
        mov     dx,offset input_buffer
        mov     ah,3fh
        int     21h
        jnc     read_block1     ;jump if no error status
        mov     ax,0            ;simulate a zero length read if error
read_block1:
        cmp     ax,inblksize    ;was full buffer read in?
        je      read_block2     ;yes,jump
        mov     bx,ax           ;no, store End-of-File mark
        mov     byte ptr [input_buffer+bx],eof
read_block2:
        mov     input_ptr,0     ;initialize pointer to input buffer.
        ret
read_block endp

;----------------------------------------------------------
;               Set page, printer configuration

compress_on proc near           ;turn on compressed printing mode
                                ;by sending command string.
        mov     cx,comp_command_length
        mov     bx,output_handle
        mov     dx,offset comp_command
        mov     ah,40h
        int     21h
        ret
compress_on endp

compress_off proc near                  ;turn off compressed printing mode
                                        ;by sending command string.
        mov     cx,norm_command_length
        mov     bx,output_handle
        mov     dx,offset norm_command
        mov     ah,40h
        int     21h
        ret
compress_off endp

ate_on  proc    near                    ;turn on 8 lpi
        mov     ax,page8lpi
        mov     pagesize,ax
        mov     linecount,ax
        mov     cx,ate_lpi_cmd_len
        mov     bx,output_handle
        mov     dx,offset ate_lpi_cmd
        mov     ah,40H
        int     21H
        ret
ate_on  endp

six_on  proc    near                    ;turn on 6 lpi
        mov     ax,page6lpi
        mov     pagesize,ax
        mov     linecount,ax
        mov     cx,six_lpi_cmd_len
        mov     bx,output_handle
        mov     dx,offset six_lpi_cmd
        mov     ah,40H
        int     21H
        ret
six_on  endp


;----------------------------------------------------------
;               Get one character from input buffer

get_char proc   near            ;get one character from input buffer
        mov     bx,input_ptr    ;is pointer at end of buffer?
        cmp     bx,inblksize
        jne     get_char1       ;no,jump
                                ;yes, buffer is exhausted,
        call    read_block      ;new block must be read from disk.
        mov     bx,0            ;initialize buffer pointer.
get_char1:
        mov     al,byte ptr [input_buffer+bx]
        inc     bx              ;bump input buffer pointer
        mov     input_ptr,bx
        ret
get_char endp

;----------------------------------------------------------
;               Put char into output line buffer

        public  put_char
put_char proc   near            ;put one character into output buffer
        mov     bx,linput_ptr
        mov     [line_buffer+bx],al
        inc     linput_ptr      ;bump pointer to output string
        ret
put_char endp

;----------------------------------------------------------
;               Heading maybe--if end of the page

        public  heading_maybe
heading_maybe proc near         ;print heading if the line
                                ;count justifies it
        mov     ax,pagesize
        cmp     linecount,ax
        jl      heading_maybe2  ;jump,page not full yet
        call    print_heading   ;form feed (maybe) and print title
heading_maybe2:
        ret
heading_maybe endp

;----------------------------------------------------------
;               Print heading

        public print_heading
print_heading proc near         ;print form feed, title, and page no.
        inc     pagecount       ;bump page number,
        mov     ax,pagecount    ;load it,
        aam                     ;and turn it into ASCII,
        add     ax,'00'
        mov     heading2,ah     ;then store into heading string.
        mov     heading2+1,al
                                ;now print the heading string.
        cmp     pagecount,1     ;check if first page heading
        je      chk_ff          ;see if FF switch was specified
        public  ph2
ph2:    mov     dx,offset heading_buffer        ;header including lead FF
        mov     cx,heading_length
        public  ph3
ph3:
;put these lines  into output buffer now instead:
;       mov     bx,output_handle
;       mov     ah,40h
;       int     21h

        call    put_line

                                ;initialize line count
        mov     linecount,heading_lines
        mov     column,0        ;and column counter
        ret

        public chk_ff
chk_ff: cmp     ff_switch,-1    ;see if set
        je      ph2             ;if set, jump back
        mov     dx,offset heading_buffer+1      ;not set, skip lead FF on page 1
        mov     cx,heading_length-1
        jmp     ph3

print_heading endp


;----------------------------------------------------------
;               Write maybe--if chars in the output line buffer

write_maybe proc near           ;transmit line to list device, if
                                ;output buffer contains anything.
        mov     ax,linput_ptr   ;pointer is more than pg_offset if
        cmp     ax,pg_offset    ;characters are waiting in buffer.
;       or      ax,ax           ;
        jz      write_maybe1    ;nothing, jump to exit
        call    write_line      ;something there, send it to printer
write_maybe1:
        ret
write_maybe endp

;----------------------------------------------------------
;               Write line buffer -- put line in output

write_line proc near            ;transmit contents of output
                                ;buffer to the standard list device.
        mov     al,lf           ;append line feed to string.
;       call    put_char        ;insert code directly instead of call
        mov     bx,linput_ptr
        mov     [line_buffer+bx],al
        inc     linput_ptr      ;bump pointer into output line buffer
        mov     cx,linput_ptr   ;CX contains length of string
                                ;DX:DX=buffer address
        mov     dx,offset line_buffer

        call    put_line        ;put line into output buffer
;       mov     bx,output_handle;BX=handle for standard list device is default
;       mov     ah,40h          ;function 40h=write to device.
;       int     21h             ;request service from DOS.


        inc     linecount       ;count lines printed this page.
        mov     linput_ptr,pg_offset    ;reset pointer to list device buffer
        ret
write_line endp

;----------------------------------------------------------
;               Put line into output buffer
;
;DX     ptr to line buffer
;CX     cnt of chars in line to be put

        public  put_line
put_line        proc    near

        cmp     cx,0            ;anything to send?
        je      xit_putlin
put1:   mov     ax,output_ptr   ;get current ptr into output block
        mov     bx,ax           ;set index for destination
        add     ax,cx           ;add the line size to be added
        cmp     ax,outblksize   ;see if we can take it
        jbe     putl2           ;if not, flush the block first
        call    flush_out
        jc      xit_putlin      ;exit if carry (error writing block)
        jmp     put1            ;recycle

putl2:  mov     output_ptr,ax   ;save new ptr (a bit out of order, but available)
        mov     si,dx           ;source into si
        mov     di,offset output_buffer
        add     di,bx           ;dest into di
        cld                     ;increment pointers (clear direction flag: fwd)
        rep     movsb           ;do your thing
        clc                     ;clear carry to indicate ok return

xit_putlin:
        ret

        public  flush_out
flush_out       proc    near
        push    cx
        push    dx
        mov     cx,output_ptr           ;bytes to write
        mov     dx,offset output_buffer ;source of bytes
        mov     bx,output_handle        ;file to write them to
        mov     ah,40h                  ;DOS Write to File call
        int     21H                     ;the old 21H maneuver
        cmp     ax,cx                   ;written should equal requested
        jne     error_putlin
        mov     output_ptr,0            ;zero the buffer counter
        clc
flush_xit:
        pop     dx                      ;restore registers
        pop     cx
        ret

        public  error_putlin
error_putlin    equ     $               ;here if file write error
        mov     dx,offset msg4
        mov     cx,msg4_len
        mov     bx,std_error
        mov     ah,40h
        int     21h
        stc
        jmp     flush_xit

flush_out       endp

put_line        endp

;----------------------------------------------------------
;               Close input file

close_input proc near           ;close input file
        mov     bx,input_handle ;BX=handle
        mov     ah,3eh
        int     21h
        ret
close_input endp

;----------------------------------------------------------
;               Close output file

close_output    proc    near    ;close output file
        mov     bx,output_handle
        mov     ah,3eh
        int     21h
        ret
close_output    endp

;Move this to the end:
;cseg   ends

page
;===============================================================;
;               Data area                                       ;

;disable data segment setup:
;data   segment para public 'DATA'

                public  input_name
input_name      db      64 dup (0)      ;buffer for input filespec

                public  input_handle
input_handle    dw      0               ;token from PCDOS for input file.
                public  output_handle
output_handle   dw      std_printer     ;for printer or std out
zzlst           db      'ZZ.SPL',0      ;ASCIIZ string for default output
zzlst_handle    dw      1               ;std file output name, later reset

                public  input_ptr
input_ptr       dw      0               ;pointer into input blocking buffer
                public  linput_ptr
linput_ptr      dw      pg_offset       ;pointer into line blocking buffer
                public  output_ptr
output_ptr      dw      0               ;ptr into output blocking buffer

column          dw      0               ;column count for tab processing
                public  linecount
linecount       dw      page8lpi        ;line counter, current page.
                                        ;(set to "pagesize" initially to
                                        ;force first heading on listing)
pagesize        dw      page8lpi        ;initially at 8 lpi size
                public  pagecount
pagecount       dw      0               ;current page number

compress_switch dw      0               ;set to -1 if /C switch
                                        ;found in command line tail.

comp_command    db      0fh             ;command string for compressed mode
comp_command_length equ $-comp_command

norm_switch     dw      0               ;set to -1 if /N switch
norm_command    db      12h             ;command string for normal print
                                        ;(actually: turn off compressed)
norm_command_length equ $-norm_command

ate_lpi         dw      0               ;set to -1 if /8 switch
ate_lpi_cmd     db      1BH,'0'         ;ESC 0
ate_lpi_cmd_len equ     $-ate_lpi_cmd

sept_bits       dw      0               ;set to -1 if /7 switch

blank_sub       dw      0               ;set to -1 if /b switch

six_lpi         dw      0               ;set to -1 if /6 switch
six_lpi_cmd     db      1BH,'2'         ;ESC 2
six_lpi_cmd_len equ     $-six_lpi_cmd

ff_switch       dw      0               ;set to -1 if /F switch (lead FF)
s_switch        dw      0               ;set to -1 if /S switch (std out)

msg1            db      cr,lf
                db      'PLIST: cannot find input file.'
                db      cr,lf,'$'
msg1_len        equ     $-msg1-1        ;net of trailing '$'

msg2            db      cr,lf
                db      'PLIST: missing file name.'
                db      cr,lf,'$'
msg2_len        equ     $-msg2-1

msg3            db      cr,lf
                db      'PLIST: requires PC-DOS version 2.0 or greater.'
                db      cr,lf,'$'
msg3_len        equ     $-msg3-1

msg4            db      cr,lf
                db      'PLIST: error writing output block.'
                db      cr,lf,'$'
msg4_len        equ     $-msg4-1

zzmsg           db      cr,lf
                db      'PLIST: error opening default file ZZ.SPL.'
                db      cr,lf,'$'
zzmsg_len       equ     $-zzmsg-1


hlpmsg          db      cr,lf
                db      'Syntax:  [d\p\]filename.ext ["title text"] [/8/6/b/7/n/c/f/s]',cr,lf
                db      cr,lf
                db      '       /8      print 8 lpi (default)',cr,lf
                db      '       /6      print 6 lpi (66 lines per page)',cr,lf
                db      '       /b      blank substitution for low ctrl chars (default: discard)',cr,lf
                db      '       /7      7-bits print (strip high bit)',cr,lf
                db      '       /c      compressed print (default)',cr,lf
                db      '       /n      non-compressed print (10 cpi)',cr,lf
                db      '       /f      leading Form Feeds added (no trailing in any case)',cr,lf
                db      '       /s      output to std out (screen), else file zz.spl default',cr,lf
                db      cr,lf
                db      'Notes:  no wildcards (*.*)  - use FOR expansion ',cr,lf
                db      '        output dumped into zz.spl on current path - 15,000 lpm on AT',cr,lf
                db      '        Version 1.2A 6.27.86',cr,lf
                db      cr,lf
                db      'Usage:  ',cr,lf,cr,lf
                db      '  C>for %1 in (*.sno) do plist %1 "6.4.86 Snobol4+ source        %1       "',cr,lf
                db      '  C>plist d:t.dta /s >tt',cr,lf
                db      '$'


hlpmsg_len      equ     $-hlpmsg-1      ;not including the '$'


                public  line_buffer
line_buffer     db      pg_offset dup(' ')      ;page offset blank pad
                db      linesize-pg_offset dup (?);buffer used to build output
                                        ;lines for list device

                public          heading_buffer
heading_buffer  db      ff              ;form feed control code
heading1        db      linesize-pg_offset-7 dup (' ')  ;filled in with title from user
                db      'Page '                         ;7 chars in Page ##
heading2        db      '00',cr
                db      heading_lines dup (lf)
heading_length  equ     $-heading_buffer

;input_buffer   db      inblksize       dup ('x');deblocking buffer for input file
                public  input_buffer
                even
end_code        equ     $               ;end of code label
input_buffer    equ     $               ;filled above program, no cseg
                                        ;space required in .COM file
;output_buffer  equ     $+inblksize     ;output buffer space
;data segment disabled:
;data   ends

;disable code for stack segment:
;stack  segment para stack 'STACK'
;       db      64 dup (?)
;stack  ends

cseg    ends

        end     entry
