home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
STARLET
/
LSWP106.ZIP
/
LSWP106.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-10-12
|
35KB
|
1,348 lines
; LSWEEP, MSDOS & CCPM version by Howard Vigorita, NYACC, CP/M SIG
; upload comments &/or updates to (718) 539 - 3338
;
release equ 1
version equ 06
date macro
db '10/12/86'
endm
;
; LSWEEP is a MSDOS generic program to step through a directory of
; LBR library members in 'sweep' fashion, with the ability to view
; or extract members. This version has been derived from the CP/M-86
; versions of LDIR & LTYPE by Charlie Godet-Ceraolo. This version has
; also been qualified for use under Concurrent PCDOS 4.1 and 5.0.
;
; This software is released into the public domain on the condition
; that it is not incorporated into any other software for which the
; source code and credits are not supplied or included in any library
; for which redistribution is restricted. Any variance from these
; conditions may only be obtained on written consent of the author.
;
; Non-Profit Public Domain Libraries & BBS's: redistribution and use
; of this package is encouraged.
;
; All other commercial activities: redistribution of this package is
; encouraged. Distribution of the executable file alone is permitted
; so long as the signon is left intact. The entire package may be
; included in a software library for commercial distribution on the
; condition that the distributor waive any rights in the software
; library which might tend to restrict its redistribution, other than
; rights similar to ones reserved here. All non-profit library and
; BBS proprietors, as well as other software authors, are intended to
; be benificiaries of this covenant. Any enrichment obtained in
; violation of this covenant shall be held in trust and disgourged on
; demand of the author or any benificiary.
;
; REGENERATION
; ------------
;
; To reassemble this program with MASM 1.0 or 2.0:
; MASM LSWEEP ;
; LINK LSWEEP ;
; With later MASMs, use the "/A" option to link segments in alpha order
;
;
; HISTORY
; -------
; ver 1.06 Removed '?' in fcb open call for CCPM 5.0.
;
; ver 1.05 Run time detection of CCPM for signon.
;
; ver 1.04 Quashed out spaces in filename z-strings for CCPM 4.1
; compatability and optimized the unsqueezer.
;
; ver 1.03 Added command interpretation during paged viewing
;
; ver 1.02 Added P option to allow paged viewing
;
; ver 1.00 Combined LDIR & LTYPE with 'sweep' interface
;
;-----------------------------------------------------------------------
; equates
;
; configuration constants
;
false equ 0
true equ NOT false
ibm_chr_set equ false ; IBM ext char set (cute little boxes)
page_len equ 20 ; # of lines for page scroll
dir_buf_sects equ 4*8 ; # of directory records to buffer
rec_size equ 128 ; LBR logical record size
irec_per_blk equ 4*27 ; count of input records to buffer
orec_per_blk equ 4*27 ; count of unsqueezed records to buffer
ibuf_size equ irec_per_blk*rec_size
obuf_size equ orec_per_blk*rec_size
; LBR equates and offsets
;
entries equ rec_size*irec_per_blk/entry_len
tree_size equ 257 ; max chars in Huffman code
entry_len equ 32
active equ 00H
unused equ 0FFH
deleted equ 0FEH
status equ 0
fname equ 1
extension equ 9
index equ 12
count equ 14 ; member size in 128 byte blocks
crc equ 16
; operating system equates
;
dos equ 21h ; MSDOS entry point
conout equ 02h ; write console character
dir_conin equ 07h ; direct console input
flush_kb equ 0Ch ; flush type-ahead keyboard buffer
openf equ 0Fh ; open file
srch_fst equ 11h ; search first
setdta equ 1Ah ; set disk transfer address
read_blk equ 27h ; random block read
setiv equ 25h ; set interrupt vector
xctl_c equ 33h ; extend ctl-c checking
makstrm equ 3Ch ; make file stream
opnstrm equ 3Dh ; open file stream
clostrm equ 3Eh ; close output stream
wrtstrm equ 40h ; write to output stream
trmproc equ 4Ch ; terminate process
; Ascii equates
;
TAB equ 09H
CR equ 0DH
LF equ 0AH
eof equ 1Ah
; Base Page Program Segment Prefix
; --------------------------------
basepg SEGMENT AT 0
; base page fields of interest
ORG 5Ch
bfcb equ $
ORG 80h
bbuff equ $
basepg ENDS
; Program Data Storage Area
; -------------------------
data SEGMENT WORD
signon db cr,lf,'LSWEEP for ',0
signon1 db 'DOS, version ', release + '0', '.'
db (version/10) + '0'
db (version MOD 10) + '0',', '
date
db ', Howard Vigorita',CR,LF,
db 0
ms_dos db 'MS-',0
ccpm db 'Concurrent PC ',0
menu_beg equ $
if ibm_chr_set
menu db CR,LF
db tab,0DAh,47 dup(0C4h),0BFh,cr,lf
db tab,0B3h,tab,tab,' COMMANDS',tab,tab,tab,0B3h,cr,lf
db tab,0B3h,6 dup(tab),0B3h,cr,lf
db tab,0B3h,tab, ' ? - Display this menu',tab,tab,tab,0B3h,cr,lf
db tab,0B3h,tab, ' E - Extract & unsqueeze a member',tab,0B3h,cr,lf
db tab,0B3h,tab, ' Q - Quick extract w/o unsqueezing',tab,0B3h,cr,lf
db tab,0B3h,tab, ' V - View a (viewable) member',tab,tab,0B3h,cr,lf
db tab,0B3h,tab, ' P - Page through a member',tab,tab,0B3h,cr,lf
db tab,0B3h,tab, ' X - Exit this program',tab,tab,tab,0B3h,cr,lf
db tab,0B3h,' Anything else skips to the next member',tab,0B3h,cr,lf
db tab,0C0h,47 dup(0C4h),0D9h,cr,lf
db 0
else
menu db CR,LF,tab,tab,tab,'COMMANDS:',cr,lf,cr,lf
db tab,tab,'? - Display this menu',cr,lf
db tab,tab,'E - Extract & unsqueeze a member',cr,lf
db tab,tab,'Q - Quick extract w/o unsqueezing',cr,lf
db tab,tab,'V - View a (viewable) member',cr,lf
db tab,tab,'P - Page through a member',cr,lf
db tab,tab,'X - Exit this program',cr,lf
db tab,' Anything else skips to the next member',cr,lf
db 0
endif
menu_len equ $-menu_beg
USEMSG db TAB,'USAGE: "LSWEEP [D:]LibraryName[.LBR]"',CR,LF
db tab,' or "LSWEEP D:" if only one LBR on D:',0
drv_req db 'Enter destination drive A: to P: (CR=default): ',0
k_msg db 'k > <',8,8,0
unsq_msg db ' unsqueezing -> ',0
page_msg db 'CTL-X cancels, SPACE advances a line, '
db 'RETURN advances a page',cr,lf,lf,0
OPNMSG db 'Library file not found',0
LIBEXT db 'LBR',0
EOFMSG db 'Premature End of File',0
NoRoomMsg db 'No room for Huffman tree',CR,LF,0
mak_msg db 'Error making output file',0
wrt_msg db 'Error writing to output',0
rd_msg db 'Error reading library file',0
full_msg db 'Error writing to output file, disk may be full',0
lbrmsg db 'Library: ',0
done_msg db 'DONE.',cr,lf,0
MAXMSG db '; maximum slots:',0
FREEMSG db '; free slots:',0
; dynamic data area
;
dda equ $
max_entries equ dda+2 ; dw (?) size of dir
in_use equ max_entries+2 ; dw (?) Max - inuse = free
entries_todo equ in_use+2 ; dw (?) how many so far
SEARCH_STR equ entries_todo+2 ; db 11 dup (?) for fcb2 fname
FCB equ search_str+11 ; db (?)
FCBDN equ FCB
FCBFN equ fcb+1 ; db 8 dup(?)
FCBFT equ fcbfn+8 ; db 3 dup(?)
FCBEX equ fcbft+3 ; db (?)
FCBS1 equ fcbex+1 ; db (?)
FCBS2 equ fcbs1+1 ; db (?)
FCBRC equ fcbs2+1 ; db (?)
FCB2 equ fcbrc+1 ; db 16 dup (?) second fcb
FCBD0 equ FCB2
FCBCR equ fcb2+16 ; db (?)
FCBRNO equ fcbcr+1 ; db 4 dup (?)
decbuf equ fcbrno+4 ; db 6 dup (?) decimal output buffer
code_tree equ decbuf+6 ; db tree_size * 4 dup (?) Huffman tree
lbr_name equ code_tree+(4*tree_size) ;db 15 dup (?)
drvout equ lbr_name+15 ; db 2 dup (?)
filout equ drvout+2 ; db 15 dup (?)
buf_counter equ filout+15 ; dw ? bytes left in input buffer
buf_size equ buf_counter+2 ; dw ? input buffer size
buf_ptr equ buf_size+2 ; dw ? next input buffer byte
out_handle equ buf_ptr+2 ; dw ?
entries_left equ out_handle+2 ; dw ?
mbr_name equ entries_left+2 ; dw ?
sav_sp equ mbr_name+2 ; dw ?
entry_ptr equ sav_sp+2 ; dw ?
buf_num equ entry_ptr+2 ; dw ?
dbuf_sects equ buf_num+2 ; dw ?
blks_left equ dbuf_sects+2 ; dw ? size in 128 byte blocks
obuf_ctr equ blks_left+2 ; dw ?
obuf_bytes equ obuf_ctr+2 ; dw ?
obuf_ptr equ obuf_bytes+2 ; dw ?
drv_error equ obuf_ptr+2 ; db ? drive request out of range
last_char equ drv_error+1 ; db ? last character read
rot_counter equ last_char+1 ; db ? rotating bit counter
rot_byte equ rot_counter+1 ; db ? rotating byte
squeezed equ rot_byte+1 ; db ? un/squeezed flag
rep_cnt equ squeezed+1 ; db ? repeat counter
line_count equ rep_cnt+1 ; db ? line counter for page function
wflag equ line_count+1 ; db ? write to file requested
rflag equ wflag+1 ; db ? raw write to file (no unsq)
pflag equ rflag+1 ; db ? page through file
dta equ pflag+1 ; db 128 dup (?) disk transfer area
obuf equ dta+ibuf_size
data ENDS
; PROGRAM STARTS HERE
; -------------------
code SEGMENT WORD public
assume CS:code, DS:basepg, SS:a_stack
; note that data segment register is left pointing at the base page
; program segment prefix pending a copy to our own prog data area
;
lsweep:
mov AX,data ;init extra segment register
mov ES,AX ; to point to prog data area
assume ES:data
; copy base page file control block to our own fbc in prog data area
;
mov SI,offset bfcb ;base pg fcb to source index
mov DI,offset fcb ;our fcb to dest index
mov CX,37 ; # of bytes to move
rep movsb ;block move em
; copy base page disk transfer buffer to our own dta in prog data area
;
mov SI,offset bbuff ;base pg dta to source index
mov DI,offset dta ;our dta to dest index
mov CX,64 ; # of words to move
rep movsw ;block move em
; point SS register at program segment prefix
; and use default dta & fcb as 165 byte stack
;
push DS
pop SS
assume SS:basepg
mov SP,100h
; point the data segment register at our own data area
;
push ES
pop DS
assume DS:data
; intercept ctl-c interrupt & disable it for now
;
mov DX,offset int_disable ; address of an IRET instruction
call int_set
; turn on extended ctl-c detection
;
mov AX,xctl_c*256+1 ; AH=xctl_c; AL=1
mov DL,1
int dos
begin:
; Print signon message
;
mov SI,offset signon
call display
push DS
xor AX,AX
mov DS,AX
mov AX,word ptr DS:380h ; see what's at INT 224
pop DS
or AX,AX
jz its_msdos ; if nothing, its MSDOS
mov SI,offset CCPM ; else, its Concurrent
jmp short disp_os
its_msdos:
mov SI,offset ms_dos
disp_os:
call display
mov SI, offset signon1 ; display rest of signon
call display
; check for command line, display usage if none
;
mov BX,offset dta
cmp byte ptr [BX],0
jnz cmdok ; we got one, proceed
; no command line, show usage and exit
;
call crlf
mov SI,offset USEMSG
call display
call crlf
jmp finish
cmdok:
call display_menu
; make sure file type is LBR
;
cktype:
mov SI,offset LIBEXT
mov DI,offset FCBFT
mov CX,3
rep movsb
; if no file name supplied, put in '????????'
;
ckfname:
mov DI,offset fcbfn
cmp byte ptr [DI],' '
jne lbr_open
mov AL,'?'
mov CX,8
rep stosb
; open the LBR file
;
lbr_open:
call open_file
or AL,AL
jz start_read
; No file, send message and leave
;
mov SI,offset OPNMSG
call display
jmp finish
; file found and opened, get directory information
;
start_read:
xor AX,AX
mov word ptr fcbrno,AX ; set for first record
mov word ptr fcbrno+2,AX ; set for first record
mov word ptr in_use,1 ; init member counter
mov CX,dir_buf_sects ; ask for default # of sectors
mov word ptr dbuf_sects,CX ; save directory buffer size
call read_sector ; read them in
or AL,AL
jz start_read_1 ; if non-zero, maybe eof
cmp AL,3 ; see if partial sector
jz start_read_1 ; if so, continue
jmp prem_eof ; else bail out
start_read_1:
mov BX,offset dta ; point to first entry
mov AX,[BX+count] ; get dir size in sectors
mov CX,AX ; save directory sect count for read
shl AX,1
shl AX,1 ; sectors * 4 = MAX_ENTRIES
mov word ptr max_entries,AX ; save it
cmp CX,word ptr dbuf_sects ; whole dir in buffer?
jbe find_last ; if so, another read not needed
mov word ptr dbuf_sects,CX ; else update directory buffer size
; read in the whole directory
;
dir_read:
xor AX,AX
mov word ptr fcbrno,AX ; set for first record
mov word ptr fcbrno+2,AX ; set for first record
mov CX,word ptr dbuf_sects ; number of dir sectors to buffer
call read_sector ; read em all
or AL,AL
jz find_last ; if non-zero, maybe eof
cmp AL,3 ; see if partial sector
jz find_last ; if so, continue
; premature end of file, send message, and exit
;
prem_eof:
mov SI,offset EOFMSG
call display
jmp finish
; locate the last directory & display slot usage
;
find_last:
mov BX,offset dta ; point to first entry
add BX,entry_len ; point to next entry
mov CX,word ptr dbuf_sects ; to allow for dir header
shl CX,1
shl CX,1
dec CX ; CX = 4*dbuf_sects - 1
find_last_1:
mov AL,byte ptr [BX+status]
cmp AL,unused ; first unused entry?
jz found_last ; yes, we're done
cmp AL,active ; active entry?
jnz find_last_2 ; no, don't count it
inc word ptr in_use ; yes, bump the member counter
find_last_2:
add BX,entry_len ; no, point to next entry
loop find_last_1 ; and continue processing
found_last:
call crlf
mov SI,offset lbrmsg
call display
mov SI,offset lbr_name
call display
mov SI,offset MAXMSG
call display
mov BX,word ptr max_entries
call bin_2_dec
mov SI,offset FREEMSG
call display
sub BX,word ptr in_use ; free slots = max - in use
call bin_2_dec
call crlf
call crlf
init_vars:
xor AX,AX ; initialize variables
mov word ptr in_use,AX
mov AX,word ptr max_entries ; get maximum entry count
mov word ptr entries_todo,AX ; and put in work counter
inc word ptr in_use ; adjust for the dir header
dec word ptr entries_todo ; likewise
mov BX,offset dta ; point to first entry
add BX,entry_len ; point to next entry
mov CX,word ptr dbuf_sects ; to allow for dir header
shl CX,1
shl CX,1
dec CX ; CX = 4*dbuf_sects - 1
; Read and analyze active entries
;
search_loop:
mov word ptr entries_left,CX; save search loop control
mov AL,byte ptr [BX+status]
cmp AL,unused ; first unused entry?
jz skipit ; yes, we're done
cmp AL,active ; active entry?
jnz skipit ; no, don't process it
inc word ptr in_use ; yes, bump the member counter
lea DI,[BX+fname] ; point to name
call doentry ; else display info
skipit:
dec word ptr entries_todo ; have we read em all?
jnz skipit_1 ; no, do some more
call crlf
jmp init_vars ; else, rewind LBR directory
skipit_1:
add BX,entry_len ; point to next entry
mov CX,word ptr entries_left
loop search_loop ; and continue processing
; (shouldn't ever fall through loop)
; back to DOS
;
finish:
mov AH,trmproc
int dos
; SUBROUTINES
; -----------
; entry point for reading/writing/viewing members
typesq:
mov BX,word ptr entry_ptr ; point to the directory entry
lea DI,[BX+fname] ; point to name
mov DX,[BX+index] ; get block # of member
mov word ptr fcbrno,DX ; save member's starting position
mov DX,[BX+count] ; get the member size in blocks
mov word ptr blks_left,DX ; save it
mov BX,offset dta ; get begining of input buffer
mov word ptr buf_ptr,BX ; init pointer
xor AX,AX
mov byte ptr squeezed,AL
mov byte ptr line_count,AL
mov word ptr buf_counter,1
; if the raw flag set, go to write loop whether or not squeezed
;
cmp byte ptr rflag,FALSE ; raw flag off?
je read_sq ; if so, go read the sq'd file
call crlf
call read_byte ; else, trigger buffer fill
dec word ptr buf_ptr ; but don't eat first byte
jmp write_loop ; go dump buffer to disk
; check for the 2 byte "squeezed" marker
read_sq:
call read_word ; read the 2 byte marker
cmp BX,0FF76h ; see if it's 76FFh (byte reversed)
je read_header ; if so, read the rest of the header
call crlf
call crlf
sub word ptr buf_ptr,2 ; else not sq'd so unread 2 bytes
cmp byte ptr wflag,FALSE ; and if write flag off
je con_dump ; dump buffer to console
jmp write_loop ; otherwise, dump buffer to disk
con_dump:
jmp type_loop
; The "squeezed" marker is followed by a two-byte checksum,
; which is the simple sum of all the one-byte characters in
; the source file, carried as a two byte sum modulo 2**16.
;
read_header:
mov SI,offset unsq_msg ; tell them we're unsqueezing
call display
call read_word ; skip over checksum
mov DI,offset filout ; DI=ptr to output file z-string
; The 2 byte checksum is followed by the true filename
; which is a null terminated, packed, ascii string
read_name:
call read_byte ; AL = *buf_ptr++ (filename byte)
stosb ; *DI++ = AL (filout z-string)
or AL,AL ; null end marker?
jz read_name_x ; if so, done with filename
call putchar ; else echo filename byte to console
jmp short read_name ; and try next byte
read_name_x:
page_test:
call crlf
cmp byte ptr pflag,TRUE ; see if paging flag on
jne page_test_x ; if not, skip message
mov SI,offset page_msg ; else, display page control commands
call display
jmp short mak_ofile
page_test_x:
call crlf
; make output file if wflag set
;
mak_ofile:
cmp byte ptr wflag,FALSE ; see if write flag set
je get_tree_size ; if not, go right to code tree
call mak_out ; else, make output file first
call init_obuf ; and init output buffer
; Load code dictionary. First word is the length followed by a
; series of word pairs. For each bit in the code, select the first
; or second (1) element. If the pair is positive, it's the table entry
; (code + 4*index) at which to continue with the next bit. If it's
; negative, it is the complement of the ASCII character (lsb).
;
get_tree_size:
call read_word ; read the code tree length to BX
cmp BX,tree_size ; see that its within defined limits
jbe load_tree ; if so, go load it
mov SI,offset NoRoomMsg ; else, error message
call display
jmp exit ; and bail out
load_tree:
shl BX,1 ; multiply BX by 4
shl BX,1
mov CX,BX ; use CX as input counter
mov DI,offset code_tree ; destination is our code_tree buffer
move_em:
call read_byte ; AL = *SI++
stosb ; *DI++ = AL
loop move_em ; if(--CX) jmp mov_em
mov byte ptr rot_counter,1 ; init to trigger read in decoder
mov byte ptr squeezed,TRUE ; set sq flag for dual purpose sq loop
jmp typesq_loop ; go to squeeze processor
; convert binary word to ascii decimal & output it
; uses the 8086 divide instruction
; parameters passed in registers as follows:
; BX binary word to be converted
;
bin_2_dec:
mov DI,offset decbuf ; address of output buffer
mov CX,5 ; buffer length-1
mov AL,' ' ; pad character
rep stosb ; clear buffer & point to end
mov byte ptr [DI], 0 ; init end of string
mov AX,BX ; put binary word into AX
mov SI,10 ; put divisor in SI
next_digit:
xor DX,DX ; clear dividend high word
div SI ; AX = (DX:AX)/SI, DX = remainder
add DX,'0' ; convert DL remainder byte to ascii
dec DI ; back step in buffer
mov byte ptr [DI], DL ; put character there
or AX,AX ; all done? (AX = 0?)
jnz next_digit ; if not, do another digit
mov SI,offset decbuf ; string address to SI
call display ; output it
ret
;
; command interpreter
cmd_int:
push AX
mov DX, offset exit ; point to exit routine
call int_set ; set ctl-C interrupt vector
mov AL,FALSE
mov byte ptr pflag,AL ; initalize the flags
mov byte ptr rflag,AL
mov byte ptr wflag,AL
pop AX
cmp AL,'?' ; help command
jne cmd_int_1
call display_menu
call back_step
jmp short cmd_int_x
cmd_int_1:
cmp AL,'X' ; exit command
jne cmd_int_2
jmp finish
cmd_int_2:
cmp AL,'V' ; view command
jne cmd_int_3
call typesq
call reload_dir
call back_step
jmp short cmd_int_x
cmd_int_3:
cmp AL,'Q' ; raw extract command
jne cmd_int_4
call get_drv
cmp byte ptr drv_error,TRUE
je cmd_int_x
mov byte ptr wflag,TRUE
mov byte ptr rflag,TRUE
call typesq
call reload_dir
jmp short cmd_int_x
cmd_int_4:
cmp AL,'E' ; extract & unsqueeze command
jne cmd_int_5
call get_drv
cmp byte ptr drv_error,TRUE
je cmd_int_x
mov byte ptr wflag,TRUE
call typesq
call reload_dir
jmp short cmd_int_x
cmd_int_5:
cmp AL,'P' ; page command
jne cmd_int_6
mov byte ptr pflag,TRUE
call typesq
call reload_dir
call back_step
jmp short cmd_int_x
cmd_int_6:
cmd_int_x:
mov DX, offset int_disable ; point to IRET instruction
call int_set ; disable ctl-C interrupts
ret
; Decode next squeezed character returning the translated
; character in AL. Transfers to exit sequence on eof.
;
decode:
mov AL,byte ptr rot_byte
mov AH,byte ptr rot_counter
xor BX,BX
mov DI,offset code_tree
mov BP,DI
; Read one bit at a time via the carry flag
read_bit:
dec AH ; adjust bit rotation counter
jz read_new_bits ; if haven't done all 8 bits, do next
read_nxt_bit:
rcr AL,1
jnc its_0 ; point to this entry if lsb=0
inc DI ; else, advance to next entry (lsb=1)
inc DI
its_0:
mov BX,word ptr [BX+DI] ; read the code tree entry
cmp BX,0FEFFh ; see if code tree endmarker = 0FEFFh
je decode_eof ; if so, signal eof
or BX,BX ; check code tree entry msb
js decode_x ; minus = leaf node
; plus = index to next node
mov DI,BP ; DI=code tree root
shl BX,1 ; BX=code tree entry * 4
shl BX,1
jmp short read_bit ; go decode next bit
read_new_bits:
call read_byte ; and get 8 new bits (1 byte) into AL
mov AH,8 ; else reset rotation counter
jmp short read_nxt_bit
decode_eof:
cmp byte ptr wflag,FALSE ; see if write flag off
je d_eof_x ; if so, just exit
call flush_o ; else, flush output buffer
mov SI,offset done_msg ; and tell them we're done
call display
d_eof_x:
jmp exit
decode_x:
mov byte ptr rot_byte,AL
mov byte ptr rot_counter,AH
mov AL,BL
not AL ; else, complement the char
ret
; Print null-terminated string pointed to by SI
;
display:
lodsb ; get a character
or AL,AL ; machine zero?
jz display_x ; yes, exit
call putchar ; print it
jmp short display ; do another
display_x:
ret
; display menu
;
display_menu:
call CRLF
push BX
push CX
push DX
mov AH,40h
mov BX,1
mov CX,menu_len
mov DX,offset menu
int dos
pop DX
pop CX
pop BX
ret
back_step:
inc word ptr entries_todo ; adjust variables for no change
inc word ptr entries_left ; CX loop control
dec word ptr in_use
sub word ptr entry_ptr,entry_len
ret
; process the entry pointed to by BX
;
doentry:
mov DI,BX ; for easier processing
mov word ptr entry_ptr,BX ; save caller's pointer
lea SI,[DI+fname] ; point to the name
call pfname ; print it
mov BX,[DI+count] ; get the value
add BX,0111b ; bump to next 1k boundary
shr BX,1
shr BX,1
shr BX,1 ; convert to k
print_size:
call bin_2_dec ; convert & display file size
mov SI,offset k_msg ; write 'k >' to console
call display
call get_next
call CRLF
mov BX,word ptr entry_ptr ; restore caller's pointer
ret
; exit a menu command and return to main control loop
; also functions as ctl-c interrupt handler
exit:
mov DX,offset int_disable ; disable CTL-C interrupt
call int_set
cmp byte ptr wflag,FALSE
je exit_1
mov BX,word ptr out_handle ; output file handle
mov AH,clostrm ; close output file stream
int dos
mov byte ptr wflag,FALSE
exit_1:
mov AX,flush_kb*256 ; make sure no CTL-C in buffer
int dos
mov AL,'?'
mov SP,word ptr sav_sp ; restore the stack pointer
dec SP
dec SP
ret
int_disable:
iret ; no nothing but return
; set the ctl-C interrupt vector, expects address in DX
;
int_set:
mov AX,setiv*256+23h ; AH=setiv, AL=ctl-C int #
push DS ; save program data segment
push CS ; put code segment into
pop DS ; DS for interrupt handler
int dos
pop DS ; restore our data segment
ret
; flush output buffer
;
flush_o:
push AX
push CX
mov AH,wrtstrm
mov BX,word ptr out_handle
mov CX,word ptr obuf_bytes
mov DX,offset obuf
int dos
jnc flush_o1
jmp write_error
flush_o1:
cmp CX,AX
pop CX
pop AX
je flush_o2
jmp disk_full
flush_o2:
call init_obuf
dec word ptr obuf_ctr
ret
; input a char, convert to uppercase, then display it
;
getchar:
call getch ; console input & uc conversion
cmp AL,' ' ; no echo if not printable
jb getchar_x
getchar_1:
mov DL,AL
mov AH,conout ; echo input to console
int dos
getchar_x:
ret
; input a char & convert to uppercase w/o echo
;
getch:
mov AH,dir_conin ; use direct console input function
int dos ; wait for input
and AL,7Fh ; strip high bit
cmp AL,'a'-1 ; convert lower case to upper
jna getch_x ; but only if between
cmp AL,'z'+1 ; 'a' and 'z'
jnb getch_x
sub AL,20h ; upper case conversion
getch_x:
ret
; get destination drive, put it in drvout, ret NC if OK
;
get_drv:
call crlf
mov SI,offset drv_req
call display
call getchar
mov byte ptr drv_error,FALSE
cmp AL,cr
jne get_drv_1
mov AL,' '
mov byte ptr drvout,AL
mov byte ptr drvout+1,AL
jmp short get_drv_3
get_drv_1:
cmp AL,'A'-1
jna get_drv_2
cmp AL,'P'
ja get_drv_2
mov byte ptr drvout,AL
mov byte ptr drvout+1,':'
jmp short get_drv_3
get_drv_2:
mov byte ptr drv_error,TRUE
get_drv_3:
ret
; input a command char to determine what to do next
;
get_next:
call getchar
push AX
mov AL,' '
call putchar
call putchar
pop AX
mov word ptr sav_sp,SP ; save the stack pointer
jmp cmd_int ; go interpret command
; initialize output buffer
;
init_obuf:
mov word ptr obuf_ctr,obuf_size
mov word ptr obuf_bytes,0
mov word ptr obuf_ptr,offset obuf
ret
; make output file on the requested drive
mak_out:
mov DX,offset drvout ; address of outfile z-string
cmp byte ptr drvout,' ' ; if no drive spec
jne mak_out_1
mov DX,offset filout ; then point to file name
mak_out_1:
xor CX,CX ; no file attribute specified
mov AH,makstrm ; make file stream
int dos
mov word ptr out_handle,AX ; save output stream number
jnc mak_out_x
mov SI,offset mak_msg
call display
jmp exit
mak_out_x:
ret
; open input file
;
open_file:
mov AH,setdta
mov DX,offset dta
int dos
xor AL,AL
mov byte ptr FCBCR,AL
mov byte ptr FCBEX,AL
mov byte ptr FCBRC,AL
mov DX,offset FCB
mov AH,srch_fst
int dos
or AL,AL
jnz open_exit
mov SI,offset dta
mov DI,offset fcb
mov CX,37
rep movsb
mov AH,openf
int dos
; copy & parse lbr_name from the file control block
;
mov SI,offset dta ; fcb address is source
mov DI,offset lbr_name ; destination
movsb ; copy drive designation
add byte ptr [DI-1],'A'-1 ; convert to ascii
mov AL,':'
stosb ; colon to destination
mov CX,8
rep movsb ; copy filename
call quash_space
mov AL,'.' ; period to destination
stosb
mov CX,3
rep movsb ; copy file type
xor AL,AL
stosb ; null end marker
open_exit:
ret
; page routine for viewing
page:
cmp AL,lf ; see if char is new line
jne page_x ; if not, exit
mov AH,byte ptr line_count ; else get line counter
inc AH ; increment it
cmp AH,page_len ; see if whole page
jna sto_line ; if not, just put count back
call getch ; input w/o echo to AL
cmp AL,'X'-40h ; see if an exit command
jne page_L ; if not, go to LINE test
call crlf
jmp exit
page_L:
cmp AL,' ' ; see if a line advance command
jne page_P ; if not, assume page advance
mov AX,lf+256*page_len ; else, setup AX to advance one line
jmp short sto_line
page_P:
mov AX,lf ; setup AX to advance a full page
sto_line:
mov byte ptr line_count,AH
page_x:
ret
; Print filename pointed to by SI and precede with line #
; also make a null terminated copy @ filout
pfname:
push DI
push SI
mov BX,word ptr in_use
dec BX
call bin_2_dec
mov AL,'.'
call putchar
mov AL,' '
call putchar
pop SI
mov DI,offset filout ; point to destination of copy
mov CX,8 ; number of chars in name
fnameloop:
lodsb ; AL = *SI++
stosb ; *DI++ = AL
call putchar
loop fnameloop
call quash_space
mov AL,'.'
stosb
call putchar
mov CX,3 ; number of chars in extension
extloop:
lodsb
stosb
call putchar
loop extloop
xor AL,AL
stosb ; null terminate copy
pop DI
ret
; output CR,LF
crlf:
mov AL,CR
call putchar
mov AL,LF ; fall into putchar
; Send character in AL to console
putchar:
mov AH,conout
mov DL,AL
and DL,7Fh ; strip hi-bit (ws files)
int dos
ret
; Step DI backwards up to 8 chars while pointing to spaces
; CX downcounter starts equal to 8 at string begining
quash_space:
inc CX
cmp byte ptr [DI-1],' '
jne not_space
dec DI
cmp CX,8
jb quash_space
not_space:
ret
; Read one byte, refill buffer as needed.
;
read_byte:
dec word ptr buf_counter
jz yes_read
noread:
mov SI,word ptr buf_ptr
lodsb
mov word ptr buf_ptr,SI
ret
yes_read:
push CX
mov CX,word ptr blks_left ; get # of blocks left to read
cmp CX,irec_per_blk ; max size of buffer <= blocks left ?
jbe yes_read_1 ; if so, read em all
mov CX,irec_per_blk ; else, only read a buffer full
yes_read_1:
sub word ptr blks_left,CX ; and reduce count of blocks left
call read_sector
pop CX
cmp AL,1
jnz noread
jmp exit
; read block of sectors - expects sector count in CX
; and Relative Record field in fcb to be preset,
; translates AL=3 to AL=0 & updates buf counter & size
;
read_sector:
push DX
mov AX,offset dta
mov word ptr buf_ptr,AX
mov DX,Offset FCB ; point DX at File Control Block
mov AH,read_blk ; random block read function
int dos
or AL,AL ; filled whole buffer?
jz read_secx ; done
cmp AL,3 ; partial sector read?
jne read_sec2 ; if not, continue
xor AL,AL ; tell caller all well
jmp short read_secx ; done
read_sec2:
cmp AL,1 ; see if end of file
jne read_secx ; if not, pass AL to caller
or CX,CX ; else see if any sectors read
jz read_secx ; if not, pass AL=oef to caller
xor AL,AL ; else, tell caller all well
read_secx:
mov DX,CX ; put # of sectors read in DX
mov CL,7 ; convert DX into count of bytes
shl DX,CL ; in buffer via multiply by 128
mov word ptr buf_counter,DX ; save it
mov word ptr buf_size,DX ; save it
pop DX
ret
; read a word into BX
;
read_word:
call read_byte
mov BL,AL
call read_byte
mov BH,AL
ret
; reload the whole directory
;
reload_dir:
xor AX,AX
mov word ptr fcbrno,AX ; set for first record
mov word ptr fcbrno+2,AX ; set for first record
mov CX,word ptr dbuf_sects ; number of dir sectors to buffer
call read_sector ; read em all
ret
; type plain-text member to the console
;
type_loop:
cmp byte ptr pflag,TRUE ; see if paging flag on
jne type_loop_1 ; if not, skip message
mov SI,offset page_msg ; else, display page control commands
call display
type_loop_1:
call read_byte ; else just get a byte
cmp AL,eof ; end of file?
je type_loopx ; yes, leave
cmp byte ptr pflag,TRUE ; see if paging flag set
jne type_loop_out ; if not,just output char
call page ; else, do page
type_loop_out:
call putchar ; else display it
jmp short type_loop_1 ; and back for more
type_loopx:
jmp exit
; type squeezed member expanding repeat sequences
;
typesq_loop:
call decode ; AL = translated character
cmp AL,090h ; see if repeat character = 90h
jne reg_char ; if not, its a regular one
call decode ; else, see whats next
or AL,AL ; null?
jz intend_90h ; if so, 90h is intended
; else, it's a repeat flag & count
dec AL ; reduce the count
mov CL,AL ; convert count to word in CX
xor CH,CH
mov AL,byte ptr last_char ; restore char to be repeated
rep_char_loop:
call wrtchar ; output character
loop rep_char_loop ; if(CX--) jmp rep_char_loop
jmp short typesq_loop ; go back for more bytes
intend_90h:
mov AL,90h ; else, 90h was intended
jmp short reg_char_1 ; so treat like a regular character
reg_char:
mov byte ptr last_char,AL ; save in case a repeat flag follows
reg_char_1:
call wrtchar ; output it
jmp short typesq_loop ; and go back for more bytes
; write plain-text member to a file
;
write_loop:
call mak_out ; make the output file
write_loop_1:
; write from input buffer
;
mov BX,word ptr out_handle ; output file handle
mov DX,word ptr buf_ptr ; output buffer address
mov CX,word ptr buf_size ; size of whole buffer
sub CX,DX ; less buf_ptr
add CX,offset dta ; plus start = bytes in buffer
mov AH,wrtstrm ; write to file stream
int dos
jc write_error ; never happens if trapped by dos
cmp CX,AX ; make sure all bytes were written
jnz disk_full
; refill the buffer
;
mov CX,word ptr blks_left ; get # of blocks left to read
or CX,CX
jz closeout
cmp CX,irec_per_blk ; max size of buffer <= blocks left ?
jbe write_loop_2 ; if so, read em all to refill buffer
mov CX,irec_per_blk ; else, only read a buffer full
write_loop_2:
sub word ptr blks_left,CX ; reduce count of blocks left
call read_sector ; fill input buffer
cmp AL,1 ; exit if eof
jz closeout
or AL,AL
jnz read_error
jmp short write_loop_1 ; and back for more
disk_full:
mov SI,offset full_msg
call display
jmp exit
read_error:
mov SI,offset rd_msg
call display
jmp exit
write_error:
mov SI,offset wrt_msg
call display
closeout:
mov SI,offset done_msg
call display
jmp exit
; Write character in AL to output file stream
; if the write flag is set, else transfer to
; console output function unless eof read
wrtchar:
cmp byte ptr wflag,TRUE
je wrtflag_on
cmp AL,eof ; end of file?
jne go_putchar
jmp exit
wrtflag_on:
dec word ptr obuf_ctr
jz wrtchar_2
wrtchar_1:
mov DI,word ptr obuf_ptr
stosb
mov word ptr obuf_ptr,DI
inc word ptr obuf_bytes
ret
wrtchar_2:
call flush_o
jmp short wrtchar_1
go_putchar:
cmp byte ptr pflag,TRUE
jne go_putchar_1
call page
go_putchar_1:
jmp putchar
code ENDS ; end of code segment
; STACK LOCATION
; --------------
a_stack SEGMENT word STACK
; dummy declaration to satisfy assembler & linker
a_stack ENDS
END lsweep