Category : Batch File Utilities - mostly for DOS
Archive   : ABFS.ZIP
Filename : WDX.ASM

 
Output of file : WDX.ASM contained in archive : ABFS.ZIP
PAGE 55,132
TITLE WDX.ASM -- WHICH DIRECTORY EXTENDED

CGROUP GROUP CODE_SEG,DATA_SEG
ASSUME CS:CGROUP,DS:CGROUP

PUBLIC WDX,SDIR,SSD,WS,WSL,GFM,GNM,GSN,DRN,RETX
PUBLIC FNF,NOMATCH,FND,ISD,NMM,CLOOP,WMN,BN,BSN
PUBLIC BUILD,CNAME,ALLOCATE,SCRLF,DTS,PDTS,PDTS1,PDTS2
PUBLIC STAR_NAME,PATH_NAME,FILE_NAME
PUBLIC DSDAY,DSMONTH,DSYEAR,TSHOUR,TSMINUTE,PBUFF

; RECORDS AND STRUCTURES USED

TIMESTAMP RECORD HOUR:5,MINUTE:6,TWOSEC:5
DATESTAMP RECORD YEAR:7,MONTH:4,DAY:5

DTA STRUC ;DISK TRANSFER AREA DSECT
RSVD DB 21 DUP (?) ;DOS USE ON FIND NEXT MATCH
ATTRIBUTE DB 0 ;FILE ATTRIBUTE BYTE
TIME DW 0 ;SEE TIMESTAMP RECORD ABOVE
DATE DW 0 ;SEE DATESTAMP RECORD ABOVE
SIZEL DW 0 ;LOW WORD OF LONG INTEGER
SIZEH DW 0 ;HIGH WORD OF FILE SIZE
NAME_FOUND DB 13 DUP (?) ;FILE NAME AND EXTENSION ASCIIZ
DTA ENDS

TIMESTAMP RECORD HOUR:5,MINUTE:6,TWOSEC:5
DATESTAMP RECORD YEAR:7,MONTH:4,DAY:5

SUBTTL CODE SEGMENT
PAGE

CODE_SEG SEGMENT PARA PUBLIC 'CODE'

ORG 100H ;FOR .COM FILE USE

;
; M A I N P R O G R A M
;

WDX PROC FAR
MOV AL,1 ;SET UP FOR ERROR RETURN
CALL GET_PARMS ;RETRIEVE PARM STRING
JC RETNOW ;EXIT IF NO PARMS (RC=1)
CALL SDIR ;DO THE JOB!
XOR AL,AL ;SET ZERO RETURN CODE
RETNOW: MOV AH,4CH ;DOS TERMINATE CALL
INT 21H
WDX ENDP

SUBTTL FIRST LEVEL SUBROUTINES
PAGE

;
; RETRIEVE PARAMETER STRING, IF ANY, AND SET UP FOR SEARCH
;

GET_PARMS PROC NEAR
STC ;SET CARRY (FAILURE)
PUSH AX
PUSH CX
PUSH SI
XOR AX,AX
XOR CX,CX
MOV SI,080H ;POINT AT PARM COUNT
LODSB
CMP AL,1 ;MAY BE PIPED OUTPUT!
MOV CX,AX ;KEEP THE COUNT!
JLE RETX ;QUIT, NO PARMS (RC=1)
MOV SI,082H ;POINT AT FIRST PARM
GP1: DEC CX ;IGNORE LEADING BLANK (81H)
LODSB ;GET CHARACTER
CMP AL,' ' ;IS IT BLANK?
JE GP1 ;IGNORE IT
JCXZ RETX ;FAIL IF ALL BLANKS
DEC SI ;POINT BACK AT NON-BLANK
INC CX ;ADJUST LENGTH
;
; WE HAVE A NON-BLANK PARAMETER STRING. MOVE IT TO A WORK AREA
;
MOV DI,OFFSET CGROUP:FILE_NAME

GSN: LODSB ;GET A CHARACTER INTO AL
CMP AL,0DH ;IS IT CR?
JE DRN ;YUP, QUIT
CMP AL,' ' ;IS IT A BLANK?
JE DRN ;YUP, QUIT
STOSB ;NOPE, GO FOR MORE
JMP SHORT GSN ;UNTIL YOU HIT CR OR BLANK
DRN: XOR AL,AL ;STORE ASCIIZ ZERO AT END
STOSB ;AS SEARCH SPEC.

PAGE

;
; WE MAY RE-ENTER THIS ROUTINE WITH A DIFFERENT PATH NAME, SO WE
; MAKE SURE THAT EVERYTHING IS SET UP CORRECTLY FOR RECURSION HERE
;

MOV DI,OFFSET CGROUP:PATH_NAME

