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 =======================================