Category : Assembly Language Source Code
Archive   : ADIR103.ZIP
Filename : ADIR103.ASM

 
Output of file : ADIR103.ASM contained in archive : ADIR103.ZIP
; MSDOS ADIR
; by Howard Vigorita, NYACC, CP/M SIG
; upload comments &/or updates to (718) 539 - 3338
;
release equ 1
version equ 03
date macro
db '2/16/86'
endm
;
; ADIR is a MSDOS generic program to display a directory
; of ARC archive members. It requires MSDOS 2.x or higher
; and a 64K or greater system.
;
; This source code is released into the public domain on the
; condition that it is not distributed or incorporated into any
; other software for which the source code and credits are not
; supplied. Any variance from these conditions may only be
; obtained on written consent of the author or the New York
; Amateur Computer Club.
;
; USAGE
; -----
;
; Execute program as follows from the default drive with ARC
; also on that drive where afn = ambiguous file name of member(s):
;
; ADIR FileName[.ARC] [afn]
;
; To see all members when ADIR is on A: & FILE.ARC is on B:
;
; A>ADIR B:FILE
;
; B>A:ADIR FILE *.*
;
; ADIR will also accept a wildcard archive specification, in which
; case it will display the directories of all the ARC's it matches.
;
; REGENERATION
; ------------
;
; To reassemble this program with MASM 1.0 or 2.0:
; MASM ADIR ;
; LINK ADIR ;
; With MASM 3.0, use the "/A" option to link segments in alpha order.
;
;
; HISTORY
; -------
;
; ver 1.03 Cosmetic changes to display presentation.
;
; ver 1.02 Multiple ARC processing via wildcards added.
;
; ver 1.01 Misalignment detection & version 1 headers supported.
;
; ver 1.00 ADIR created for MSDOS assembly by MASM.
;
;-----------------------------------------------------------------------

; equates
; -------

; conditional assembly & control equates
;
true equ 0FFh
false equ 0

; dos equates
;
conout equ 02 ; write console character
setdma equ 26 ; set disk transfer address
dos equ 33 ; MSDOS entry point
setiv equ 25h ; set interrupt vector
parsef equ 29h ; parse file name
xctl_c equ 33h ; extend ctl-c checking
opnstrm equ 3Dh ; open file stream
clostrm equ 3Eh ; close file stream
rdstrm equ 3Fh ; read from stream
seekstrm equ 42h ; seek on stream
trmproc equ 4Ch ; terminate process
srchf equ 4Eh ; search first
srchn equ 4Fh ; search next

; ARC directory entry equates and offsets
;
entrylen equ 29
arc_mark equ 26
mark equ 0
arc_ver equ 1
ename equ 2
msize equ 15
mlen equ 25

; Ascii equates
;
TAB equ 09H
CR equ 0DH
LF equ 0AH
SPACE equ ' '
zero equ '0'
NUM_ACROSS equ 3 ; three across on a line


; 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 PARA MEMORY

signon db cr,lf,'MSDOS ADIR version '
db release + zero, '.'
db (version/10) + zero
db (version MOD 10) + zero,', '
date
db ', Howard Vigorita',CR,LF,0

joker db '???????????' ; = '*.*'
use_msg db TAB,TAB,'USAGE: ADIR ArcName[.ARC] [afn]',cr,lf,lf
db TAB,TAB,'afn = ambiguous member file name',cr,lf
db TAB,TAB,'ArcName may also be ambiguous',0
arc_ext db 'ARC',0
name_msg db cr,lf,TAB,TAB,TAB,' Archive file: ',0
opnmsg db 'Archive file not found',0
eofmsg db 'Premature End of File',0
not_arc db "ARC is out of alignment or it's not an ARC",0
separator db ' | ',0

zstring db 13 dup (?)
arc_handle dw ?
sf_flag db ? ; search first flag

; dynamic data area
;
dda equ $
entries_to_do equ dda+2 ; dw (?) how many so far
entries_printed equ entries_to_do+2 ; db (?) on a line
SEARCH_STR equ entries_printed+1 ; 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 (?)

fcb_ename equ fcbrno+4 ; db 37 dup (?) entry name fcb
decbuf equ fcb_ename+37 ;db 6 dup (?) dec output scratch buffer

