blumzi@TAURUS.BITNET (01/30/90)
Hi,
Enclosed is the TASM source code for a UNIX like ls
command. This code has been presented by a student
as a project, and a suspicion has been raised that
the code is copied from one of the many existing
public domain / shareware or even a commercial ls (MKS ?).
We would like to clear or verify this suspicion
by your response. Please check to see if you recognize
the following code. Remember that superficial changes
are always possible: Different commenting style,
different naming conventions. It may be even the case
that the code was written in a different language,
and a compiler has been used to generate the assembly.
The label naming convention suggests this idea, but
the direct reference to the hardware cannot be explained
by this method.
Since you have read so far, it is only fair that the reasons
for the suspicion will be detailed:
1) The student suggested the idea for having
a project instead of all the programming
exercises in the course.
2) The project topic was suggested by the student.
3) The student claimed that he is fluent in 8088
assembly, and that he had "15 years of experience"
in the field. However, for various reasons he was
not able to finish the course in 1988, and
he had to repeat the course in 1989. The course
is based mostly on (almost trivial) 8086 assembly language
programming tasks, no final exams.
4) The professor of the course is not in the "heart
of the matter" in PC related general knowledge
5) The project was finished very very quickly - perhaps
too quick for that order of magnitude of lines of
good assembly code. The code looks as one of
"not so poor" UNIX ls imitations.
The student knows that an investigation is done about his project,
but we do not specify his name on purpose. Please do not make
any attemts to find the name of the student. This posting is
(very) indirect in purpose. No need for more than needed publicity
at this stage. It can very well be that every thing is proper.
Enclosed below is the manual page for the ls command. The manual
is very clearly a modified UNIX ls man page. It is known
(from other investigation) that this is the case indeed, but
of course - this doesn't proof anuthing.
After the manual page - you can find the source code. Parts of the
code are deleted because of two reasons.
1) If someone will be able to come up with the missing
parts - this will be the best proof.
2) If the code was copied from somewhere - it should
not become public domain after the posting:
All deletions are clearly marked in the code.
Many thanks
======================= This is the man page ==========================
NAME
ls - list and generate statisitcs for files
SYNTAX
ls [_o_p_t_i_o_n_s] _n_a_m_e...
DESCRIPTION
For each directory argument, _l_s lists the contents of the
directory. For each file argument, _l_s repeats the file name
and gives any other information you request with the options
available. By default, the list is sorted alphabetically.
When no argument is given, the current directory is listed.
When several arguments are given, files are listed first,
followed by directories and the files within each directory.
Options are listed below.
OPTIONS
-1 Displays one entry per line.
-a Displays all entries including Hidden/Sys/Volume and those
begining with a period (.).
-A Displays all entries including Hidden/Sys/Volume but not
those begining with a period.
-c Sorts entries by date-time. Default is by name.
-d Displays names of directories only, not contents. Use
this option with -l to get the status of a directory.
-F Marks directories with trailing slash (/), and
executable files with a trailing asterisk (*).
-f Displays names in the order they exist in directory.
all entries are listed. This option overrides the
-l, -t, -s, and -r options.
-l Lists the attributes, size in bytes, and date
and time of last modification for each file.
The attribute field consists of 6 characters. Dots
indicate that the attribute is off, A letter indicates on :
R if the entry is read-only
H if the entry is hidden
S if the entry is a system file
V if the entry is a volume name
D if the entry is a directory
A if the archive bit is on
-R Recursively lists all subdirectories.
-r Sorts entries in reverse alphabetic or time order.
-s Displays the size in bytes of each file. This is the
first item listed in each entry.
-t Sorts by time modified (latest first) instead of by name.
-u Uses the time of last access instead of last modification
for sorting (with the -t option) or printing (with the -l
option).
RESTRICTIONS
The output device is assumed to be 80 columns wide.
======================= This is the assembly code ========================
; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
; $ $
; $ ls $
; $ $
; $ implement UNIX 'ls' on MS-DOS, for a complete definition $
; $ and instructions see manual document. $
; $ compatiable with DOS 3.20 . $
; $ $
; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
title ls
; *********************** definitions *******************************
;
; *********** constants definitions *********
; general constants definitions
;
TAB EQU 09h
LF EQU 0ah
CR EQU 0dh
;
ATTD_MASK EQU 10h ; mask for dir bit in file attr
ATTALL_MASK EQU 3fh ; mask for all bits in attr
;
tbl_size EQU 128 ; size of work tables, limits # of dirent/dir
en_size EQU 30h ; length of each entry, > max(entsize,fnlen)
args_num EQU 10h ; max number of command line arguments (ex sw)
; offsets of fields in a parsed dir ent
ofs_name EQU 00h
ofs_size EQU 20h
ofs_attr EQU 28h ; (len = 1)
ofs_date EQU 29h ; (len = 2+1+1)
ofs_time EQU 2dh ; (len = 1+1)
ofs_attd EQU 10h ; attr & ATTD_MASK (len = 1)
ofs_nadd EQU 11h ; addrs of original name (len = 2)
ofs_mark EQU 1fh ; extra mark char for '-F' option (len = 1)
; lengths of fields in a parsed dir ent
len_name EQU 14 ; 8+1+3+1+1 (name+dot+ext+mark+space)
len_size EQU 8 ; > 32MB (DOS max)
;
; ************* macro definitions ***********
;
movss MACRO sstr,dstr,len ; copy string
cld
lea si,sstr
lea di,dstr
mov cx,len
rep movsb
ENDM
dosfunc MACRO funcnum ; do a DOS function call
mov ah,funcnum
int 21h
ENDM
dsply MACRO strng ; dsply a string ending with a '$'
mov dx,offset strng
dosfunc 09h
ENDM
p1space MACRO ; dsply one space
mov dl,' '
dosfunc 02h
ENDM
ptab MACRO ; dsply one tab
mov dl,TAB
dosfunc 02h
ENDM
;
; **************************** stack segment ************************
;
sseg SEGMENT STACK
DB 100 dup(?)
sseg ENDS
;
; **************************** data segment *************************
;
dseg SEGMENT
; ************** variables definitions ******
;
; character strings for display and formating templates
;
star2 DB "\*.*",0
dot1 DB ".",0
dotexe DB ".EXE"
dotcom DB ".COM"
errmsg DB "ls: $"
crlf DB CR,LF,"$"
dots2 DB ":",CR,LF,"$"
ftotal DB "Total $"
attrbs DB "RHSVDA"
dplate DB "00-00-0000$"
tplate DB "00:00$"
nplate DB " $"
; ls flags (0=T,other=F)
flgall DB 'a'
flgtmc DB 'c'
flgndr DB 'd'
flgpln DB 'f'
flglng DB 'l'
flgrev DB 'r'
flgsiz DB 's'
flgtmt DB 't'
flgtmu DB 'u'
flg1pl DB '1'
flgaex DB 'A'
flgmkf DB 'F'
flgrec DB 'R'
flgxxx DB 0ffh
; variables
my_dta DB 30h dup(0) ; dta to accept output of dosfun 4E
;
neword DW 1 ; flag for command line decoding
numflg DW flgxxx - flgall ; number of flags installed
clen DW 0 ; length of command
cmndln DB 80 dup('$') ; internal buffer for command line
; 'sort' procedure arguments and internal vars
srtfld DW 0 ; arg- offset of key field (rel bx)
srtlen DW 0 ; arg- length of key field
srtst1 DW 0 ; var- address of one string
srtst2 DW 0 ; var- address of second string
srtyet DW 0 ; arg- number of recs to sort
srtdrc DW 0 ; arg- direction of sort
;
dtitle DW 0 ; dsply title flg (1=T,other=F)
phase DW 0 ; phase indicator (1,2)
; 'showall' proc internal vars
colms DW 0 ; # of colums to be in formated output
lines DW 0 ; # of lines ...
colc DW 0 ; colums counter (down)
linc DW 0 ; lines counter (down)
;
ecntr DW 0 ; number of relevant enteris in ent tbl
ncntr DW 0 ; number of relevant entries in names tbl
numdirs DW 0 ; number of subdir ent in ent tbl
curnam DW 0 ; pointer to name being refered
entaddr DW 0 ; pointer to entry now being refered
namaddr DW 0 ; pointer to names being expanded
namelen DW 0 ; length of name being expanded
; buffers
zero_en DB en_size dup(0) ; used to reset totl_ent
totl_en DB en_size dup(0) ; size field used to count total
ffname DB 80 dup(0) ; buffer for name to be expanded
entries DB en_size * tbl_size dup(?) ; tbl for entries found
names DB en_size * tbl_size dup(?) ; bfr for dir names to expnd
args DB en_size * args_num dup(?) ; bfr for cmmndln args
; error msgs tbl
e_01 DB "Invalid function code$"
e_02 DB "File not found$"
e_03 DB "Path not found$"
e_08 DB "Insufficient memory$"
e_18 DB "No more files$"
e_87 DB "Invalid parameter$"
;
e_unkn DB "Unknown error$"
; error codes tbl
err_tbl DW 1 ,e_01
DW 2 ,e_02
DW 3 ,e_03
DW 8 ,e_08
DW 18 ,e_18
DW 87 ,e_87
DW 0 ,e_unkn
dseg ENDS
;
; ******************************* code segment **********************
;
cseg SEGMENT
ASSUME cs:cseg,ds:dseg,ss:sseg
;
; ############ entry point ##################
;
; **************** initialization ***********
start: mov ax,dseg
mov ds,ax
mov phase,0
start1: ; **** copy cmnd line from PSP to data seg *******
mov ch,0
mov cl,es:80h ; get length of cmnd line
mov bx,cx ; save length
mov clen,cx
mov si,cx
cmp bx,0
je start2 ; no cmnd line
cp1: mov al,es:80h[si] ; copy cmnd line
mov ds:cmndln[si] - 1,al ; to internal buffer
dec si
loopnz cp1
; **************** init ES ******************
start2: push ds ; set ES
pop es ; to eq DS
mov byte ptr ds:cmndln[bx],0
getsw1: ; ******** get option switchs ***************
lea bx,cmndln[0]
getsw2:
mov al,[bx] ; get char
cmp al,0 ; EOL ??
je getsw9 ; Y - exit
cmp al,' ' ; space ??
jne getsw3
mov neword,1 ; Y - deli
jmp getsw6 ; adv to next chr
getsw3: cmp neword,0 ; not spc, is first ??
je getsw4 ; middle of word, go process
cmp al,'/' ; first, is sw ??
je getsw5 ; Y - skip slash
cmp al,'-' ; accept '-' as well as '/'
je getsw5
jmp getsw9 ; N - param found - exit
getsw4: mov cx,numflg ; scan flag tbl
lea si,flgall ; from first
gts4: mov dl,[si]
cmp dl,al
je gts44 ; until found
inc si
loop gts4
gts44: mov byte ptr [si],0 ; mark flg with a zero
getsw5: mov neword,0
getsw6: inc bx
dec clen ; remaining string length
jmp getsw2
getsw9: ; ************ get arguments *******************
lea si,dot1 ; default parm
mov cx,2 ; size of it
cmp al,0 ; no parm ??
je cont2
gs99: mov si,bx ; copy user parm
cont2: ; copy args into args tbl
lea bx,args[0]
mov ncntr,1
cont5: mov di,bx
mov cx,0 ; count arg len
cont4:
mov al,[si] ; get chr from argv
inc si
cmp al,' ' ; is seperator ??
jne cont3 ; no
mov al,0
mov [di],al
add bx,en_size
inc ncntr
cmp ncntr,args_num ; too many args ??
ja error0 ; yes
jmp cont5
cont3: mov [di],al
cmp al,0 ; is end-of-line ??
je dep0 ; yes
inc di ; adv addr
inc cx ; adv cntr
cmp cx,en_size ; arg too long ??
jae error0 ; yes - abort
jmp cont4 ; no - do next char
dep0: ; *********** set options dependancies *************
cmp flgpln,0
jne dep2
dep1: mov flgall,0 ; ON
mov flglng,0ffh ; OFF
mov flgsiz,0ffh
mov flgtmt,0ffh
dep2: cmp flglng,0
jne dep3
mov flg1pl,0
mov flgsiz,0
dep3: cmp flgall,0
jne dep4
mov flgaex,0
dep4: cmp flgtmc,0
jne dep5
mov flgtmt,0
dep5: cmp flgtmu,0
jne dep6
mov flgtmt,0
dep6:
; *********** set current dta addr **********
set_dta:mov dx,offset my_dta
dosfunc 1ah
; *******************************************************************
sof0: jmp phase1
error0:
mov ax,87 ; Invalid parameter
jmp errorh
;
; ************ end of init *************************
;
; ************** phase 1 ***************************
;
; For each argument, find all the dirctory entries that matches it
; and store them in ent tbl. If no match was found exit with a
; error message. Sort entries using specified or default criteria
; with files ent before subdirs ent. Unless flag 'd' is on, push
; subdir ent into names stack. Show remainig entries.
;
phase1: mov phase,1
start3: ; *************** expand args ***************
mov ecntr,0
mov numdirs,0 ; no sub-dirs found yet
lea bx,entries[0] ; start of table
mov entaddr,bx
lea ax,args ; names in args tbl
mov namaddr,ax
start4: call findall ; expand argument to entries tbl
jnc start6
cmp ax,2 ; File not found
je start6
cmp ax,3 ; Path not found
je start6
cmp ax,18 ; No more files
je start6
jmp error1
start6: dec ncntr
jz start5 ; no more names
mov ax,namaddr
add ax,en_size
mov namaddr,ax
jmp start4 ; go do next name
start5:
mov ax,2 ; no files found !!
cmp ecntr,0
jne p100
jmp error1
; ***** sort ent tbl, files below subdirs ***
p100: mov srtfld,ofs_attd ; sort by file/dir
mov srtlen,1 ; 1 byte
mov srtdrc,1 ; files first
mov ax,ecntr ; sort all ent
mov srtyet,ax ; sort all ent
lea bx,entries[0] ; from first
call far ptr sort
p110: ; sort files at lower ent tbl
mov ax,ecntr
sub ax,numdirs ; calc num of files
jz p130 ; no files
mov srtyet,ax
mov srtfld,ofs_name ; defaul is sort by fname
mov srtlen,len_name
cmp flgtmt,0
jne p120
p118: mov srtfld,ofs_date ; sort by date+time
mov srtlen,6
p120: lea bx,entries[0]
mov al,flgrev
cbw
mov srtdrc,ax
call far ptr sort
p130: ; sort subdirs at upper ent tbl
mov ax,numdirs
cmp ax,0
je p145 ; no subdirs to sort
mov srtyet,ax
mov srtfld,ofs_name ; defaul is sort by fname
mov srtlen,len_name
cmp flgtmc,0
je p138
cmp flgtmt,0
jne p140
p138: mov srtfld,ofs_date ; sort by date+time
mov srtlen,6
p140: lea bx,entries[0]
mov ax,ecntr
sub ax,numdirs
mov dx,en_size
mul dx ; dx destroyed
add bx,ax ; bx points to first dir ent
mov al,flgrev
cbw
mov srtdrc,ax
call far ptr sort
p145: ; ************ process subdir names *********
cmp flgndr,0 ; no dir exp ??
je p150 ; then go show all now
cmp numdirs,0
je p150 ; no dirs
mov ax,ecntr
mov dtitle,ax
lea bx,entries[0]
mov ax,ecntr
sub ax,1
mov dx,en_size
mul dx ; dx destroyed
add bx,ax ; bx points to last dir ent
lea dx,names[0]
mov curnam,dx
pcp1: ; mov dir names to names, rev order
mov di,curnam
mov si,[bx+ofs_nadd] ; restore addr of original arg
pcp2: mov dx,di ; save addr of last ok chr + 1
pcp3: mov al,byte ptr [si] ; get chr from arg
cmp al,0 ; end-of-name ??
je pcp4 ; yes
mov byte ptr [di],al ; no - put chr
inc si
inc di
cmp al,'\' ; is path sep ??
je pcp2 ; yes - remember loc
cmp al,':' ; is path sep ??
je pcp2 ; yes - remember loc
jmp pcp3
pcp4: mov di,dx ; restore sep + 1 addr
mov si,bx ; addr of dir ent name
add si,ofs_name
mov cx,len_name
rep movsb
inc ncntr
dec ecntr
dec numdirs
jz p150 ; no more dir names
cmp ncntr,tbl_size ; too many names ??
ja error1 ; yes
sub bx,en_size
add curnam,en_size
jmp pcp1
p150: ; ********** show remaining ent tbl *********
lea bx,entries[0] ; start of table
mov entaddr,bx
call showall
; ******************************************************************
ok1: jmp phase2
sof1: jmp sof
error1: jmp errorh
;
; ********************** end of phase 1 *****************************
;
;************************* phase 2 **********************************
;
; Until names stack is empty, remove first name and process it:
; find all dir ent in that subdir. Unless flag 'f' is on
; sort ent tbl. Show entries according to formating flags,
; If flag 'R' is on, push names of subdirs found to stack.
;
phase2: mov phase,2
p2:
cmp ncntr,0
jne p20
jmp sof2 ; no more names to expand
p20:
cmp ncntr,tbl_size ; too many names ??
jbe p200 ; no
jmp error2 ; yes
p200: ; ********** prepare search string **********
lea di,ffname
mov si,curnam ; expand current dir name
mov cx,en_size
mov namelen,0 ; count name len
mov dx,0 ; count spaces
p208: lodsb ; get chr
cmp al,' '
je p205
cmp dx,0
jne p206
inc namelen ; remember name len
jmp p206
p205: inc dx
p206: stosb
loop p208
p207:
lea si,star2 ; concat '\*.*',0 to name
lea di,ffname
add di,namelen
mov cx,5
rep movsb
; *************** expand subdir *************
mov ecntr,0 ; prepare for findall
movss zero_en,totl_en,en_size
lea bx,entries[0] ; start of table
mov entaddr,bx
lea ax,ffname
mov namaddr,ax
mov numdirs,0
p210: call findall ; expand argument to entries tbl
jnc p220 ; ignore expected errors
cmp ax,2 ; File not found
je p220
cmp ax,3 ; Path not found
je p220
cmp ax,18 ; No more files
je p220
jmp error2 ; unexpected error
p220: ; **************** sort ent *****************
cmp flgpln,0
je p250 ; plain dsply - do not sort
mov srtfld,ofs_name ; defaul is sort by fname
mov srtlen,len_name
cmp flgtmc,0
je sort2
cmp flgtmt,0
jne sort3
sort2: mov srtfld,ofs_date ; sort by date+time
mov srtlen,6
sort3: lea bx,entries[0]
mov al,flgrev
cbw
mov srtdrc,ax
mov dx,ecntr
cmp dx,0
je p250 ; no files to sort
mov srtyet,dx
call far ptr sort
p250: ; *********** show entries found ************
dsply crlf
cmp dtitle,1
je p260 ; only one subdir
mov bx,curnam
add bx,namelen
mov byte ptr [bx],'$' ; mark end of name for printing
mov dx,curnam
dosfunc 09h ; show dir-name
dsply dots2
p260: cmp flgsiz,0
jne p270
call ptotal
p270: lea bx,entries[0] ; start of table
mov entaddr,bx
call showall
sub curnam,en_size ; adjust after showall
dec ncntr
mov dtitle,2 ; from now on title
precd: ; ****** if recursion push subdir names *****
cmp flgrec,0 ; sub dir recursion ??
jne ok2
mov ax,en_size
mul ecntr ; dx destroyed
mov bx,ax
add bx,entaddr ; addr of last+1 ent
p280: cmp numdirs,0
je ok2
sub bx,en_size
mov al,[bx+ofs_attd] ; file/dir byte
cmp al,0
je p280 ; file - go next
dec numdirs ; dir ent found
mov al,[bx+ofs_name]
cmp al,'.' ; '.' or '..'
je p280
add curnam,en_size
; copy name of current dir
lea si,ffname
mov di,curnam
mov cx,namelen
rep movsb
mov byte ptr [di],'\' ; concat '\'
inc di
mov si,bx ; concat subdir name
add si,ofs_name
mov cx,len_name
rep movsb
inc ncntr
jmp p280
; ******************************************************************
ok2: jmp p2
sof2: jmp sof
error2: jmp errorh
;
; ********************* end of phase 2 *****************************
;
; ********************* error routine ******************************
;
errorh:
lea bx,err_tbl
errh1: mov cx,[bx] ; error code in cx
cmp cx,0 ; no more codes ??
je errhp ; print unknown
cmp cx,ax ; this code ??
je errhp ; print it
add bx,4 ; next entry in err_tbl
jmp errh1
errhp: add bx,2 ; point to addr of msg str
dsply crlf
dsply errmsg ; dsply err prompt
mov dx,[bx] ; point to body of msg
dosfunc 09h ; print it
dsply crlf
;
; ******************************************************************
;
; ############### exit point ##################
;
sof: dosfunc 4ch
; *********** end of main *******************************************
;
; ********************** procedures *********************************
;
; NOTES on procedures documentation headers :
; * Registers listed undel DESTROYed include only registers
; destroyed directly by the procedure itself or the macros
; it uses, but NOT registers destroyed by any other
; procedure that it may call.
; * Definitions of global variables listed under PARaMeterS,
; USES, or VARiableS can be found on the original lines
; where those variables are declared.
; * 'FLAGS' mean a subset of the flag variables.
; * The notetion 'DOS(x1,x2,...)' under CALLS means that the
; procedure or a macro it uses does (a) system call(s) with
; the functions x1,x2 etc. requested. If xi is a symbol this
; means that the call is being made from a macro named xi,
; in this case refer to the macro definition to see what
; function was called.
findall PROC NEAR ; *******************************************
; find all directory entries matching a given
; filename path which may include wildcards.
;
; destroy : ax,bx,cx,dx,si,di
; prams : namaddr addr of name to expand
; entaddr addr of first entry storage loc
; uses : FLAGS,phase
; vars : None
; effects : ecntr,numdirs,[entaddr]
; calls : DOS(4E,4F,dsply)
; output : ax error code
; CF error flag
get_1: mov dx,namaddr ; addr of name in dx
mov cx,ATTD_MASK ; default is only normal files + dirs
cmp flgaex,0 ; show all files ??
jne get11
or cx,ATTALL_MASK ; yes
get11: dosfunc 4eh
chk1: jnc found1
jmp ferror
found1:
mov bx,entaddr
call parse2
mov al,[bx+ofs_attd]
cmp al,0 ; is ent a subdir ??
je get20 ; no
get15: mov si,namaddr
mov di,bx
add di,ofs_name
mov al,0
cmp phase,1
je get17 ; name is arg
mov al,' ' ; seperator
get17: cmp byte ptr [si],'.' ; is name '.' ??
jne getaa ; no - ok
cmp [si+1],al
jne get19
mov byte ptr my_dta[1eh],'.' ; yes - restore
mov byte ptr my_dta[1eh+1],0
jmp repars
get19: cmp byte ptr [si+1],'.' ; is name '..' ??
jne getaa
cmp [si+2],al
jne getaa
mov byte ptr my_dta[1eh],'.' ; yes - restore
mov byte ptr my_dta[1eh+1],'.'
mov byte ptr my_dta[1eh+2],0
repars: call parse2
getaa:
cmp byte ptr [di],'.' ; is entry '.' or '..' ??
jne getdz ; no
cmp flgall,0
je getdz
cmp phase,2
je chknxt ; ignore '.' and '..' in ph2 unless flgall
getdz:
inc numdirs ; count subdirs
get20:
inc ecntr
cmp ecntr,tbl_size ; too many entrs ??
jb get22 ; no
mov ax,8 ; yes - out of memory
jmp ferror
get22: add bx,en_size
mov entaddr,bx ; store add of next ent
chknxt: dosfunc 4fh
jc ferror
jmp found1
chklst: cmp ax,18 ; no more files
je fok ; other error
ferror: stc
jmp fexit
fok: clc
mov ax,0
fexit:
ret
findall ENDP
showall PROC NEAR ; *******************************************
; show all directory entries stored at ent tbl
; with formating as requeired.
;
; destroy : ax,bx,dx
; prams : entaddr addr of first entry storage loc
; uses : FLAGS,ecntr,crlf
; vars : colms,lines,colc,linc
; effects : None
; calls : psize,pattrb,pdate,ptime,pname2
; output : None
mov colms,1
mov ax,ecntr
cmp ax,0
jne sh20
jmp shexit ; no files
sh20: mov lines,ax
cmp flg1pl,0
je cp22 ; one ent per line
mov colms,5 ; calc num of lines in col format
cmp flgsiz,0
jne sh01
mov colms,3
sh01: mov dx,colms
add ax,colms
sub ax,1
div dl ; result in al
cbw
mov lines,ax
cp22: mov ax,lines
mov linc,ax
cp33: mov ax,colms
mov colc,ax
jmp cp55
cp44: ptab
cp55:
mov ax,lines
mov dx,colms
sub dx,colc
mul dl ; result in ax, dx destroyed
add ax,lines
sub ax,linc
cmp ax,ecntr
jae pr8 ; shorter line
mov dx,en_size
mul dl ; offset of entry in ax
add ax,entaddr
mov bx,ax ; addr of ent in bx
pr2:
cmp flgsiz,0
jne pr3 ; show size ??
call psize
p1space
pr3:
cmp flglng,0
jne pr7 ; long format ??
pr4: call pattrb
p1space
pr5: call pdate
p1space
pr6: call ptime
p1space
pr7: call pname2
dec colc
jnz cp44
pr8: dsply crlf
dec linc
jnz cp33
shexit:
ret
showall ENDP
parse2 PROC NEAR ; *******************************************
; parse a directory entry created by DOS func
; 4E and 4F into ent tbl using format defined
; by ofs_ and len_ constants.
;
; destroy : ax,cx,dx,si,di
; prams : bx pointer to offset 0 of entry
; uses : nplate,my_dta,dotexe,dotcom,nameaddr
; totl_en
; vars : None
; effects : [bx]
; calls : None
; output : None
lea si,nplate ; cp plate to entry[0]
mov di,bx
mov cx,len_name ; length of nplate
rep movsb
lea si,my_dta[1eh] ; cp name to entry
mov di,bx
mov dx,0 ; no dot found yet
par23: mov al,[si] ; get chr
cmp al,0
je par29 ; end of name
cmp al,'.'
jne par25
mov dx,di ; save addr of dot in entry
jmp par25 ;;;;;;;;;;;;;;;;;;;
mov cl,my_dta[15h]
and cl,ATTD_MASK ; is entry a directory
jnz par25 ; Y - allow dots
mov di,bx ; jmp dst pointer to dot loc
add di,8
par25: mov [di],al ; store chr
inc di
inc si
jmp par23
par29:
mov byte ptr [bx+ofs_mark],' ' ; default mark as plain file
cmp dx,0
je par45
mov di,dx ; chk if file is 'exe'
lea si,dotexe
mov cx,4
repe cmpsb
je par40
mov di,dx ; chk if file is 'com'
lea si,dotcom
mov cx,4
repe cmpsb
jne par45
par40:
mov byte ptr [bx+ofs_mark],'*'
par45: mov cx,len_size ; cnvrt fsize to unpacked bcd
mov ax,word ptr my_dta[1ah] ; low word in ax
mov dx,word ptr my_dta[1ch] ; high word in dx
mov si,10 ; div by 10d
cvlp1: idiv si ; result in ax
mov di,cx ; remainder in dx
add di,bx ; calc reslt byte addr
add di,ofs_size - 1
mov [di],dl ; sto res
sub dx,dx ; reset dx to zero
loop cvlp1 ; do len times
tl1: mov cx,len_size ; add size to total
mov di,bx
add di,ofs_size+len_size
lea si,totl_en
add si,ofs_size+len_size
mov ah,0 ; carry digit
mov dl,10 ; modulo ten
tl2: dec si
dec di
tl3: mov al,byte ptr [si] ; get total digit
add al,byte ptr [di]
add al,ah ; add carry
cbw
div dl ; new carry now in al
xchg al,ah ; back to ah
mov byte ptr [si],al ; result in al, update total
loop tl2
mov al,my_dta[15h] ; get attrib byte
mov [bx+ofs_attr],al
and al,10h ; calc direct att
mov [bx+ofs_attd],al ; store
cmp al,0
je par50 ; not a subdir
mov byte ptr [bx+ofs_mark],'/'
par50: mov ax,namaddr ; save src name addr
mov [bx+ofs_nadd],ax
mov dx,word ptr my_dta[18h] ; get date
mov ax,dx
mov cl,9
shr ax,cl
mov [bx+ofs_date],ax ; store year word
mov ax,dx
and ax,111100000b
mov cl,5
shr ax,cl
mov [bx+ofs_date+2],al ; store month byte
mov ax,dx
and ax,11111b
mov [bx+ofs_date+3],al ; store day byte
mov dx,word ptr my_dta[16h] ; get time
mov ax,dx
mov cl,11
shr ax,cl
mov [bx+ofs_time],al ; store hours
mov ax,dx
and ax,11111100000b
mov cl,5
shr ax,cl
mov [bx+ofs_time+1],al ; store mons
ret
parse2 ENDP
pname2 PROC NEAR ; *******************************************
; print a file name from ent tbl and optionaly
; add file type mark.
;
; destroy : ax,cx,dx,si,di
; prams : bx pointer to offset 0 of entry
; uses : FLAGS
; vars : None
; effects : None
; calls : DOS(02)
; output : None
cmp flgmkf,0
jne pna55
mov di,bx
add di,ofs_name
mov cx,len_name
mov al,' '
repne scasb
mov al,[bx+ofs_mark]
mov [di-1],al
pna55: mov si,bx ; file names may include '$'
add si,ofs_name
mov cx,len_name
dec cx
pna66: mov dl,[si]
dosfunc 02h
inc si
loop pna66
pna99: ret
pname2 ENDP
psize PROC NEAR ; *******************************************
; print unpacked bcd number stored in 'size'
; field of a entry.
;
; destroy : ax,cx,dx,si,di
; prams : bx pointer to offset 0 of entry
; uses : None
; vars : None
; effects : None
; calls : DOS(02)
; output : None
mov cx,len_size ; do len times
mov si,0 ; reset leading zero flag
mov di,ofs_size ; start offset of size
pslp1: mov dl,[bx+di] ; get digit
cmp dl,0 ; is digit zero ?
jne not0 ; no - mark and prnt
cmp si,0 ; yes - is leading ?
jne ps2 ; no - normal
mov dl,' ' ; yes prnt blank
jmp ps3
not0: mov si,1
ps2: add dl,30h ; cvrt bcd to ascii
ps3: dosfunc 02h ; output char
cont: inc di
loop pslp1 ; next car
ret
psize ENDP
pattrb PROC NEAR ; *******************************************
; print file attributes from an entry, if att
; is on then print the att letter, otherwise
; print a dot.
;
; destroy : ax,cx,dx,si,di
; prams : bx pointer to offset 0 of entry
; uses : attrbs
; vars : None
; effects : None
; calls : DOS(02)
; output : None
mov cl,[bx+ofs_attr] ; get attrib byte
mov si,0
pat4: mov dl,'.'
rcr cl,1
jnc pat5
mov dl,attrbs[si]
pat5: dosfunc 02h
inc si
cmp si,6 ; no more attribs
jb pat4
ret
pattrb ENDP
pdate PROC NEAR ; *******************************************
; print a date from an entry.
;
; destroy : ax,cx,dx
; prams : bx pointer to offset 0 of entry
; uses : dplate
; vars : None
; effects : dplate
; calls : wtoasc,DOS(dsply)
; output : None
;;;;;;;;;;;;;;;;;;;;;;;;;;; CODE DELETED ;;;;;;;;;;;;;;;;;;;;;;;
pdate ENDP
ptime PROC NEAR ; *******************************************
; print a time field from an entry.
;
; destroy : ax,cx,dx
; prams : bx pointer to offset 0 of entry
; uses : tplate
; vars : None
; effects : tplate
; calls : wtoasc,DOS(dsply)
; output : None
mov ax,0
mov al,byte ptr [bx+ofs_time] ; get hours
push bx
lea bx,tplate[1]
mov cx,2
call wtoasc
pop bx
mov ax,0
mov al,[bx+ofs_time+1] ; get mins
push bx
lea bx,tplate[4]
mov cx,2
call wtoasc
pop bx
dsply tplate
ret
ptime ENDP
wtoasc PROC NEAR ; *******************************************
; convert binary word to ascii string.
;
; destroy : bx,dx,si
; prams : bx pointer to last ascii digit
; cx length of output string
; uses : None
; vars : None
; effects : [bx]
; calls : None
; output : none
mov si,10
wtoa1: sub dx,dx
idiv si
add dl,'0'
mov [bx],dl
dec bx
loop wtoa1
ret
wtoasc ENDP
ptotal PROC NEAR ; *******************************************
; print size field of the 'totl_en' entry with
; a title.
;
; destroy : ax,dx
; prams : None
; uses : ftotal,totl_en,crlf
; vars : None
; effects : None
; calls : DOS(dsply),psize
; output : None
;;;;;;;;;;;;;;;;;;; CODE DELETED ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ptotal ENDP
sort PROC FAR ; *******************************************
; do a key sort on records in ent tbl.
;
; destroy : ax,cx,dx,di,si
; prams : bx pointer to start of table
; srtdrc direction of sort (normal/reverse)
; srtfld start pos of key field
; srtlen length of key
; srtyet number of recs yet to sort
; uses : None
; vars : srtst1,srtst2
; effects : [bx],stryet
; calls : swaps
; output : None
mov srtst1,bx
biglup: dec srtyet
jz srt999
mov dx,srtyet
mov ax,srtst1
add ax,en_size
mov srtst2,ax ; set upper to bottm+1
smalup:
scmp1: mov si,srtst1
add si,srtfld ; point to key fld
mov di,srtst2
add di,srtfld
srt1: mov cx,srtlen
repe cmpsb ; scan key until diff
rcl al,1 ; save carry
cmp srtdrc,0
jne srt11 ; normal
not al ; reverce sort
srt11: rcr al,1
jc srt2 ; str2 is bigger
mov si,srtst1
mov di,srtst2
mov cx,en_size
call swaps ; swap entries
srt2: dec dx
jnz srt3 ; small loop not finished
mov ax,srtst1 ; prepare for big loop
add ax,en_size
mov srtst1,ax
jmp biglup
srt3:
mov ax,srtst2 ; prepare for small loop
add ax,en_size
mov srtst2,ax
jmp smalup
srt999:
ret
sort ENDP
swaps PROC NEAR ; *******************************************
; swap records (strings).
;
; destroy : ax,cx,di,si
; prams : si pntr to one rec
; di pntr to second rec
; cx length of rec
; uses : None
; vars : None
; effects : [si],[di]
; calls : None
; output : None
swp1: mov al,[si]
mov ah,[di]
mov [si],ah
mov [di],al
inc si
inc di
loop swp1
ret
swaps ENDP
cseg ENDS
;
; ********************* end of procedures **********************
;
END start
======================== END OF CODE =======================================