CLD ;FORWARD DIRECTION SCAN
XOR AL,AL ;BUILD A ZERO SEARCH ARG.
MOV CX,64 ;MAX OF 64 BYTES
REPNZ SCASB ;SCAN FOR ZERO AT END
MOV BX,DI ;DI POINTS TO END+1
DEC BX ;POINT AT END WITH BX
MOV DX,0 ;FLAG FOR LEVEL 0 OF SEARCH
CLC ;CLEAR CARRY, WE ARE ALL OK NOW!
RETX: POP SI
POP CX
POP AX
RET
GET_PARMS ENDP

PAGE

;
; THIS IS THE REAL "MAIN" RECURSIVE SUBROUTINE
;

SDIR PROC NEAR ;SCAN CURRENT DIRECTORY
PUSH SI
PUSH DX
CALL BN ;BUILD SEARCH ARGUMENT
CALL GFM ;GET FIRST MATCH
JC NOMATCH
CALL WMN ;WRITE MATCHED NAME
FNF: CALL GNM ;FIND NEXT MATCH
JC NOMATCH
CALL WMN ;WRITE MATCHED NAME
JMP SHORT FNF ;FIND NEXT MATCH
NOMATCH: POP DX ;POINT BACK AT DTA
PUSH DX ;SAVE IT AGAIN
MOV SI,DX ;POINT SI AT DTA
CALL BSN ;BUILD *.* NAME
CALL GFM ;GET FIRST MATCH
JC NMM ;NOTHING THERE TO PRINT
MOV SI,DX ;POINT SI BACK AT DTA
TEST [SI].ATTRIBUTE,010H ;IS THIS A DIRECTORY?
JNZ ISD ;YUP
FND: CALL GNM ;GET NEXT MATCH
JC NMM ;NOTHING HERE TO MATCH
TEST [SI].ATTRIBUTE,010H ;IS THIS A DIRECTORY?
JZ FND ;YUP
ISD: CMP [SI].NAME_FOUND,'.' ;DOT OR DOT-DOT?
JE FND ;IF "." ONLY
CALL SSD ;SCAN THE SUBDIRECTORY
PUSH AX
MOV AH,01AH ;RESET DTA TO CURRENT DX!
INT 21H
POP AX
JMP SHORT FND ;AND FIND SOME MORE MATCHES
NMM: POP DX
POP SI
RET
SDIR ENDP

PAGE

;
; SCAN A SUBDIRECTORY
;

SSD PROC NEAR ;SCAN A SUBDIRECTORY
PUSH DI
PUSH SI
PUSH AX
PUSH BX
CLD
MOV SI,DX ;POINT AT NAME IN DTA!
ADD SI,OFFSET NAME_FOUND
MOV DI,BX ;POINT AT SEARCH ARGUMENT!
CLOOP: LODSB ;COPY THE NAME OVER
STOSB
OR AL,AL ;TO SET CONDITION CODE
JNZ CLOOP ;GET OUT ON BYTE OF ZERO
MOV BX,DI ;POINT BX AT END OF NAME
STD ;BACKWARD DIRECTION
STOSB ;STORE THE ZERO BYTE
MOV AL,'\' ;PRECEEDED BY "\"
STOSB
CALL SDIR ;AND RECURSE...CURSE...CURSE
POP BX
MOV BYTE PTR[BX],0
POP AX
POP SI
POP DI
RET
SSD ENDP

PAGE

;
; WRITE OUT THE MATCHED NAME STRING, DATE AND TIME
;

WMN PROC NEAR
PUSH AX
PUSH DX
CALL DTS
MOV DX,OFFSET CGROUP:PATH_NAME
MOV AL,[BX]
MOV BYTE PTR [BX],0
CALL WS
MOV [BX],AL
POP DX
PUSH DX
ADD DX,OFFSET NAME_FOUND
CALL WS
CALL SCRLF
POP DX
POP AX
RET
WMN ENDP

;
; BUILD A FILE NAME SEARCH ARGUMENT
;

BN PROC NEAR
PUSH SI
MOV SI,OFFSET CGROUP:FILE_NAME
CALL BUILD
POP SI
RET
BN ENDP

PAGE

;
; BUILD A STAR_NAME SEARCH ARGUMENT
;

BSN PROC NEAR
PUSH SI
MOV SI,OFFSET CGROUP:STAR_NAME
CALL BUILD
POP SI
RET
BSN ENDP

;
; BUILD A (GENERIC) SEARCH STRING ARGUMENT
;

BUILD PROC NEAR
PUSH AX
PUSH DI
MOV DI,BX ;USE BX AS DESTINATION!
CLD
CNAME: LODSB
STOSB
OR AL,AL ;TEST FOR ZERO BYTE
JNZ CNAME
POP DI
POP AX
RET
BUILD ENDP