dfa equ decbuf+6 ; 44 dup (?) directory feedback area

dta equ dfa+44 ; db 80h dup (?) disk transfer area


data ENDS


; PROGRAM STARTS HERE
; -------------------
;
code SEGMENT para 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
;
adir:
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

begin:

; Print signon message
;
mov SI,offset signon
call display
call crlf

; 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 use_msg
call display
call crlf
jmp all_done

; check for extension, add ARC if none
;
cmdok:
mov SI,offset arc_ext
mov DI,offset FCBFT
mov CX,3
rep movsb

; check for search request, use Joker (*.*) if none
;
extok:
mov SI,offset FCB2+1 ; assume fcb2
mov DI,offset SEARCH_STR ; destination
mov CX,11 ; bytes to move
cmp byte ptr [SI], SPACE ; anything there?
jne gotaname ; yes, move it
mov SI,offset joker ; no, move the joker
gotaname:
rep movsb ; move it
mov byte ptr sf_flag,true ; set the search first flag

; try to open & process the arc
;
proc_arc:
call mfname
jnc openok

; No file, send message and leave
;
mov SI,offset opnmsg
call display
jmp all_done

; file found and opened, get header information
;
openok:
; initialize variables
mov byte ptr entries_printed,num_across
call crlf

call read_header ; read first header entry
jnc readok ; if carry set, we're at eof

; premature end of file, send message, and exit
;
mov SI,offset eofmsg
call display
jmp all_done
readok:
mov BX,offset dta ; point to first entry

; Read and analyze entries until eof
;
main:
cmp byte ptr [BX+arc_ver],0 ; see if end of arc mark
je skipit
cmp byte ptr [BX+mark],arc_mark ; make sure we have an arc
je compare ; if so, continue
mov SI, offset not_arc
call display
jmp all_done

; does it match?
compare:
mov SI,offset SEARCH_STR ; source
mov CX,11 ; number of bytes to compare
cmploop:
repe cmpsb
jcxz itmatches
cmp byte ptr [SI-1],'?'
jne cmpexit
jmp short cmploop
itmatches:
xor AL,AL ; set the zero flag
cmpexit:
jnz skipit ; nope, skip it
call do_entry ; else display info
skipit:
call read_nxt_header ; point to next entry
jnc main ; and continue processing
call crlf
call mfname ; else, see if all arc'd out
jnc openok ; if not, do em too

; back to DOS
;
all_done:
mov AH,trmproc
int dos

; SUBROUTINES

; process the entry pointed to by BX
;
do_entry:
push BX
mov SI,offset fcb_ename+1 ; move filename pointer
call pfname ; print it
lea DI,[BX+msize] ; point to member length
push DI ; save for possible ver 1 header
call print_size
mov AL,' '
call putchar
mov AL,'/'
call putchar
pop DI ; restore ptr to member length
cmp byte ptr dta+arc_ver,1 ; see if a version 1 header
je do_ver_1 ; if so, leave DI unchanged
lea DI,[BX+mlen] ; else point to expanded size
do_ver_1:
call print_size
dec byte ptr entries_printed
jnz do_separator
call crlf
mov byte ptr entries_printed,NUM_ACROSS
jmp short no_sep
do_separator:
mov SI,offset separator
call display
no_sep:
pop BX ; restore caller's pointer
ret

print_size:
push BX
mov BX,word ptr [DI] ; get the file size low word
mov DX,word ptr [DI+2] ; get the file size high word
add BX,1023 ; bump to next 1k boundary
adc DX,0
mov CL,10
shr BX,CL ; merge low & high words
mov CL,6
shl DX,CL
add BX,DX ; K size good to 64 meg
call bin_2_dec ; print it
mov AL,'k'
call putchar
pop BX
ret

putchar:
mov AH,conout
mov DL,AL
int dos
ret

crlf:
mov AL,CR
call putchar
mov AL,LF
call putchar
ret

mfname:
mov AH,setdma
mov DX, offset dfa ; point to directory feedback area
int dos

cmp byte ptr sf_flag,true ; see if should do first first
jne search_next ; if not, search next

