home *** CD-ROM | disk | FTP | other *** search
- ;ZDIR .ZIP directory utility
- ;From a disassembly and hack of ADIR.EXE
-
- ;v1.8 Update for PKZIP v2.04x
- ; - Added new "deflate" method.
- ; - Moved versions out to HISTORY.TXT
- ; - Removed earlier "v1.x" comments
-
- FALSE equ 0
- TRUE equ NOT FALSE
- PLAIN equ 0
- VERBO equ 0FFh
- MONOSYL equ 1
- STRINGWILD Equ '*' ; wildcard for strings
- CHARWILD Equ '?' ; wildcard for single chars
- CR equ 0DH
- LF equ 0AH
- STDOUT equ 1
- STDERR equ 2
- ENDOFS equ 4096 ;enough for largest possible
- ;ZIP end directory structure.
- ;(to include XMODEM padding)
- ;(and hormongous comments!)
- ;(was 256 in v1.3)
-
- Print macro name ; display a field
- mov dx,offset name
- call PrintS
- endm
-
- ;PKZIP central directory structure:
-
- zdirEntry STRUC
- zsig1 db 50H,4BH,01H,02H ;central file header signature 4 bytes
- ;(0x02014b50)
- zVerMade dw ? ;version made by 2 bytes
- zVerExt dw ? ;version needed to extract 2 bytes
- zBitFlag dw ? ;general purpose bit flag 2 bytes
- zCmpMeth dw ? ;compression method 2 bytes
- zModTime dw ? ;last mod file time 2 bytes
- zModDate dw ? ;last mod file date 2 bytes
- zCrc32 dw ?,? ;crc-32 4 bytes
- zCmpSiz dw ?,? ;compressed size 4 bytes
- zUncmpSiz dw ?,? ;uncompressed size 4 bytes
- zNameLen dw ? ;filename length 2 bytes
- zExtraLen dw ? ;extra field length 2 bytes
- zFilCmtLen dw ? ;file comment length 2 bytes
- zDskNrPtr dw ? ;disk number start 2 bytes
- zIntAttr dw ? ;internal file attributes 2 bytes
- zExtAttr dw ?,? ;external file attributes 4 bytes
- zHdrOfs dw ?,? ;relative offset of local header 4 bytes
- zFilename db ? ;filename (variable size)
- ;extra field (variable size)
- ;file comment (variable size)
- zdirEntry ENDS
-
- ; End of central dir record:
-
- zdirEnd STRUC
- zEndSig db 50H,4BH,05H,06H ;end of central dir signature 4 bytes
- ;(0x06054b50)
- zDskNr dw ? ;number of this disk 2 bytes
- zDirDsk dw ? ;number of the disk with the
- ;start of the central directory 2 bytes
- zDskNrEntry dw ? ;total number of entries in
- ;the central dir on this disk 2 bytes
- zDirNrEntry dw ? ;total number of entries in
- ;the central dir 2 bytes
- zDirSiz dw ?,? ;size of the central directory 4 bytes
- zDirOfs dw ?,? ;offset of start of central
- ;directory with respect to
- ;the starting disk number 4 bytes
- zCmtLen dw ? ;zipfile comment length 2 bytes
- zCmt db ? ;zipfile comment (variable size)
- zdirEnd ENDS
-
-
- CSEG segment para public
- assume CS:CSEG,DS:CSEG
-
- org 5CH ;FCB #1
- db ? ;drive val
- fcb1 db 10H dup(?) ;5DH, FCB #1 first char
- fcb2 db 10H dup(?) ;6DH, FCB #2 first char
- org 80H
- nchar db ?
- params db ?
- org 9EH ; We'll use the default PSP DTA,
- PSP_DTA_Name db ? ; and the file name found will be HERE.
-
- ;program entry point
- org 100H
-
- Zdir proc near
- jmp Start ;skip over runtime data
-
-
- usage db CR,LF,9,9, 'ZDIR version 1.8, 920124',CR,LF
- db 9,9,'David Kirschbaum, Toad Hall/mod GWS',CR,LF
- db 9,9, 'USAGE: ',9,'ZDIR zipname[.zip] [afn] [-v|-m]',CR,LF
- db 9,9,9,'zipname may be ambiguous (wildcarded)',CR,LF
- db 9,9,9,'afn = ambiguous member file name (like a*b)', CR,LF
- db 9,9,9,'-v = verbose display',CR,LF
- db 9,9,9,'-m = monosyllabic display',CR,LF
- USAGELEN equ $ - usage
-
- ziptyp db '.ZIP'
- ZIPTYPLEN equ $ - ziptyp
-
- msg1 db CR,LF, 9, 9, 9, ' ZIP file: '
- MSG1LEN equ $ - msg1
- msg2 db 'ZIP file not found',CR,LF
- MSG2LEN equ $ - msg2
- msg3 db 'Central directory not found',CR,LF
- MSG3LEN equ $ - msg3
- msg4 db 'ZIP is out of alignment or it''s not a ZIP'
- crlf db CR,LF
- MSG4LEN equ $ - msg4
- CRLFLEN equ $ - crlf
-
- ;Keith Petersen suggested this oughtta go .. Sigh ...
- ;rivvvt db 'Rivvvvt',CR,LF
- ;RVTLEN equ $ - rivvvt
-
-
- handle dw 0
- flag1 db LOW(TRUE) ;Find First flag
- verbose db PLAIN ;verbose display switch
- ;PLAIN, VERBO, or MONOSYLLABIC
- znameptr dw 0 ;point past ZIP target file path
- mnameptr dw 0 ;remember .zFilename start
- dirNrEntry dw 0 ;central directory file count
- dirctr dw 0 ;for counting down members
- pathflag db ' ' ;is set to '+' if member
- ; filename includes a path
-
- vhdrflag db FALSE ;set true when first member
- ;file is found
-
- Comment ~ Looks like:
- +filename.typ 000K / 000K +filename.typ 000K / 000K +filename.typ 000K / 000K
- Comment ends ~
- blankline db ' . K / K . K / K '
- db ' . K / K',CR,LF
- LINELEN equ $ - blankline
-
- ; Verbose display data
- ; display lines for verbose
- ; Adding a "E" (just before Stowage style) if encrypted
-
- vhdr db CR,LF
- db ' Name Length E Stowage SF Size now Date Time CRC'
- db CR,LF
- db ' ============ ======== = ======== ==== ======== ========= ====== ========'
- db CR,LF
- VHDRLEN equ $ - vhdr
-
- vline label byte ;db CR,LF
- vname db 15 dup (' ')
- vlength db 9 dup (' ') ; length in archive
- vencflag db 3 dup (' ') ;"E" if encrypted, else blank
- vstyle db 10 dup (' ') ; compression method (text)
- vfactor db ' xx% ' ; compression factor (percentage)
- vsize db 10 dup (' ') ; actual file bytes
- vdate db 'dd ' ; creation date
- vmonth db 'mmm '
- vyear db 'yy '
- vtime db 'hh:mm ' ; creation time
- vcrc db 'xxxxxxxx' ; 32-bit crc in hex
- db CR,LF
- VLINELEN equ $ - vline
-
-
- ; final totals line
-
- vthdr db '*Total '
- vtmbrs db 5 dup (' ')
- vtlen db 8 dup (' '),' '
- db 12 dup (' ')
- vtsf db ' % '
- vtsize db 8 dup (' ')
- db CR,LF ; for tom
- VTHDRLEN equ $ - vthdr
-
- ;Totals for each ZIP file's members:
-
- totcmp dw 0,0 ; total of file lengths
- totuncmp dw 0,0 ; total of file sizes
- totmbrs dw 0 ; total number of files
- TOTLEN equ $ - totcmp
-
- ;Totals for ALL ZIP files displayed:
-
- ttotcmp dw 0,0 ;total compressed file size
- ttotuncmp dw 0,0 ;total uncompressed file size
- ttotmbrs dw 0 ;total nr member files
-
-
- ; ZIP compression types:
-
- ;#define STORED 0 /* compression methods */
- ;#define SHRUNK 1
- ;#define REDUCED1 2
- ;#define REDUCED2 3
- ;#define REDUCED3 4
- ;#define REDUCED4 5
- ;#define IMPLODED 6
- ;#define TOKENIZED 7
- ;#define DEFLATED 8
- ;#define NUM_METHODS 9 /* index of last method + 1 */
-
- MAXSTYLES EQU 8 ;v1.8
- zstyles label byte
- db ' Stored' ;0 - The file is stored (no compression)
- db ' Shrunk' ;1 - The file is Shrunk
- db 'Reduced1' ;2 - Reduced with compression factor 1
- db 'Reduced2' ;3 - Reduced with " " 2
- db 'Reduced3' ;4 - Reduced with " " 3
- db 'Reduced4' ;5 - Reduced with " " 4
- db 'Imploded' ;6 - The file is imploded
- db 'Tokenize' ;7 - The file is "tokenized" v1.8
- db 'Deflated' ;8 - The file is Deflated v1.8
- db ' Unknown' ;illegal or unknown value
-
- months db 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
-
- ; translation table for upper-casing national chars:
- UpperSet Db 'ÄÖÜÇÅÉÆÑ' ; upper case national chars
- LowerSet Db 'äöüçåéæñ' ; lower case national chars
-
-
- Zdir endp
-
- Start proc near
-
- call Parse_CmdLine ;parse cmdline for
- ;target filenames
- jb Jmp_Msg_Term ;failed
-
- ;Let's get to work
-
- call Find_Zip
- jnc ZipLup_73 ;found the first one
- mov dx,offset msg2 ;'Zipfile not found'
- mov cx,MSG2LEN
- Jmp_Msg_Term:
- jmp Msg_Term ;display, terminate
-
- ZipLup_73:
- call Read_CentralDir ;try to read in file trailer
- jnb Got_Dir ;found it, DS:BX -> directory
-
- mov dx,offset msg3 ;'No central directory'
- mov cx,MSG3LEN
- jmp short Next1 ;right to next ZIP file
-
- Got_Dir:
- ; We'll only show our verbose header line
- ; when and if we find our first member file.
- ; (Down in Show_FileData)
-
- cmp verbose,MONOSYL ;mode switch
- ja MemberLup ;verbose, no init
- jb GD_InitLine ;plain, use standard
-
- mov di,offset blankline ;if monosyllabic, blank
- mov al,' ' ; that blankline for
- mov cx,LINELEN-2 ; good
- rep stosb
-
- GD_InitLine:
- call Refresh_LineBuff ;Init formatted display line
-
- MemberLup:
- cmp word ptr [bx],4B50H ;signature?
- jnz Bad_Dir ;nope, bogus
- cmp word ptr 2[bx],0201H ;normal entry?
- jnz Bad_Dir ;nope, bogus
-
- ;Normal directory entry. Display it.
-
- call Show_FileData ;display entry info
- dec dirctr ;decr nr entries
- jz Next_Zip ;last entry
- jmp MemberLup ;next member
-
-
- Bad_Dir:
- mov dx,offset msg4 ;'ZIP is out of alignment'
- mov cx,MSG4LEN ; or not a .ZIP file'
- call Pr_StdOut ;display msg
-
- Next_Zip:
- mov dx,offset crlf ;need a new line
- mov cx,CRLFLEN ;length
- cmp verbose,VERBO ;verbose mode?
- jz Show_Verbose_Totals ;yep, maybe display totals
-
- mov ax,offset linebuff ;formatted line start
- cmp di,ax ;got any file entries?
- jz Next1 ;nope
- dec di ;back up over the two spaces
- dec di ; from the last file size
- mov dx,ax ;DX'll need it for display
- mov cx,ax ;CX will be nr chars
- mov ax,0A0DH ;CR/LF
- stosw ;stuff
- stosw ;2 CR/LFs
- xchg cx,di ;CX = end, DI = start
- sub cx,di ;end - start = length
- jmp short Next1
-
-
- ;Verbose mode
-
- Show_Verbose_Totals:
- cmp totmbrs,0 ;any totals?
- jz Next1 ;nope
- call Format_Totals ;yep, format
- ;CX,DX prepared for ...
- ; If just 1 member, there won't BE a total display!
- ; BP returns from Format_Totals with 0 (1 file) or 1 (more than
- ; 1 file)
- or bp,bp ;just 1 file?
- jz Next2 ;yep, no totals
-
- Next1:
- call Pr_StdOut ;display line seg or CR/LF
- Next2:
- call Find_Zip ;next .ZIP file
- jnc ZipLup_73 ;found it, loop
-
- xor ax,ax ;handy 0/FALSE
- cmp al,verbose ;nonverbose mode?
- jle NoMsg_Term ;nonverbose, terminate
- ;(errorlevel 0)
-
- ; We've been accumulating overall totals.
- ; Now display them. Gotta move the total totals
- ; into the totals (where Format_Totals expects them).
-
- ; If we never displayed our verbose header line,
- ; we never found a qualifying member file!
- ; Ergo .. no totals ..
-
- cmp vhdrflag,al ;FALSE ;no header line?
- jz NoMsg_Term ;no hdr, so no totals
-
- mov ax,ttotmbrs ;accumulated total mbrs
- cmp ax,dirNrEntry ;just the one ZIP?
- jz No_More ;yep, forget total totals
- cmp ax,1 ;<= 1?
- jbe No_More ;yep, forget the total totals
-
- mov si,offset ttotcmp ;move total totals
- mov di,offset totcmp ;into totals
- mov cx,TOTLEN SHR 1 ;nr words
- rep movsw
-
- call Pr_CrLf ;down extra line
- call Format_Totals ;format overall totals
- call Pr_StdOut ;display them
-
- No_More:
- ; Keith Petersen suggested this oughtta go .. Sigh ..
- ; mov dx,offset rivvvt
- ; mov cx,RVTLEN ;fall thru to...
- xor ax,ax ;ERRORLEVEL 0
- jmp short NoMsg_Term
-
- Msg_Term:
- push ax ;save errorlevel
- call Pr_StdOut ;display error msg
- pop ax
- NoMsg_Term:
- mov ah,4Ch ;terminate, AL = ERRORLEVEL
- int 21h
-
- Start endp
-
-
- ;SUBROUTINE
-
- Find_Zip proc near
-
- ;We reset our DTA to the default PSP DTA each time through.
- ;The actual ZIP file open uses another one.
-
- mov dx,80H ;use PSP DTA
- mov ah,1AH ;set DTA
- int 21h
-
- ;v1.7a new code
- mov ah,4FH ;assume not first time thru
- ;think how many bytes,
- ; machine cycles THIS saved!
- cmp flag1,0FFh ;first time thru?
- jne Find_Done ;nope
-
- ;First time through
- not flag1 ;set to NOT first time thru
-
- mov dx,offset ziptarget ;DS:DX -> zip target name
- xor cx,cx ;read-only
- dec ah ;4EH ;find first
-
- Find_Done:
- int 21h ;hah - two bytes saved!
- jb FindZ_X ;failed, return CF set
-
- ;v1.7a new code ends
-
- Comment ~ introduced in v1.7
- Once DOS has found a file, we could apply our own matching
- on top (DOS will maybe find MORE than we like, but never LESS).
- Basically, that's another 'call MatchW'; remember to 'CLC' before
- returning, so that we will be called again. - Just one problem:
- We need our old name, as used to be in ziptarget; but that has
- now been overwritten with the previous matching file name. So
- we'd need to keep the old name somewhere... Too lazy to do it now.
- End of comment v1.7 ~
-
- call Move_FileName ;move name in after path
- ;to create full name for open
-
- ;Found target file. Announce, set new DTA, open it.
-
- mov dx,offset msg1 ;'Zip file: '
- mov cx,MSG1LEN
- call Pr_StdOut
- Print ziptarget ;'filename.zip'
- call Pr_CrLf ;new line
-
- ;We need a new DTA for the file open/read so we don't blow away
- ;the find first/find next stuff in the PSP DTA.
-
- mov dx,offset dta1BA ;DS:DX -> new DTA
- mov ah,1Ah ;set DTA
- int 21h
-
- mov dx,offset ziptarget ;DS:dx -> filename buffer
- mov ax,3D00H ;open file, read only
- int 21h
- mov handle,ax ;save handle
- FindZ_X:
- ret
- Find_Zip endp
-
-
- Move_FileName proc near
-
- mov si,offset PSP_DTA_Name ;FCB #1 +1
- mov di,znameptr ;pointer to after path
- mov cx,6 ;first 12 bytes
- rep movsw
- movsb ;13th byte
- ret
-
- Move_FileName endp
-
-
- ;Reads in file tailer.
- ;Then scans for the unique central directory signature.
- ;On success:
- ; DS:BX -> central directory structure
- ; readlen = nr bytes actually read
- ; CF clear
- ;Else CF set for failure
-
- Read_CentralDir proc near
-
- xor cx,cx ;CX:DX = offset from end
- xor dx,dx ;to very end
- mov bx,handle ;file handle
- mov ax,4202H ;move file pointer to end
- int 21H ;gets file size in DX:AX
- jb RCD_Close ;seek failed
-
- ; Increased ENDOFS to read in more of the ZIP file's tail.
- ; Original value wasn't enough to allow for huge comments.
-
- sub ax,ENDOFS ;back up psn.lo
- jnb Read1 ;ok, no problem
- sub dx,1 ;got a borrow, decr psn.hi
- jnb Read1 ;no problem
- xor ax,ax ;sigh .. small file ..
- xor dx,dx ; .. back to very start
- Read1:
- mov cx,dx ;psn.hi
- mov dx,ax ;psn.lo
- mov ax,4200H ;now move from start
- int 21H ;CX:DX point to offset from end
- ;(big) or to start (small)
- jb RCD_Close ;failed, close up
-
- mov cx,ENDOFS ;try to read this much
- mov dx,offset dirbuff ;into our directory buffer
- mov di,dx ;DI'll need it in a second
- mov ah,3FH ;read from file/device
- int 21H ;AX=bytes read
- jb RCD_Close ;failed, close up
-
- ;First scan the end structure to locate the central directory.
-
- call Sig_Scan ;find the structure start
- ;(using bytes read in AX)
- jb RCD_InvalidDir ;failed, close and exit
-
- ;ES:DI -> end structure start (the signature)
- ;While we have the end structure, let's pick up and display
- ;any ZIP file comment.
-
- mov cx,[di].zCmtLen ;comment length
- jcxz RCD_NoComment ;nope, forget it
-
- lea dx,[di].zCmt ;DS:DX -> comment
- call Pr_StdOut ;display it.
- call Pr_CrLf ;and a new line
-
- RCD_NoComment:
-
- ; Pick up the central directory file pointer (long integer):
- ; It's a pointer directly to the central directory start.
- ; This will only work for single-disk ZIP files.
-
- mov si,[di].zDirSiz ;save central directory size
-
- mov ax,[di].zDirNrEntry ;nr central dir entries
- mov dirNrEntry,ax ;save it for later
- mov dirctr,ax ;two places
-
- mov dx,[di].zDirOfs ;central directory offset.lo
- mov cx,[di].zDirOfs[2] ;offset.hi
- mov ax,4200H ;move file ptrs from start
- int 21H
- jb RCD_Close ;seek failed, close and exit
-
- mov cx,si ;read central dir size bytes
- mov dx,offset dirbuff ;into our directory buffer
- mov ah,3FH ;read from file/device
- int 21H
- jb RCD_Close ;failed, forget it
-
- mov di,dx ;DI -> dir start
- xor ax,ax ;return AX=0 for ok
- cmp word ptr [di],4B50H ;is it a signature?
- jnz RCD_InvalidDir ;nope
- cmp word ptr 2[di],0201H ;is it a file entry sig?
- jz RCD_Close ;yep, good to go, CF clear
-
- RCD_InvalidDir:
- mov al,11 ;Invalid format
- stc ;insure CF set, AL=error
- RCD_Close:
- mov dx,ax ;save error value (if any)
- pushf ;save flags
- mov ah,3EH ;close file
- int 21H ;(BX = file handle)
- popf ;restore orig flags
- mov ax,dx ;and any error value
- mov bx,di ;if it went well,
- ;DS:BX -> central dir struc
- ret
-
-
- ; Subroutine for Read_CentralDir
- ; Scans backwards through buffer for a directory end signature.
- ; Enter with:
- ; SI = second two signature bytes
- ; DX -> buffer start
- ; AX = bytes read
-
- ;We must scan at the byte level (since a member or directory entry
- ;can be ANY length).
-
- Sig_Scan:
- mov di,dx ;ES:DI -> dirbuff
- ;(now a ZIP end dir structure)
- add di,ax ;+ bytes read = -> buff end
- mov cx,ax ;bytes read for the scan
- inc cx ;debug for MAX size
- inc cx
- mov ax,4B50H ;scan for first signature char
- ;(same for all structures)
- mov si,0605H ;2d 2 chars of a directory
- ;end structure signature
- std ;scan from end to start
-
- SS_Lup:
- repne scasb ;ES:DI -> read buffer
- jnz No_Sig ;not found
- jcxz No_Sig ;scanned it all
-
- ;ES:DI -> the byte BEFORE the 50H signature
-
- cmp 2[di],ah ;2d signature byte?
- jnz SS_Lup ;nope, keep searching
- cmp 3[di],si ;last 2 signature bytes?
- jnz SS_Lup ;nope, keep searching
-
- inc di ;bump from that last scasb
- ;DS:DI -> dir structure
- cld ;forwards again to be neat
- clc ;CF clear for success
- ret
-
- No_Sig: cld ;forward again to be neat
- stc ;return CF set for failure
- ret
-
- Read_CentralDir endp
-
-
- ;SUBROUTINE
- ;1 call
- Show_FileData proc near
- ;Added tests for cmdline member name testing
-
- call Member_Test ;see if file is eligible
- jnz SF_NextRec ;nope, forget it
-
- push bx
-
- xor ax,ax ;FALSE
- cmp al,verbose ;not verbose?
- jle SFD_NonVerbose ;not verbose
-
- ;Verbose mode
- cmp vhdrflag,al ;FALSE ;verbose hdr displayed?
- jnz SFD_HdrDone ;yep
-
- not vhdrflag ;set to TRUE
- mov dx,offset vhdr ;display verbose header
- mov cx,VHDRLEN
- call Pr_StdOut
-
- SFD_HdrDone:
- call Show_Verbose ;show verbose member display
- jmp short SFD_BumpPtrs ;skip nonverbose stuff
-
-
- ;Nonverbose mode
-
- SFD_NonVerbose:
- call Stuff_FileName ;parse, pad at ES:DI
-
- cmp verbose,MONOSYL ;monosyllabic output?
- je SFD_FlushLine ;shove it out
-
- lea si,[bx].zCmpSiz ;compressed size (long int)
- call Stuff_FileSize ;to ES:DI
-
- lea si,[bx].zUncmpSiz ;uncompressed size
- inc di ;adjust line ptr
- call Stuff_FileSize ;stuff uncompressed size
- ; to ES:DI
- cmp di,offset linebuff + LINELEN ;hit end?
- jb SFD_BumpPtrs ;nope
-
- SFD_FlushLine:
- mov dx,offset linebuff ;display the line
- mov cx,LINELEN ;length
- call Pr_StdOut ;display it
- call Refresh_LineBuff ;refresh dynamic variable
-
- SFD_BumpPtrs:
- pop bx
-
- SF_NextRec:
- ;Now bump our BX pointer to the next entry
- lea ax,[bx].zFilename ;from filename start
- add ax,[bx].zNameLen ;add in name field length
- add ax,[bx].zExtraLen ;and extra field length
- add ax,[bx].zFilCmtLen ;and file comment field length
- mov bx,ax ;should be next record
- ret
-
- Show_FileData endp
-
- ;Tests to see if THIS file is eligible (e.g., meets the ambiguous
- ;filename entered on cmdline at startup).
- ; If no such parm, accept it (return CF clear).
- ; If it matches, return CF clear.
- ; If no match, return CF set.
-
- ;While we're here, let's Asciify that stupid ZIP directory file name
- ;for later tests.
-
- Member_Test proc near
-
- mov cx,[bx].zNameLen ;name length
- jcxz MT_Fail1 ;zero .. flunk it!
-
- push di ;save formatted line pointer
-
- lea si,[bx].zFilename ;dirEntry filename
- mov di,si ;start
- dec di ;back it up one
- mov ax,di ;remember new start
- mov dx,cx ;save length
-
- rep movsb ;move it left 1 char
- ;(make room for AsciiZ 0)
- mov byte ptr [di],0 ;AsciiZ the name
-
- mov cx,dx ;restore count/length
- mov si,ax ;new start (1 char to left)
- mov dx,ax ;remember in DX
-
- mov mnameptr,ax ;assume no paths
-
- cmp byte ptr 1[si],':' ;a drive separator?
- jnz MT_NoDrive ;nope
- mov ax,2
- add si,ax ;bump past d:
- sub cx,ax ;adjust length counter
- jbe MT_Fail ;zeroed out, flunk it!
-
- MT_NoDrive:
-
- ;Check for directory slashes
- mov di,si ;starting point
- ;PKZIP uses the '/' character for paths!
- ; Wonder why GWS is loading the entire AX?
- ; We're only doing a SCASB for the slash!
- ; Aha! Because of that je MT01 below .. tricky, tricky...
- mov ax,' /' ;scan for PKZIP
- ; directory slashes
- MT_SlashScan:
- repne scasb
- jnz MT_NoSlash ;none
- jcxz MT_Fail ;zeroed out, flunk it!
- mov si,di ;new starting point
- mov byte ptr [di-1], '\' ;old habits never die
- jmp MT_SlashScan ;and try again until all gone
-
- MT_NoSlash:
-
- ;SI now points at first filename char.
-
- cmp verbose,MONOSYL ;are we monosyllabic?
- je MT_01 ;yes,remember full path
-
- mov mnameptr,si ;remember the new address
-
- ; We'll set a global flag if there was a path.
- ; Simpler than testing if mnameptr = filename start
- ; in both verbose and nonverbose display modes.
- ; DX -> shifted .zFilename
- ; SI -> filename first char
-
- mov ax,'+ ' ;assume yes (no paths)
- ;(AL=' ',AH='+')
- cmp dx,si ;name^ = zFileName^?
- jz MT_1 ;yep, no path
- MT_01: ;if monosyl, use ' '!
- mov al,ah ;'+' ;set the path flag
- MT_1:
- mov pathflag,al ;post path flag
-
- cmp byte ptr pname1,0 ;empty member name?
- jz MT_Done ;empty, forget the compares
-
- mov di, si
- mov si, offset pname1
- call MatchW
-
- pop di
- ret
-
- MT_Fail: ;no match
- pop di ;restore formatted line ptr
-
- MT_Fail1:
- mov al,1 ;return ZF clear
- MT_X: ret
-
- MT_Done:
- pop di
- xor al,al ;return ZF set for success
- ret
-
- Member_Test endp
-
- ; The following routine introduced in v1.7:
-
- MatchW Proc Near
-
- ; This function checks if a given string matches a given pattern
- ; including generalized wildcards, e.g., 'a*b?c'. The matching is
- ; case-sensitive. The result is returned in the flags:
- ; ZF set = exact match (check with JZ ExactMatch)
- ; CF set = no match ( JB NoMatch)
- ; CF clear, ZF clear = prefix match ( JA PartialMatch)
- ; (or JAE PartialOrExact)
- ;
- ; Hand-assembly from a Fortran routine by Gunter Rademacher
- ;
- ; Input
- ; si - pointer to pattern, ASCIIZ
- ; di - pointer to string, ASCIIZ
- ; Output
- ; carry and zero flags (cf. above)
- ; Registers modified
- ; ax, cx, si, di
-
-
- ; Let's use BX and DX (saving them on the stack just in case
- ; they need to be preserved) instead of the variables saveSI and saveDI.
- ; Gain speed, reduce size.
-
- push bx ;preserve
- push dx
-
- mov dx,di ;save DI a sec
- xor ax,ax ;clear lsb and msb
- ;(to find end of AsciiZ
- ; string, later as flag)
-
- ; Bad assumption here: What is CX prior to this REPNE SCASB?
- ; Donno .. so we'd better make sure it's big, ne?
- ; I can live with assuming we're already CLD'ed (forward)
- ; I also don't see where saveSI was ever initialized!
- ; I can only assume pattern start (since I don't quite have the
- ; logic of this sucker figured out yet!).
-
- mov bx,si ;initialize saveSI
-
- mov cx,0FFFFH ;max number
- Repne Scasb
- Dec di
- Dec di
- xchg di,dx ;DI restored (first char)
- ;DX=pointer to last char
- ; AH is already 0 (possible return code)
-
- Xor cx, cx ; wildcard pointer
-
- GetPat: Lodsb ; get char from pattern
- Or al, al
- Jz ChkMore ; branch if end of pattern
-
- Cmp al, STRINGWILD ;'*'
- Je SaveStar ; branch if string wildcard
- Cmp Byte Ptr [di], 0
- Je MatchWr ; branch if at end of string
-
- Scasb ; branch if pattern char matches
- Je GetPat ; string wildcard
- Cmp Al, CHARWILD ;'?'
- Je GetPat ; ... or if char wildcard
-
- MatchAny: Dec cx
- inc dx ; restore last psn for
- mov di,dx ; string wildcard + 1
- Cmp Byte Ptr [di], 0
- Je MatchWr
- mov si,bx ; restore corresponding
- ; pattern
- Jmp Short GetPat ; ... position and loop
-
- SaveStar: Cmp Byte Ptr [si], 0
- Jz Found ; branch if end of pattern
- Mov cx, 1 ; mark this fact
- mov dx,di ;save pointer to string
- mov bx,si ;and pointer to pattern
- Jmp Short GetPat ; and loop
-
- ChkMore: Mov ah, 2 ; at least substring match
- Cmp Byte Ptr [di], 0
- Jne MatchAny ; loop if not at end of string
-
- Found: Mov ah, 1 ; true match!
-
- MatchWr: Sub ah, 1 ; done; set up flags
-
- pop dx ;restore
- pop bx
- Ret
-
- MatchW EndP
-
- ; End of routine introduced in
-
-
- ;ES:DI -> next position on formatted line
- ;zFilename is now AsciiZed
- ;mnameptr contains ptr to original or real zFilename start
- ;(paths stripped)
-
- Stuff_FileName proc near
-
- push di ;save formatted line ptr
-
- ; Now using pathflag if target filename has a path
-
- mov al,pathflag ;' ' if no paths,
- ;'+' if paths
- mov si,mnameptr ;ptr to filename start
-
- stosb ;stuff space or '+'
- mov dx,di ;name start
- add dx,8 ;bump to the dot
-
- SN_Lup: lodsb
- or al,al ;hit AsciiZ 0 yet?
- jz SN_Done ;yep
- cmp verbose,MONOSYL ;monosyllabic?
- je SN_NoDot ;ay,don't mess with '.'
- cmp al,'.' ;.typ separator?
- jnz SN_NoDot ;nope
- cmp di,dx ;where the dot should go?
- jz SN_NoDot ;yep, put it there
- mov di,dx ; bump to the dot psn
- SN_NoDot:
- stosb ;stuff in formatted line
- jmp SN_Lup
-
- SN_Done:
- pop di ;orig ptr
- add di,14 ;bump to size psn
- ret
-
- Stuff_FileName endp
-
-
- ;SUBROUTINE
- ;2 calls
-
- Stuff_FileSize proc near
- push bx ;Preserve BX! (dta ptr)
-
- add di,3 ;move to number string end
- push di ;save it (ptr to last digit)
-
- mov ax,[si]
- mov dx,[si+2]
- add ax,3FFh ;div 1024 to get Kb
- adc dx,0
- mov cl,0Ah
- shr ax,cl
- mov cl,6
- shl dx,cl
- add ax,dx
-
- mov si,0Ah
- SFS_Lup:
- xor dx,dx
- div si
- add dl,30H ;asciify
- dec di ;back up the digit pointer
- mov [di],dl ;stuff digit in buffer
- or ax,ax ;number done?
- jnz SFS_Lup ;nope
-
- pop di ;restore line buffer ptr
- add di,3 ;bump past ' / ' or ' | '
- pop bx
- ret
-
- Stuff_FileSize endp
-
-
- ;Verbose display functions
- ;Format, display single line for each member
- ;On success, return:
- ; CF clear
- ; AL = 0
- ;On error, return:
- ; CF set (because of output write fail)
- ; AL = error code
- ;Preserve BX (buffer ptr)
- ; Right before the compression style:
- ; "E" if encrypted
- ; Else blank
- ; Forgot to show our possible "extended" filename with path
- ; (via a "+" preceding the stripped filename).
- ; Worked fine for nonverbose mode, now adding for verbose mode.
- sign db ' ' ;local variable
- hundred dw 100 ; for computing percentages
-
-
- Show_Verbose proc near
-
- mov si,mnameptr ;move real member name
- ;(no paths)
- mov di,offset vname ;into formatted line
- mov al,pathflag ;' ' if no paths,
- ;'+' if paths
- stosb ;stuff '+'
- mov cx,13 ;14 spaces in field
- ; minus the path flag
- ; already stuffed
- SV_Lup:
- lodsb ;snarf char
- or al,al ;AsciiZ ending?
- jz SV_5 ;yep
- stosb
- loop SV_Lup
-
- SV_5:
- ; I don't see where we EVER loaded AH with a space!
- ; Must have lost it in one of the hacks.
- ; Replacing it again.
-
- mov al,20H
- rep stosb ;pad with spaces
-
- ; reduce the size/length to word values
-
- mov si,[bx].zUncmpSiz ; get uncompressed file size
- mov ax,[bx].zUncmpSiz[2]
-
- mov cx,[bx].zCmpSiz ;compressed size
- mov dx,[bx].zCmpSiz[2]
-
- SVL_51: or ax,ax ; big number?
- jz SV_52 ; nope, can use it
- shr ax,1 ; yup, divide by two
- rcr si,1
- shr dx,1
- rcr cx,1
- jmp SVL_51 ;loop
-
- SV_52:
- mov ax,si ; low word of actual size
- mov sign,' '
- cmp ax,cx ; arc member is larger?
- jb SV_520
- sub ax,cx ; amount saved
- jmp short SV_521
-
- SV_520:
- sub ax,cx
- neg ax
- mov sign,'-'
-
- SV_521:
- mul hundred ; to percentage
- add ax,50
-
- ; I'm thinking PK isn't doing this rounding ..
- ; our percentage figures are sometimes 1% off the PKZIP -v display.
- ; Close enough for govt work...
-
- adc dx,0 ; round up percent
- or si,si ; empty file?
- jnz SV_53
- mov ax,100
- jmp short SV_54
-
- SV_53: div si
- SV_54: cmp ax,100 ; archive fouled?
- jbe SV_55
- sub ax,ax
- SV_55:
- mov di,offset vfactor-2 ;format stowage factor
- call Asciify ;display AX
-
- mov al,sign
- mov vfactor,al
-
- ; If encrypted, stuff an 'E', else a blank
- mov di,offset vencflag ;space for "E", space
- mov ax,' E' ;assume unencrypted
- ;(AL='E',AH=' ')
- test byte ptr [bx].zBitFlag,1 ;If 0 bit is set,
- jnz SV_56 ;it's encrypted
- mov al,ah ;' ' ;blank (not encrypted)
- SV_56:
- stosw ;stuff 'E' or space,
- ;trailing space
- ;DI -> vstyle field
-
- ; Adding test to insure compression method (0..6) is in legal range
- ; (e.g., doesn't overrun our compression style table)
-
- mov si,offset zstyles ;style table start
- xor ax,ax ;clear msb
- or ax,[bx].zCmpMeth ;bring in method
- ; of compression
- jz SV_58 ;0 -> use table base
-
- ;v1.8 cmp al,6 ;max legal
- cmp al,MAXSTYLES ;max legal v1.8
- jbe SV_57 ;it's legal
- ;v1.8 mov al,7 ;' Unknown'
- mov al,MAXSTYLES+1 ;' Unknown' v1.8
- SV_57:
- mov cl,3 ; eight bytes each entry
- shl ax,cl
-
- SV_58:
- add si,ax ;table base + offset
- ;DI already points to vstyle
-
- mov cx,4 ;move as words (8 bytes)
- rep movsw
-
- mov dx,[bx].zCmpSiz[2] ;compressed size.hi
- mov ax,[bx].zCmpSiz ;compressed size
- add totuncmp,ax ;accumulate
- adc totuncmp[2],dx
- mov di,offset vsize ;format file size
- call Asciify_Long
-
- mov dx,[bx].zUncmpSiz[2] ;uncompressed size.hi
- mov ax,[bx].zUncmpSiz ;uncompressed size.lo
- add totcmp,ax ;accumulate
- adc totcmp[2],dx
- mov di,offset vlength ;format file length
- call Asciify_Long
-
- mov ax,[bx].zModDate ; format file date
- call GetDate
-
- mov ax,[bx].zModTime ; format file time
- call GetTime
-
- mov ax,[bx].zCrc32 ; format crc.lo in hex
- mov di,offset vcrc + 4
- call Cvh
- mov ax,[bx].zCrc32[2] ; format crc.hi in hex
- mov di,offset vcrc
- call Cvh
-
- inc totmbrs ;bump total file count
-
- mov dx,offset vline ;display formatted info
- mov cx,VLINELEN
- call Pr_StdOut
- ret
-
- Show_Verbose endp
-
-
- ;Formats, displays verbose totals
-
- Format_Totals proc near
-
- mov ax,totmbrs ;total members
- add ttotmbrs,ax ;accumulate
-
- ; Don't display totals for this ZIP file's members
- ; unless there's more than 1.
-
- xor bp,bp ;use BP for a flag
- ;(undisturbed by Asciify)
- ;(0 = only 1 file)
-
- cmp ax,1 ;just one?
- jbe FT_1 ;yep, no Asciify
- inc bp ;flag more than 1 file
- mov di,offset vtmbrs-2 ;format total members
- call Asciify
-
- FT_1: mov dx,totcmp[2] ;total compressed file size
- mov ax,totcmp
- add ttotcmp,ax ;accumulate total totals
- adc ttotcmp[2],dx
-
- or bp,bp ;just 1 file?
- jz FT_2 ;yep, no Asciify
- mov di,offset vtlen ;format total compressed file
- ;size
- call Asciify_Long
- FT_2:
- mov dx,totuncmp[2] ; total uncompressed file size
- mov ax,totuncmp
- add ttotuncmp,ax ;accumulate total totals
- adc ttotuncmp[2],dx
- or bp,bp ;just 1 file?
- jz FT_9 ;yep, no Asciify
- ;no fancy computations
-
- mov di,offset vtsize ;format total uncompressed
- ;file size
- call Asciify_Long
-
- ; reduce the total size/length to word values
-
- mov si,totcmp ; get compressed file size
- mov ax,totcmp[2]
- mov cx,totuncmp ; uncompressed file size
- mov dx,totuncmp[2]
-
- FTDiv: or ax,ax ; big number?
- jz FT_4 ; nope, can use it
- shr ax,1 ; yup, divide by two
- rcr si,1
- shr dx,1
- rcr cx,1
- jmp short FTDiv
-
- FT_4:
- mov ax,si
- mov sign,' ' ;whata kludge
- cmp ax,cx ;compressed > uncompressed?
- jb FT_5 ;yep
- sub ax,cx ;amount saved
- jmp short FT_6
-
- FT_5: sub ax,cx
- neg ax
- mov sign,'-'
-
- FT_6: mul hundred ; to percentage
- add ax,50
- adc dx,0 ; round up percent
- or si,si ; empty file?
- jnz FT_7
- mov ax,100
- jmp short FT_8
-
- FT_7: div si
- FT_8: mov di,offset vtsf-2 ;format stowage factor
- call Asciify ;AX
-
- mov al,sign
- mov vtsf,al
-
- FT_9:
- mov di,offset totcmp ;starting at totcmp
- mov cx,TOTLEN/2 ;length of totals to clear
- ; (words)
- xor ax,ax ;handy 0
- rep stosw
-
- or bp,bp ;just 1 file?
- jz FT_X ;yep, exit
-
- mov dx,offset vthdr ;prepare to display totals
- mov cx,VTHDRLEN ;msg length
- FT_X:
- ret ;to display
-
- Format_Totals endp
-
-
- ; format the time (in AX)
-
- time record hour:5,min:6,sec:5 ;packed time
-
- GetTime proc near ;format the date
- mov di,offset vtime
- or ax,ax ;it is zero?
- jz GotTime
-
- push ax ;save date
- and ax,mask hour ;get hour part
- mov cl,hour ;bits to shift
- shr ax,cl
- call Cnvrt1
- stosw
- mov al,':'
- stosb
-
- GT3: pop ax ;get the time back
- and ax,mask min ;get min part
- mov cl,min ;bits to shift
- call Cnvrt
- stosw
- GotTime:ret
-
- GetTime endp
-
-
- Cnvrt2 proc near ;convert to ascii
-
- call Cnvrt
- cmp al,'0' ;suppress leading zero
- jne Cnvrtd
- mov al,' '
- ret
-
- Cnvrt: shr ax,cl
- Cnvrt1: aam ;make al into bcd
- or ax,'00' ; and to ascii
- xchg al,ah
- Cnvrtd: ret
- Cnvrt2 endp
-
- page
-
- ; format the date (in AX)
-
- date record yr:7,mo:4,dy:5 ;packed date
-
- GetDate proc near ;format the date
- or ax,ax ;is it zero?
- jz GotDate
-
- push bx ;preserve BX (buff ptr)
-
- push ax ;save date
- and ax,mask yr ;get year part
- mov cl,yr ;bits to shift
- call Cnvrt
- mov di,offset vyear
- or al,'8' ;adjust for base year
- stosw
-
- pop bx ;get the date back
- push bx ;save it
- and bx,mask mo ;get month part
- mov cl,mo ;bits to shift
- shr bx,cl
- add bx,bx ; form month table index
- add bx,bx
- lea si,word ptr months-4[bx]
- mov di,offset vmonth
- movsw ;2 bytes
- movsb ;the 3rd
-
- pop ax ;get the date back
- and ax,mask dy ;get day part
- mov cl,dy ;bits to shift
- call Cnvrt
- mov di,offset vdate
- stosw
-
- pop bx ;restore buff ptr
- GotDate:ret
-
- GetDate endp
-
-
- ;A severely hacked single/double precision number conversion function.
- ;Originally from JMODEM, but severely hacked by Toad Hall.
- ;ES:DI -> string
- ;Destroys everything almost.
-
- ;Enter here if integer in AX
- Asciify proc near
-
- push bx ;save buff ptr
-
- xor dx,dx ; clear fake long.hi
- mov si,ax ;move integer into SI
- xor ah,ah ;clear msb (flag)
- jmp short Ascii_Ax ;jump into the code
-
- ;Enter here if long integer in DX:AX.
- Asciify_Long:
-
- push bx ;save buff ptr
-
- mov si,ax ;move long.lo into SI
- xor ah,ah ;clear msb (flag)
-
- Comment ~
- Taking out the extremely high numbers to reduce column width.
-
- MOV CX,3B9AH ; Get billions
- MOV BX,0CA00H
- CALL Subtr ; Subtract them out
-
- MOV CX,05F5H ; Get hundred-millions
- MOV BX,0E100H
- CALL Subtr ; Subtract them out
- Comment ends ~
-
- and dx,4FFH ;seems likely
- MOV CX,0098H ; Get ten-millions
- MOV BX,9680H
- CALL Subtr ; Subtract them out
-
- MOV CX,000FH ; Get millions
- MOV BX,4240H
- CALL Subtr ; Subtract them out
-
- MOV CX,1 ; Get hundred-thousands
- MOV BX,86A0H
- CALL Subtr ; Subtract them out
-
- Ascii_Ax:
- xor cx,cx ; Get ten-thousands
- MOV BX,2710H
- CALL Subtr ; Subtract them out
- MOV BX,03E8H
- CALL Subtr ; Subtract them out
-
- MOV BX,0064H
- CALL Subtr ; Subtract them out
- MOV BX,10
- CALL Subtr ; Subtract them out
- mov ax,si ;residual in SI
- add AL,'0' ; Add bias to residual
- stosb ; Put in the string
-
- pop bx ;restore buff ptr
- RET
-
- ;Common subroutine for Asciify
-
- Subtr: mov al,'0'-1
-
- Subtr1: INC al ; Bump the digit character
- SUB si,BX ; Dword subtraction
- SBB DX,CX
- JNB Subtr1 ; Continue until a carry
-
- ADD si,BX ; One too many, add back
- ADC DX,CX ; and the remainder
-
- cmp al,'0'
- jnz Subtr2 ;nope, turn off leading flag,
- ; stuff
- or ah,ah ;no more leading spaces?
- jnz Sub_Stuff ;right, stuff the '0'
- mov al,' ' ;make it neat
- ; with leading spaces
- Sub_Stuff:
- stosb ;stuff the char
- RET
-
- Subtr2: inc ah ;turn off leading space flag
- stosb
- ret
-
- Asciify ENDP
-
-
- ;Convert 16-bit binary word in AX
- ;to hex ASCII string at ES:DI
- ;(Protect BX, directory array pointer)
-
- hexchar db '0123456789ABCDEF'
-
- Cvh proc near
-
- push bx ;save buff ptr
-
- mov si,offset hexchar ;for faster access
- mov dx,ax ; save 16-bits
-
- mov bl,dh ; third nibble
- xor bh,bh ;clear msb
- mov cx,0F04H ;CL=4 for shifting,
- ;CH=0FH for masking
- shr bl,cl
- mov al,[si][bx] ;snarf hex char
- stosb
-
- mov bl,dh ; last nibble
- and bl,ch ;0fh
- mov al,[si][bx] ;snarf hex char
- stosb
-
- mov bl,dl ; first nibble
- shr bl,cl ; isolate (CL still 4)
- mov al,[si][bx] ;snarf hex char
- stosb
-
- mov bl,dl ; second nibble
- and bl,ch ;0fh ; isolate
- mov al,[si][bx] ;snarf hex char
- stosb
-
- pop bx ;restore buff ptr
- ret
-
- Cvh endp
-
-
- ;SUBROUTINE
-
- Pr_CrLf proc near
- mov dx,offset crlf
- mov cx,CRLFLEN ;fall through to ...
-
- Pr_CrLf endp
-
- Pr_StdOut proc near
-
- push bx ;preserve bx
- mov bx,STDOUT
- mov ah,40H ;write
- int 21H
- pop bx
- ret
-
- Pr_StdOut endp
-
-
- ;Print null-terminated (AsciiZ) string like int 21h function 9
- ;Enter with DS:DX -> AsciiZ string
- ;Destroys AX
- ;On success, return:
- ; CF clear
- ; AL = 0
- ;On failure (StdOut write fail), return:
- ; CF set
- ; AL = error
-
- PrintS proc near
-
- mov cx,0FFFFH ;max scan
- xor al,al ;handy 0
- mov di,dx ;string start
- repne scasb ;find the terminator
- inc cx ;adjust
- not cx ;CX=length
-
- call Pr_StdOut ;display to StdOut
-
- ret
-
- PrintS endp
-
-
- ;Reinit our nonverbose formatted display line
- ;Returne ES:DI -> formatted line start
- Refresh_LineBuff proc near
-
- mov si,offset blankline ;formatted display line
- mov ax,offset linebuff ;dynamic data area
- mov di,ax ;move to ...
- mov cx,LINELEN ;length
- rep movsb
- mov di,ax ;ES:DI -> formatted line start
- ret
-
- Refresh_LineBuff endp
-
-
- ;Parses cmdline for target files.
- ;If failure:
- ; Returns CF set,
- ; AL = ERRORLEVEL,
- ; DX -> error msg
- ;Adding command line switch ('-v') parsing.
- ;And '-m', too. Also accept '/' as switch char.
- ;And fixing the bug.
-
- Parse_CmdLine proc near
-
- call _Args ;parse cmdline
- ;returns AX = argc
- or ax,ax ;any argc?
- jnz Got_Parm ;yep
-
- Cmd_Err:
- mov dx,offset usage ;intro, usage
- mov cx,USAGELEN ;total length
- mov al,1 ;errorlevel 1
- stc ;CF set
- ret ;for a jmp to Msg_Term
-
- Got_Parm:
- mov cx,ax ;argc
-
- ;See if any of the argv's are our '-v' verbose switch.
- ;Or '-m'. Or '/v'. Or '/m'. Or. Or. Or.
- ;If so, turn switch on, clear that argv.
-
- cmp cx,1 ;just 1 arg?
- jz Chk_ZipName ;yep, can't be any switches
-
- mov bx,offset argv[2] ;start with ^argv(1)
-
- Chk_VSwitch:
- mov si,[bx] ;argv^(1)
- cmp byte ptr 2[si],0 ;arg longer than 2 chars?
- jnz Chk_VRelup ;yes, can't be switch
- mov ax,[si] ;snarf possible -V parm
- cmp al,'-' ;is first(!) char '-'?
- je Found_Some_Switch ;yes, check which
- cmp al,'/' ;is first(!) char '/'?
- jne Chk_VRelup ;no, cant' be switch
-
- Found_Some_Switch:
- ; We KNOW the args are upper case, because we made them so!
- mov al,VERBO ;assume it's 'v'
- cmp ah,'V' ;'V'?
- jz Found_Switch ;yep
- cmp ah,'M' ;'M'?
- jnz Chk_VRelup ;nope
- mov al,MONOSYL ;hah-it's monosyllabic
-
- Found_Switch:
- cmp byte ptr 2[si],0 ;Just the '-v'?
- jnz Chk_VRelup ;nope, must be a name
- mov verbose,al ;got switch,set verbose
- mov byte ptr [si],0 ;clear this argv
- cmp cx,argc ;first argc?
- jnz Chk_V_NoShift ;nope
- inc argc ; .. sigh .. readjust
- call _Shift ;yep, move other args down one
- ;(will decr argc again)
- Chk_V_NoShift:
- dec argc ;final decr to eliminate it
- jmp short Chk_ZipName ;done
-
- Chk_VRelup:
- add bx,2 ;next argv^
- loop Chk_VSwitch ;check all args
-
- ;If argv(1) was the '-v' switch,
- ;or that other one,
- ;that argv has been cleared via the _Shift call.
- ;The target zip file name HAS to be argv(1)!
-
- Chk_ZipName:
-
- mov cx,argc ;argc arg counter
- jcxz Cmd_Err ;he only had a switch!
-
- mov bx,offset argv[2] ;^argv(1)
- mov si,[bx] ;argv^(argc)
- call Parse_MoveZipName ;handle the zip name
- call _Shift ;move argv's down one
-
- ;Check for member testing (2d or 3d argv).
- ;We make the call even if argc = 0 (to clear a buffer)
-
- Chk_MbrName:
- mov di,offset pname1
- mov byte ptr [di], 0 ;initialize mbr name
- mov cx,argc ;argc counter
- jcxz Parse_Done ;all done, no member
-
- mov bx,offset argv[2] ;it's now ^argv(2)
- mov si,[bx] ;argv^(argc)
- Chk_MbrCopy: ;copy name to safe place
- lodsb
- stosb
- or al, al ;at end?
- jnz Chk_MbrCopy ;loop if not
-
- Parse_Done:
- clc
- ret
-
- Parse_CmdLine endp
-
- ;Cmdline parsing subroutine
- ;Moves argv into our targetfile buffer,
- ;picks up a pointer to past the paths (if any)
- ;SI -> argv
-
- Parse_MoveZipName proc near
-
- push si ;save SI
-
- mov bx,offset ziptarget ;full zip target filename
-
- mov di,bx
- mov cx,64 ;clear ziptarget
- xor ax,ax
- rep stosw
-
- mov di,bx ;DI -> ziptarget
-
- Move_ZipName:
- lodsb ;snarf cmdline char
- or al,al ;AsciiZ terminator?
- jz Skip_Zip_Path ;yep
- stosb ;stuff
- jmp Move_ZipName
-
-
- Skip_Zip_Path:
-
- ;DI -> last ziptarget's real char +1
-
- mov dx,di ;end, last char +1
- sub dx,bx ;end - start = length
-
- dec di ;adjust from last movsb
- std ;backwards
-
- mov si,di ;SI -> ziptarget last char
-
- ;BX = ziptarget start
- ;SI -> ziptarget lastchar
- ;DX = ziptarget length
- ;DI -> ziptarget lastchar
-
- ;Now find any path separators in ziptarget
-
- mov cx,dx ;scan length
- mov al,'\' ;subdir dividers
- repne scasb ;scan till we hit one
- jz Zip_GotPath ;DI -> char before the '\'
-
- mov di,si ;back to last char
- mov cx,dx ;scan length
- mov al,':' ;how about just drive?
- repne scasb
- jnz Zip_NoPath ;nope, DI -> ziptarget-1
- ;skip the extra inc
- Zip_GotPath:
- inc di ;bump to '\' or ':'
- Zip_NoPath:
- inc di ;and past it to filename's char
- cld ;forward again
- mov znameptr,di ;points to start of
- ;true filename (beyond path)
- ;for later appending Find Next
- ;filenames to path
-
- ;append type of .ZIP, if not specified. Moved here from above in
- mov dx,si ;end of file name
- mov cx,dx
- sub cx,di ;end - start = length
- inc cx ;well, nearly...
-
- mov al,'.'
- repne scasb ;find a .TYP separator
-
- ;DI -> char after '.' or actual filename end
- jz PZN_Exit ;leave .TYP alone!
- mov si,offset ziptyp ;assume need full '.ZIP'
- movsw ;copy .ZIP in
- movsw ;(4 chars)
-
- PZN_Exit:
- pop si ;restore
- ret
-
- Parse_MoveZipName endp
-
-
- Capitalize Proc Near
- ; This routine takes a pointer to an ASCIIZ string and uppercases the
- ; latter in place, taking national characters into account
-
- ; Input
- ; si - pointer to string
- ; Registers modified
- ; ax, cx, di, si
- ; National characters .. Gad! Sure do appreciate
- ; the European outlook .. we provincial New World types ...
-
- Inc si
- mov ah,20H ;handy constant
- CNextChar: Lodsb ; get next char of string
- Or al, al
- Jz CExit ; branch if at end of string
- Cmp al, 'a'
- Jb CNextChar ; skip this char if below 'a'
- Cmp al, 'z' ; if above 'z', then...
- Ja CUpperHalf ; ...test for national chars
- Sub al,ah ; 20h ; otherwise make upper case
- Jmp Short CPutChar ; branch for replacement
-
- CUpperHalf: mov cx, LowerSet-UpperSet ; number of national chars
- mov di, offset LowerSet ; pointer to lower case letters
- repne scasb ; try to find
- jne CNextChar ; loop if not found
- mov al, [di+UpperSet-LowerSet-1] ; otherwise replace
-
- CPutChar: Mov byte ptr [si-1], al ; store back
- Jmp Short CNextChar ; and loop
-
- CExit: Ret
-
- Capitalize EndP
-
-
- ;---- args.asm ----------------------------------------------------------
- ;from KEGELUNX.ARC Unix-like utils.
-
- ; Args parses the command line into a unix-style parameter array.
- ; CALL _ARGS to have it parse the cmdline.
- ; Argc and Argv are just as in C; argc = # of params on cmd line,
- ; argv is an array of pointers to strings (null terminated, of course).
- ; Because MS-DOS doesn't pass us the name used to invoke the program,
- ; argv[0] always points to a null string.
- ; _Shift updates argc.
-
- ;--------------------------------------------------------------------------
-
- ; Maximum number of parameters
- MAXPARMS equ 4
-
- _Args proc near
-
- ; initialize
- cld ; clear decrement mode
- mov bx, 2 ; argc = 0 (will sub 2 from bx at end)
- mov argv[0], offset null ; prog name unknown; set to null.
- mov si,offset params ; i = 0
- mov cl,nchar ; cx = # of chars in command line
- xor ch,ch
- jcxz Args_Done ; no arg chars -> we're done.
-
- mov di, si ; pointer to end of cmd line
- add di, cx
- mov [di+1],ch ; 0 ; ASCIIZ-ify command line
- push si ; save vitals parms
- push cx
- call Capitalize ; convert to uppercase in situ
- pop cx ; retrieve vital parms
- pop si
-
- mov di,offset argbuff ;big arg buffer
-
- ; Move arguments out of default DTA.
- push cx
- push di
- rep movsb
- pop si
- pop cx
-
- ; Big loop- find arguments...
- mov ah,20H ;handy space
- ParmL:
-
- ; Little loop #1: strip leading blanks from argument.
- ; while (i<NCHAR && params[i] = ' ') do i++;
- StripL: lodsb ; al = [si++]
- cmp al,ah ; space?
- loopz StripL ; if so, keep skipping.
- jne Args_GotOne ; If we found a nonblank,
- ; skip zero test.
- jcxz Args_Done ; found no unblank chars -> we're done.
-
- Args_GotOne:
- dec si ; bump SI back to start of nonblank.
- inc cx
- mov argv[bx],si ; save pointer to this string
-
- ; Little loop #2: skip nonblank chars.
- ; while (i<NCHAR && params[i] <> ' ') do i++;
-
- SkipL: lodsb
- cmp al,ah
- loopnz SkipL
- jz Oky
- ; Last char of line was not blank.
- inc si ; make next statement put null
- ; AFTER arg.
- Oky:
- mov byte ptr [si][-1], 0 ; put null at end of arg
- add bx,2 ; argc++
-
- jcxz Args_Done ; if we ran off end of cmdline,
- ; no more args.
-
- cmp bx, MAXPARMS*2
- jb ParmL ; loop if argc < MAXPARMS.
-
- Args_Done:
- ; All done finding parms; now share argc with caller.
- mov ax,bx
- sub ax, 2
- shr ax, 1
- mov argc,ax ;save argc
-
- ret
-
- _Args endp
-
- ;---- _Shift: --------------------------------------------
- ; Shifts %2 to %1, %3 to %2, etc. Leaves %0 alone.
- ; Works by shuffling argv[*].
-
- _Shift proc near
- cld
- mov si, offset argv[4]
- mov di, offset argv[2]
- mov cx, MAXPARMS
- rep movsw
- dec argc
- ret
- _Shift endp
-
-
- ;---- parameter count, array ----------------
- ; Pointers to up to MAXPARMS parameter strings are held here.
-
- null dw 0 ; the null string
- argc dw ?
- argv dw MAXPARMS dup (null)
-
-
- ;Dynamic variables start here.
- ;Not REAL big .. we could calculate them and release unneeded memory ..
- ;but who needs it? This ain't TSR, and the normal 64Kb required for
- ;a .COM program shouldn't stress anyone's system capacity.
-
- dta1BA equ $ ;alternate DTA
- ziptarget equ dta1BA + 42 ;up to 128 bytes
- pname1 equ ziptarget + 128 ;11-byte FCB filename + 0
- argbuff equ pname1 + 14 ;cmdline parsing buff
-
- Comment ~ Looks like:
- +filename.typ 000K / 000K +filename.typ 000K / 000K +filename.typ 000K / 000K
- Comment ends ~
- linebuff equ argbuff ;82 chars long
- dirbuff equ linebuff + 82 ;ENDOFS bytes long
-
-
- CSEG ENDS
- END Zdir