PAGE
;
; GET FIRST FILE NAME MATCHING SEARCH ARGUMENT
;
;
; NOTE: WE USE A DIFFERENT DTA EACH TIME WE CALL GFM, STARTING
; WITH THE DTA IMMEDIATELY AFTER THE DATA SEGMENT ITSELF
;

GFM PROC NEAR
PUSH CX
CMP DX,0 ;FIRST ALLOCATE?
JA ALLOCATE
;
; FIRST TIME WE BACK UP ONE DTA SIZE, THEN ADD IT BACK
;
MOV DX,OFFSET CGROUP:DISK_TRANSFER_AREAS-TYPE DTA

ALLOCATE: ADD DX,TYPE DTA ;NEXT DTA PLEASE!
MOV CX,10H ;?????
MOV AH,01AH ;SET DTA DS:DX
INT 21H
PUSH DX ;SAVE CURRENT DTA
MOV DX,OFFSET CGROUP:PATH_NAME
MOV AH,04EH ;ISSUE FIND FIRST MATCH
INT 21H
POP DX ;RECOVER OLD DTA
POP CX ;AND CX
RET
GFM ENDP

PAGE
;
; GET NEXT FILE NAME MATCHING SEARCH ARGUMENT
;

GNM PROC NEAR
PUSH CX ;SAVE CX
PUSH DX ;AND DTA ADDRESS
MOV DX,OFFSET CGROUP:PATH_NAME ;POINT AT SEARCH ARG
MOV CX,010H
MOV AH,4FH ;FIND NEXT MATCH
INT 21H
POP DX ;RECOVER DTA ADDRESS
POP CX ;AND CX
RET
GNM ENDP

;
; OUTPUT CR-LF AT END OF CURRENT OUTPUT STRING(S)
;

SCRLF PROC NEAR
PUSH AX ;SAVE AX
PUSH DX ;AND DTA!
MOV AH,02 ;DISPLAY OUTPUT
MOV DL,0DH ;CR
INT 21H
MOV DL,0AH ;LF
INT 21H
POP DX ;RECOVER DTA
POP AX ;AND AX
RET
SCRLF ENDP

PAGE
;
; WRITE STRING
;

WS PROC NEAR
PUSH AX ;SAVE AX
PUSH DX ;AND DTA
PUSH SI ;AND SOURCE POINTER
CLD ;FORWARD DIRECTION
MOV SI,DX ;SOURCE IS DTA(0)
MOV AH,2 ;DISPLAY OUTPUT
LODSB ;GET A BYTE
WSL: MOV DL,AL ;PUT IN DL
INT 21H ;WRITE IT
LODSB ;GET ANOTHER BYTE
OR AL,AL ;TEST FOR ZERO BYTE
JNZ WSL ;NOPE, DO MORE!
POP SI ;RECOVER SOURCE POINTER
POP DX ;AND DTA
POP AX ;AND AX
RET
WS ENDP

PAGE
;
; GET AND PRINT FILE DATE AND TIME INFORMATION
;

DTS PROC NEAR
PUSH AX ;SAVE AX
PUSH BX ;SAVE BX
PUSH CX ;SAVE CX
PUSH DX ;AND DTA
;
; NOW GO GET THE DATE AND TIME FROM THE DTA, AND UNPACK FOR OUTPUT
;
MOV BX,DX ;USING BX
MOV AX,[BX].TIME ;PICK UP TIME WORD
AND AX,MASK HOUR ;ISOLATE THE HOUR
MOV CL,HOUR ;SHIFT TO RIGHT JUSTIFY
SHR AX,CL ;MAKE IT AN INTEGER
MOV TSHOUR,AX ;SAVE IT FOR OUTPUT
MOV AX,[BX].TIME ;SAME AS ABOVE FOR MINUTES
AND AX,MASK MINUTE
MOV CL,MINUTE
SHR AX,CL
MOV TSMINUTE,AX ;SAVE FOR OUTPUT
MOV AX,[BX].DATE ;DITTO DATE JUNK
AND AX,MASK DAY
MOV CL,DAY
SHR AX,CL
MOV DSDAY,AX
MOV AX,[BX].DATE
AND AX,MASK MONTH
MOV CL,MONTH
SHR AX,CL
MOV DSMONTH,AX
MOV AX,[BX].DATE
AND AX,MASK YEAR
MOV CL,YEAR
SHR AX,CL
ADD AX,80 ;0==1980!
MOV DSYEAR,AX ;SAVE FOR OUTPUT
PAGE
;
; NOW PRINT THEM OUT AS NEEDED
;
MOV AX,TSHOUR
CALL PDTS
PUSH DX ;SAVE IT ONCE MORE
MOV AH,2
MOV DL,':'
INT 21H
POP DX ;POINT AT CURRENT DTA!
MOV AX,TSMINUTE
CALL PDTS
PUSH DX ;SAVE IT ONCE MORE
MOV AH,2
MOV DL,' '
INT 21H
POP DX ;POINT AT CURRENT DTA!
MOV AX,DSMONTH
CALL PDTS
PUSH DX ;SAVE IT ONCE MORE
MOV AH,2
MOV DL,'/'
INT 21H
POP DX ;POINT AT CURRENT DTA!
MOV AX,DSDAY
CALL PDTS
PUSH DX ;SAVE IT ONCE MORE
MOV AH,2
MOV DL,'/'
INT 21H
POP DX ;POINT AT CURRENT DTA!
MOV AX,DSYEAR
CALL PDTS
PUSH DX ;SAVE IT ONCE MORE
MOV AH,2
MOV DL,' '
INT 21H
POP DX ;POINT AT CURRENT DTA!
POP DX ;RECOVER ALL REGS
POP CX
POP BX
POP AX
RET
DTS ENDP