mov byte ptr sf_flag,false ; search next, next time
mov SI,offset fcb ; source is file control block
mov DI,offset zstring ; destination is path zstring
call unparse_fn ; unparse from fcb to zstring

mov AH,srchf ; search first function
mov DX,offset zstring
int dos
jc mfname_x ; exit on error

jmp short parse_fname ; else, parse the found name

search_next:
mov AH,srchn
int dos
jc mfname_x ; exit on error

parse_fname:
mov AH,parsef ; parse fname into fcb for display
mov AL,0010b ; ignore leading separators
mov SI,offset dfa+30 ; fname in dir feedback area
mov DI,offset fcb ; parse to file control block
int dos

mov SI,offset fcb
mov DI,offset zstring
call unparse_fn ; unparse from fcb to zstring
clc
mfname_x:
jnc open_arc
ret

unparse_fn:
lodsb ; get requested disk byte
or AL,AL ; test for 0
jz cpy_fname ; if so, skip drive spec
add AL,'A'-1 ; else, convert drive to ascii
stosb ; write to path zstring
mov AL,':'
stosb ; also write the ':'
cpy_fname:
mov CX,8 ; 8 chars in fname
rep movsb ; copy em
mov AL,'.'
stosb
mov CX,3 ; 3 chars in ftype
rep movsb
xor AX,AX
stosb ; null terminate it
ret

open_arc:
mov SI,offset name_msg ; first tell em which arc
call display
mov SI,offset zstring
call display
call crlf

mov AH,setdma
mov DX,offset dta ; set dma to disk transfer area
int dos

mov AH,opnstrm ; open file stream
xor AL,AL ; read only mode
mov DX,offset zstring ; file to open
int dos
mov word ptr arc_handle,AX ; save the arc file handle
ret

; prefix to read_header which seeks to the next one first
;
read_nxt_header:
push BX
lea DI,[BX+msize]
mov DX,word ptr [DI] ; get low size word
mov CX,word ptr [DI+2] ; and high size word
mov BX,word ptr arc_handle
mov AH,seekstrm ; seek fwd from current position
mov AL,1
int dos
pop BX

; read header from file stream, returns carry on error or eof
; else, clears carry & returns DI pointing to parsed entry name
read_header:
push BX
mov BX,word ptr arc_handle
mov CX,entrylen
mov DX,offset dta
mov AH,rdstrm
int dos
pop BX
jc read_header_x
cmp AX,CX
je align_ver_1
stc
jmp short read_header_x

; adjust stream pointer for 4 bytes shorter version 1 header
;
align_ver_1:
cmp byte ptr dta+arc_ver,1 ; see if a version 1 header
jne parse_ename ; if not, no adjustment needed
mov CX,-4 ; else set up CX:DX for a
mov DX,0FFFFh ; negative seek
mov AX,seekstrm*256+1 ; seek from current position
int dos

; parse packed entry name from header into an fcb
; for easier display and wildcard processing
parse_ename:
mov AH,parsef ; parse file name
xor AL,AL ; normal parse
lea SI,[BX+ename] ; point to entry name
mov DI,offset fcb_ename ; destination fcb
int dos
inc DI ; point past drive specifier
clc
read_header_x:
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 ; get another
display_x:
ret

; Print filename pointed to by SI
;
pfname:
push CX
mov CX,8 ; number of chars in name
fnameloop:
lodsb
call putchar
loop fnameloop
mov AL,'.'
call putchar
mov CX,3
ftype_loop:
lodsb
call putchar
loop ftype_loop
pop CX
ret

; convert binary word to ascii decimal & output it
; uses the 8086 divide instruction
; parameters passed in registres as follows:
; BX binary word to be converted
bin_2_dec:

push DI
mov DI,offset decbuf ; address of output buffer
mov CX,4 ; 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

pop DI
ret


code ENDS ; end of code segment



; STACK LOCATION
; --------------
;
a_stack SEGMENT PARA STACK

; dummy declaration to satisfy assembler & linker

a_stack ENDS


END adir


  3 Responses to “Category : Assembly Language Source Code
Archive   : ADIR103.ZIP
Filename : ADIR103.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/