PAGE
;
; PRINT DATE AND TIME STAMP FIELDS -- CONVERTING FROM INTEGER TO ASCII
; AND ZERO PADDING ON THE LEFT TO TWO-DIGITS IF NECESSARY!
;

PDTS PROC NEAR
PUSH AX ;SAVE USED REGS
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV DI,OFFSET CGROUP:PBUFF ;POINT DI AT THE BUFFER!
XCHG AX,DX ;PUT BINARY VALUE IN DX
XOR CX,CX ;CLEAR OUT COUNT OF BYTES
PDTS1: PUSH CX ;SAVE COUNT
MOV AX,DX ;GET WORD INTO AX
MOV DX,0 ;CLEAR DX
MOV CX,10 ;DIVIDE BY 10
DIV CX
XCHG AX,DX ;RESULT TO DL FOR OUTPUT
ADD AL,30H ;MAKE IT ASCII
MOV [DI],AL ;PUT IT IN BUFFER
INC DI ;POINT AT NEXT BUFFER BYTE
POP CX ;RECOVER COUNT
INC CX ;INCREMENT COUNT
CMP DX,0 ;REG NOW ZERO?
JNZ PDTS1 ;NOPE, TRY SOME MORE
;
; WE ARE NOW POINTING ONE BYTE PAST THE (LAST) CONVERTED DIGIT IN PBUFF
; AND HAVE TO CHECK WHETHER WE NEED TO ZERO PAD THE CONVERTED NUMBER
; TO TWO DIGITS IN LENGTH BEFORE OUTPUT. NOTE THAT THE DIGITS ARE
; IN "REVERSE" ORDER IN THE BUFFER!
;
MOV DL,'0' ;PRE-SET FOR ZERO BYTE OUTPUT
MOV AH,2 ;DISPLAY OUTPUT REQUEST
CMP CX,2 ;ONLY ONE DIGIT?
JAE PDTS2 ;NOPE, JUST OUTPUT
INT 21H ;PAD OUTPUT TURKEY!
PDTS2: DEC DI ;OK, NOW DUMP OUT THE DIGIT(S)
MOV AH,2
MOV DL,[DI]
INT 21H
LOOP PDTS2
POP DI ;RECOVER ALL REGS
POP DX
POP CX
POP BX
POP AX
RET
PDTS ENDP

SUBTTL DATA SEGMENT
PAGE

;
; WARNING. THIS DATA SEGMENT MUST BE THE LAST SEGMENT LOADED
; IN CGROUP, AS RECURSIVE CALLS ALLOCATE NEW GENERATIONS
; OF DATA STARTING AT THE END OF THIS SEGMENT!
;

DATA_SEG SEGMENT PARA PUBLIC 'DATA'

;
; TEMPORARY WORK AREAS FOR DATE/TIME DECODE AND CONVERSION
;

DSDAY DW 0
DSMONTH DW 0
DSYEAR DW 0
TSHOUR DW 0
TSMINUTE DW 0

PBUFF DB 20 DUP(' ') ;PRINTER BUFFER FOR CONVERSIONS

STAR_NAME DB '*.*',0 ;ASCIIZ SEARCH ARGUMENT

PATH_NAME DB '\',0 ;ASCIIZ ROOT PATH NAME
DB 80 DUP(0) ;TOTAL OF 81 BYTES OF ZERO
FILE_NAME DB 13 DUP(0) ;NOTE TRAILING ZERO BYTE BELOW
DB 0

DISK_TRANSFER_AREAS LABEL BYTE

DATA_SEG ENDS

CODE_SEG ENDS
END WDX


  3 Responses to “Category : Batch File Utilities - mostly for DOS
Archive   : ABFS.ZIP
Filename : WDX.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/