	page	74,132
	title	ZIPV - Display directory of ZIP files

; name: 	ZIPV, version 1, 7 March 1989
; copyright:	1989, for personal use only; may not be sold.
; author:	Vernon D. Buerg
;
; syntax:
;		ZIPV [filespec[.ZIP] [/p] [/b] [/c]
; where:
;    /p  pauses the display after a screen full
;    /b  suppresses display of d:\path information for bbs use
;    /c  displays ZIPfile and file comments and extra fields
;
; output:
;    - errorlevel returned:
;	0 - normal completion
;	1 - wrong DOS version
;	2 - no files found
;	3 - some invalid ZIP file(s) encountered
;
; notes:
;    - supports DOS 3 file sharing
;    - requires about 56k of memory, figure 64k for a .COM program
;    - assembled using SLR Systems OPTASM; you figure the JMPs for MASM
;    - handles self-extracting ZIP files (.EXE type)

	.xlist
print	macro	name			; display a field
	mov	dx,offset name
	call	prints
	endm

printl	macro	text			; display a literal
	local	txt,nxt
	mov	dx,offset txt
	call	prints
	jmp	nxt
txt	db	cr,lf,text
	db	stopper
nxt	equ	$
	endm

save	macro	reglist 		; save registers
	irp	reg, <reglist>
	push	reg
	endm
	endm

restore macro	reglist 		; restore registers
	irp	reg, <reglist>
	pop	reg
	endm
	endm
	.list

central_dir	struc			; from APPNOTES.TXT
cd_sig		db	02h,01h,4bh,50h ; signature
cdver_made	db	0,0		; version made by
cdver_ext	db	0,0		; version to extract
cd_flag 	db	0,0		; general purpose bit flag
cd_method	dw	0		; compression method
cd_mod_time	dw	0		; last mod time
cd_mod_date	dw	0		; last mod date
cd_crc		dw	0,0		; crc-32
cd_comp_size	dw	0,0		; compressed size
cd_true_size	dw	0,0		; uncompressed size
cd_flnm_len	dw	0		; filename length
cd_extra_len	dw	0		; extra field length
cd_comment_len	dw	0		; file comment length
cd_disk_start	dw	0		; disk number start
cd_intfile_attr dw	0		; internal file attributes
cd_extfile_attr dw	0,0		; external file attributes
cd_local_offset dw	0,0		; file offset of local header
					; variable length fields follow (boo-hiss)
central_dir	ends

cd_filename	equ	size central_dir; filename (variable size)
cd_extra	equ	size central_dir; extra field (variable size)
cd_comment	equ	size central_dir; file comment (variable size)

central_end	struc			; length 22+n
ce_sig		db	06h,05h,4bh,50h ; signature
ce_disk_number	dw	0		; number of this disk
ce_disk_start	dw	0		; disk number with central dir start
ce_disk_entries dw	0		; entries in central dir on this disk
ce_entries	dw	0		; total entries in central dir
ce_size 	dw	0,0		; size of central dir
ce_offset	dw	0,0		; offset to central dir on this disk
ce_comment_len	dw	0		; length of zipfile comment
					; variable length fields follow (nerts)
central_end	ends

ce_comment	equ	size central_end; zipfile comment (variable size)

dtantry struc				; DOS Data Transfer Area
dtarsvd db	21 dup (0)		;  reserved
dtaattr db	0			;  attribute
dtatime dw	0			;  update time
dtadate dw	0			;  update date
dtasize dw	0,0			;  size bytes (lo,hi)
dtaname db	12 dup (' ')            ;  name and ext
	db	0,13,10,255		;  stopper and print
dtantry ends

	subttl	ZIPV - Mainline routines
	page

cseg	segment public para 'CODE'
	assume	cs:cseg, ds:cseg, ss:cseg, es:cseg
	org	100h

zipv	proc	far
	jmp	start			; skip around data

	subttl	--- constants, equates and data areas
	page

bel	equ	7			; honker
bs	equ	8			; backspace
tab	equ	9			; tabski
lf	equ	10			; Line Feed
cr	equ	13			; la Carriage Return
eof	equ	26			; end of file character
stopper equ	255			; ends print strings

	db	bs,bs,bs,'   '          ; overlay entry jmp for type

usage	db	cr,lf,	 'ZIPV Version 1.07 Copyright (c) 1989 Vernon D. Buerg'
	db	cr,lf,	 'For personal use only. May not be sold.'
	db	cr,lf,lf,'  Usage:  zipv [d:][\path\]filespec[.ZIP]  [/p] [/b] [/c]'
	db	cr,lf
	db	cr,lf,	 '  Where:  /P pauses after each screenful'
	db	cr,lf,	 '          /B suppresses display of d:\path'
	db	cr,lf,	 '          /C displays comments'
	db	cr,lf,stopper,eof

errlvl	db	0			; dos error level returned
opencod db	0			; open code for share
flags	db	255			; find-first return code

options db	0			; command options
b_parm	 equ	1			; /b -bbs display option
p_parm	 equ	2			; /p -pause at screen full
c_parm	 equ	4			; /c - display comments

stkptr	dw	0			; stack pointer upon entry
ce_ptr	dw	0			; offset to central_end dir record
ce_count dw	0			; count of entries in central dir

fileptr dw	filenm			; spot after d:\path
filehdl dw	0			; file handle

ziptitl db	cr,lf,'Archive:  ',stopper

zipname db	13 dup (0),0,stopper	; ZIP file name for heading

;	display lines for verbose

vhdr	db	cr,lf
	db	cr,lf,'Name          Length    Method     SF   Size now  Mod Date    Time    CRC-32 '
dashes	db	cr,lf,'============  ========  ========  ====  ========  =========  ======  ========'
	db	stopper

vline	db	cr,lf
vname	db	14 dup (' ')
vsize	db	'       0  '            ; acutal file size
vstyle	db	'          '            ; compression method
vfactor db	' xx%  '                ; compression factor
vlength db	10 dup (' ')            ; compressed length
vdate	db	'dd '                   ; creation date
 vmonth db	'mmm '
 vyear	db	'yy  '
 vtime	db	'hh:mm   '              ; creation time
 vcrc	db	'xxxxxxxx'              ; crc in hex
	db	stopper
len_vline equ	$-vline 		; length of print line

totsf	dw	0,0			; average stowage factor
totlen	dw	0,0			; total of file lengths
totsize dw	0,0			; total of file sizes
totmbrs dw	0			; total number of files

;	final totals line

vthdr	db	cr,lf,'*total'
 vtmbrs db	'        '
 vtsize db	8 dup (' '),'  '
	db	10 dup (' ')
 vtsf	db	'   %  '
 vtlen	db	8 dup (' ')
	db	cr,lf
	db	stopper
 sign	db	' '

vtotal	db	'*total'
ctitle	db	cr,lf,'Comment:  ',stopper
cextra	db	cr,lf,'Extra:    ',stopper

styles	db	'Stored  '              ; compression method names
	db	'Shrunk  '
	db	'Reduced1'
	db	'Reduced2'
	db	'Reduced3'
	db	'Reduced4'

hundred dw	100			; for computing percentages
months	db	'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
	subttl	--- Mainline
	page

start:
	mov	sp,offset cs:stk_end	; local stack
	mov	stkptr,sp		; save for dos return

	mov	ah,30h			; get dos version
	int	21h			;
	cmp	al,2			; version 2 or later?
	jb	badver			; no, gotta quit
	cmp	al,3			; enough for share?
	jb	dos_okay		; no, open as-is
	mov	opencod,40h		; yes, add read-only

dos_okay:
	mov	bx,paras		; size of program
	mov	ah,4ah			; shrink allocated memory
	int	21h			; setblock function

	mov	di,offset filenm	; clear operands
	mov	cx,offset stk-filenm	;  and work areas
	mov	al,0			;
	rep	stosb			;

	subttl	--- gather command line parameters
	page

getparm:
	mov	si,82h			; Command tail
	sub	cx,cx			;
	or	cl,byte ptr -2[si]	; test parm length
	jz	getparms		; none, return as-is

sw1:	lodsb				; scan for switch
	cmp	al,'/'                  ;
	loopne	sw1			;
	or	cx,cx			; found one?
	jz	getparms		; no, done
	mov	byte ptr -1[si],cr	; yes, stop command line there
	jmp	sw2a			; and check next character

sw2:	lodsb				; Next character
	cmp	al,'/'                  ; Another switch?
	loopne	sw2			;
	jcxz	getparms		;

sw2a:	lodsb				; yes, get letter following
	and	al,0dfh 		; make upper case
	dec	cx			;
	jle	sw3			; missing switch

sw3:	cmp	al,'P'                  ; Pause?
	jne	sw4			;
	or	options,p_parm		;

sw4:	cmp	al,'B'                  ; BBS use
	jne	sw5			;
	or	options,b_parm		;

sw5:	cmp	al,'C'                  ; display Comments?
	jne	sw2			;
	or	options,c_parm		;
	jmp	sw2			; Try for another option

	subttl	--- Gather command operands
	page

;	copy first command line operand as ZIP selection filespec

getparms:
	mov	si,80h			; offset to command line
	sub	cx,cx			; its length
	or	cl,byte ptr [si]	; any operand?
	jnz	parm0			; no,
	print	usage			;  display usage
	jmp	zipv_exit		;   and quit

parm0:	inc	si			; point to operands
parm2:	lodsb				; strip leading blanks
	cmp	al,' '                  ;
	loope	parm2			;

	mov	di,offset filenm	; first operand target
	stosb				;
parm3:	lodsb				; copy filename
	cmp	al,cr			; end of name?
	je	parm4			;
	cmp	al,' '                  ; don't know why this is here
	je	parm4			;
	stosb				;
	loop	parm3			;
parm4:
	mov	si,offset filenm +75	; end of filename stuff
	mov	cx,76			;
	std				;
parm5:
	lodsb				;
	cmp	al,'/'                  ; funny path delimiter?
	je	parm6			;
	cmp	al,'\'                  ; normal path delimiter?
	je	parm6			;
	cmp	al,':'                  ; bumped into drive?
	je	parm6			;
	loop	parm5			;
	dec	si			;
parm6:
	cld				;
	add	si,2			; point to where filename goes
	mov	fileptr,si		; and save for later

;	add default ZIP extension if necessary

	mov	si,fileptr		; start of filespec
	mov	cx,13			;
parm10:
	lodsb				;
	cmp	al,0			; end of name?
	je	parm11			;
	cmp	al,'.'                  ; got extension?
	je	parm12			;
	loop	parm10			;
parm11:
	mov	di,si			; ptr to end of name
	dec	di			;
	mov	ax,'Z.'                 ; default extension
	stosw				;
	mov	ax,'PI'                 ;
	stosw				;
parm12:

	subttl	--- Find matching files
	page
;
;	set up next matching file name

process:
	mov	dx,offset dta		; set local dta for murkers
	mov	ah,1ah			;
	int	21h			;

	mov	dx,offset filenm	; find first matching file
	sub	cx,cx			; normal attribute
	mov	ah,4eh			;
	int	21h			;
	mov	flags,al		; indicate find-first status
	or	ax,ax			; any return code?
	jz	gotfirst		; nope, continue
	jmp	nofiles 		; yup, abort

;	set up next matching file name

gotfirst:
	mov	si,offset dta+30	; point to filename found
	mov	di,fileptr		; and overlay old name
	mov	cx,13			;
gotfirst1:
	lodsb				; next char
	stosb				;
	cmp	al,0			; end of name?
	loopne	gotfirst1		;
	mov	al,0FFh 		; append stoppers
	stosb				;

	mov	si,offset dta+30	; copy filename for heading
	mov	di,offset zipname	;
	mov	cx,13			; asciiz filename
gotfirst2:
	lodsb				; next char
	stosb				;
	cmp	al,0			; end of name?
	loopne	gotfirst2		;
	mov	al,0FFh 		; append stoppers
	stosb				;

process_loop:				; open the file
	mov	dx,offset filenm	; point to d:\path\filename
	mov	ah,3dh			; open function
	mov	al,opencod		; share parameters
	int	21h			; issue open
	jc	open_err1		; oops
	mov	filehdl,ax		; save file handle

	call	posfile 		; position and read central directory

	call	close			; release the ZIP file

	call	dispdir 		; display directory contents

getnext:
	mov	ah,4fh			; get next file name
	int	21h			;
	jc	alldone 		;
	or	ax,ax			;
	jz	gotfirst		;
alldone:
	jmp	zipv_exit		; all done

	subttl	--- Display directory entries
	page

ecount	dw	0			; entries on current disk

dispdir proc	near
	sub	ax,ax			; reset totals counters
	mov	totmbrs,ax		;
	mov	totsize,ax		;
	mov	totsize+2,ax		;
	mov	totlen,ax		;
	mov	totlen+2,ax		;
	mov	totsf,ax		;

;  display titles

	mov	ax,ce_count		; number of entries
	mov	ecount,ax		; save as line counter
	print	ziptitl 		;
	test	options,b_parm		; want short filename?
	jz	dispdir1		; no
	print	zipname 		; show short name
	jmp	dispdir2		;
dispdir1:
	print	filenm			; show full name

;  display comments

dispdir2:
	test	options,c_parm		; want them?
	jz	disp3			; no
	mov	si,ce_ptr		; offset to ce dir
	mov	cx,ce_comment_len[si]	;
	jcxz	disp3			; if none
	print	ctitle			; yes, add heading item
	lea	dx,ce_comment[si]	; point to comment
	mov	ah,40h			; write to file
	mov	bx,1			; using std out
	int	21h			;

disp3:
	print	vhdr			; show headings
	mov	bx,offset cdir		; first header in central directory
dispdir_loop:
	mov	di,offset vname 	; clear print line
	mov	cx,14			;
	mov	al, ' '                 ;
	rep	stosb			;

	call	stowage 		; compute stowage factor

disp_style:
	mov	si,cd_method[bx]	; compression method code
	mov	cl,3			;
	shl	si,cl			; time style length
	add	si,offset styles	; list of method names
	mov	di,offset vstyle	;
	mov	cx,8			;
	rep	movsb			;

disp_crc:
	mov	di,offset vcrc		; format crc-32 value
	mov	ax,cd_crc+2[bx] 	; first word
	call	cvh			;
	mov	ax,cd_crc[bx]		; second word
	call	cvh			;

	mov	ax,cd_mod_time[bx]	; last modified time
	call	gettime 		; format it

	mov	ax,cd_mod_date[bx]	; last modified date
	call	getdate 		; format it

	mov	ax,word ptr cd_true_size[bx]   ; actual file size
	mov	dx,word ptr cd_true_size+2[bx] ; high word
	add	totsize,ax		; accumulate total size
	adc	totsize[2],dx		;
	mov	si,offset vsize 	;
	call	format			;

	mov	ax,word ptr cd_comp_size[bx]   ; compressed file size
	mov	dx,word ptr cd_comp_size+2[bx] ; high word
	add	totlen,ax		; accumulate total length
	adc	totlen[2],dx		;
	mov	si,offset vlength	;
	call	format			;

	mov	cx,cd_flnm_len[bx]	; file name length
	lea	si,cd_filename[bx]	;  and offset
	mov	di,offset vname 	;   to print line
	rep	movsb			;

	inc	totmbrs 		; total files count
	print	vline			; display an entry

;  process extra field

dispdir_extra:
	test	options,c_parm		; want comments?
	jz	dispdir_next		;  no
	mov	cx,cd_extra_len[bx]	; extra field
	jcxz	dispdir_comment 	; if none
	mov	si,cx			; compute offset
	add	si,bx			;  to extra field
	add	si,cd_flnm_len[bx]	;
	print	cextra			;
	lea	dx,cd_comment[si]	; point to comment
	mov	ah,40h			; write to file
	mov	bx,1			; using std out
	int	21h			;

;  display copmment field

dispdir_comment:
	mov	cx,cd_comment_len[bx]	; comment field
	jcxz	dispdir_next		; if none
	mov	si,cx			; compute offset
	add	si,bx			;  to comments
	add	si,cd_flnm_len[bx]	;
	add	si,cd_extra_len[bx]	;
	print	ctitle			;
	lea	dx,cd_comment[si]	; point to comment
	mov	ah,40h			; write to file
	mov	bx,1			; using std out
	int	21h			;

; set-up for next entry

dispdir_next:
	mov	cx,size central_dir	; minimum cd entry size
	add	cx,cd_flnm_len[bx]	;  plus file name length
	add	cx,cd_extra_len[bx]	;   plus extra field length
	add	cx,cd_comment_len[bx]	;    plus comment field length
	add	bx,cx			;     to point to next entry
	dec	ecount			;
	jnz	dispdir_loop		; continue

	page
;
;	display totals for current file

dir_totals:
	print	dashes			; separate totals line

	mov	ax,totsize		; total file sizes
	mov	dx,totsize[2]		; high word
	mov	si,offset vtsize	;
	call	format			;

	mov	ax,totlen		; compressed file size
	mov	dx,totlen[2]		; high word
	mov	si,offset vtlen 	;
	call	format			;

	mov	ax,totmbrs		; count of members
	sub	dx,dx			;
	mov	si,offset vtmbrs-2	;
	call	format			;

	mov	cx,totlen		; compressed file size
	mov	dx,totlen[2]		; high word
	mov	bx,totsize		; actual file size
	mov	ax,totsize[2]		; high word
	call	stow_total		;

	mov	si,offset vtotal	; say *total
	mov	di,offset vthdr+2	;
	mov	cx,6			;
	rep	movsb			;

	print	vthdr			; display totals
	ret				;
dispdir endp

	subttl	--- Position file
	page
;
;	Position to end of ZIP file less central directory size

margin	dw	size central_end	; how far before ce to read

posfile proc	near			;
	mov	margin,size central_end ; how far before ce dir to point

posfile_point:
	mov	bx,filehdl		; get file handle
	mov	cx,dta.dtasize[2]	; high word of size
	mov	dx,dta.dtasize		; low word of size
	sub	dx,margin		; less size of central
	sbb	cx,0			;   directory end record
	jl	posfile_start		; if small file
	mov	ax,4200h		; move to central end directory
	int	21h			; lseek function
	jmp	read_ce 		;

posfile_start:
	mov	ax,dta.dtasize		; use file size
	mov	margin,ax		;  as amount to position
	jmp	posfile_point		;

;  read central-directory-end record

read_ce:
	mov	cx,margin		; how much to read (pos before eof)
	mov	dx,offset cde		; central end dir area
	mov	ah,3fh			;
	int	21h			;
	jc	open_err2		; failed
	cmp	ax,cx			; read it all?
	jne	open_err3		; nope

;  search end of file for cde signature

	mov	bx,offset cde+1 	; point to centerl end dir record
	mov	cx,margin		; look back this far
	sub	cx,size central_end-1	;
	add	bx,cx			;
search_loop:
	mov	si,bx			; next cde byte
	dec	bx			;
	cmp	word ptr [si],4b50h	; check signature
	jne	search_loop1		;
	cmp	word ptr 2[si],0605h	;
	je	read_cd 		; found it
search_loop1:
	loop	search_loop		; continue search
	add	margin,256		; not yet,
	jmp	posfile_point		;  back up some more

; re-position to central-directory

read_cd:
	mov	ce_ptr,si		; save pointer to c_e dir start
	mov	ax,ce_disk_entries[si]	; number of entries
	mov	ce_count,ax		;  and save for later
	mov	dx,ce_offset[si]	; offset to central directory
	mov	cx,ce_offset+2[si]	;
	mov	bx,filehdl		; get file handle
	mov	ax,4200h		; move file pointer
	int	21h			; returns dx:ax position

; read the central directory until end-of-file

	mov	bx,dta.dtasize[2]	; get file size in bx:cx
	mov	cx,dta.dtasize		;  to compute
	sub	cx,ax			;   size of
	sbb	bx,dx			;    central dir to eof
	mov	bx,filehdl		; get file handle
	mov	ah,3fh			; for reading
	mov	dx,offset cdir		; central dir end area
	int	21h			;
	jc	open_err4		; failed
	cmp	ax,cx			; read it all?
	jne	open_err5		; nope

	ret				;
posfile endp

	page
;
;	compute stowage; reduce the size/length to word values

stowage proc	near			; compute stowage factor
	push	bx			; save dir pointer

	mov	cx,word ptr cd_comp_size[bx]	 ; compressed file size
	mov	dx,word ptr cd_comp_size+2[bx]	 ; high word

	mov	ax,word ptr cd_true_size+2[bx]	 ; high word
	mov	bx,word ptr cd_true_size[bx]	 ; actual file size
	mov	si,offset vfactor-5	; target area
	jmp	stow51			;

stow_total:
	push	bx			; entry for totals calculation
	mov	si,offset vtsf-5	; target area

stow51: or	ax,ax			; big number?
	jz	stow52			; nope, can use it
	shr	ax,1			; yup, divide by two
	rcr	bx,1			;
	shr	dx,1			;
	rcr	cx,1			;
	jmp	stow51			;

stow52:
	mov	ax,bx			; low word of actual size
	mov	sign,' '                ;
	cmp	ax,cx			; zip member is larger?
	jb	stow520 		;
	sub	ax,cx			; amount saved
	jmp	stow56			;
stow520:
	sub	ax,cx			;
	neg	ax			;
	mov	sign,'-'                ;
stow56:
	mul	hundred 		; to percentage
	add	ax,50			;
	adc	dx,0			; round up percent
	or	bx,bx			; empty file?
	jnz	stow53			;
	mov	ax,100			;
	jmp	stow54			;

stow53: div	bx			;
stow54: sub	dx,dx			;
	cmp	ax,100			; archive fouled?
	jbe	stow55			;
	sub	ax,ax			;
stow55:
	call	format			;
	mov	al,sign 		; get + or -
	mov	byte ptr [si],al	;
	pop	bx			; restore dir pointer
	ret				; return to caller
stowage endp				;

	subttl	--- subroutines
	page
;
;	close the file

close	proc	near			;
	mov	bx,filehdl		; file handle
	or	bx,bx			; is it open
	jz	close_done		;
	mov	ah,3eh			; close function
	int	21h			;
	sub	bx,bx			;
close_done:
	mov	filehdl,bx		; indicate closed
	ret				;
close	endp				;

	page
;
;	print string like int 21h function 9

pause	db	cr,lf,'... more?$'
backup	db	cr,9 dup (8),'$'
linecnt db	0		; line counter for pause
pagecnt db	23		; lines per screen

prints	proc	near			; dx has offset to string

	test	options,p_parm		; want pausing?
	jz	ps1			; no, skip next

	save	<bx,cx,dx,si>		; save work regs
	mov	al,linecnt		;
	cmp	al,pagecnt		; end of screen?
	jbe	ps0			; not yet
	mov	dx,offset pause 	; yup, say so
	mov	ah,9			;
	int	21h			;
	mov	ah,0			; get a key
	int	16h			;
	mov	dx,offset backup	; over write pause prompt
	mov	ah,9			;
	int	21h			;
	mov	linecnt,0		; reset line counter
ps0:	restore <si,dx,cx,bx>		; restore work regs

ps1:	save	<si,bx,cx>		; save work regs
	mov	si,dx			;
	sub	cx,cx			;
ps2:	lodsb				;
	cmp	al,stopper		; ending hex ff?
	je	ps8			;
	inc	cx			; incr text length
	cmp	al,lf			; another line?
	jne	ps2			;
	inc	linecnt 		;
	jmp	ps2			;

ps8:	mov	ah,40h			; write to file
	mov	bx,1			; using std out
	int	21h			;

ps9:	restore <cx,bx,si>		; recover registers
	ret				;
prints	endp

	page
;
;	format the time

time	record	hour:5,min:6,sec:5	; packed time

gettime proc	near			; format the date
	mov	di,offset vtime 	;
	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

cnvrt	proc	near			; convert to ascii
	shr	ax,cl			;
cnvrt1: aam				; make al into bcd
	or	ax,'00'                 ; and to ascii
	xchg	al,ah			;
cnvrtd: ret				;
cnvrt	endp

	page
;
;	format the date

date	record	yr:7,mo:4,dy:5		; packed date

getdate proc	near			; format the date
	push	bx			; save cd pointer
	or	ax,ax			; is it zero?
	jz	gotdate 		;
	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	cx,3			;
	mov	di,offset vmonth	;
	rep	movsb			;

	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				;
gotdate:				;
	pop	bx			; restore cd pointer
	ret				; back to caller
getdate endp

	page
;
;	 format 4-byte binary into ASCII for display

ddptr	dw	0			;

format	proc	near			; formats a 32 bit integer in dx:ax
	save	<bp,bx,di,si>		;  to ds:si
	mov	ddptr,si		; addr of target field
	mov	di,dx			; routine uses di:si
	mov	si,ax			;
	call	printdd 		;
	restore <si,di,bx,bp>		;
	ret				;

printdd:
	xor	ax,ax			; zero out the
	mov	bx,ax			; working
	mov	bp,ax			; registers.
	mov	cx,32			; # bits of precision
j1:	shl	si,1			;
	rcl	di,1			;
	xchg	bp,ax			;
	call	j6			;
	xchg	bp,ax			;
	xchg	bx,ax			;
	call	j6			;
	xchg	bx,ax			;
	adc	al,0			;
	loop	j1			;
	mov	cx,1710h		;
	mov	ax,bx			;
	call	j2			;
	mov	ax,bp			;
j2:	push	ax			;
	mov	dl,ah			;
	call	j3			;
	pop	dx			;
j3:	mov	dh,dl			;
	shr	dl,1			; move high
	shr	dl,1			;  nibble to
	shr	dl,1			;   the low
	shr	dl,1			;    position
	call	j4			;
	mov	dl,dh			;
j4:	and	dl,0fh			; mask low nibble
	jz	j5			; if not zero
	mov	cl,0			;
j5:	dec	ch			;
	and	cl,ch			;
	or	dl,'0'                  ; fold in ascii zero
	sub	dl,cl			;
	mov	bx,ddptr		;
	mov	[bx],dl 		; ptr to next target field
	inc	ddptr			;
	ret				;

j6:	adc	al,al			;
	daa				;
	xchg	al,ah			;
	adc	al,al			;
	daa				;
	xchg	al,ah			;
	ret				;
format	endp

	page
;
;	convert binary word to two hex characters

hexchar db	'0123456789ABCDEF'      ; for conversion

cvh	proc	near			; convert 16-bit binary word in ax
	save	<bx,cx,dx>		; to hex ASCII string at ds:di
	sub	bx,bx			;
	mov	dx,ax			; save 16-bits

	mov	bl,dh			; third nibble
	mov	cl,4			;
	shr	bl,cl			;
	mov	al,hexchar[bx]		;
	stosb				;

	mov	bl,dh			; last nibble
	and	bl,0fh			;
	mov	al,hexchar[bx]		;
	stosb				;

	mov	bl,dl			; first nibble
	mov	cl,4			;
	sub	bh,bh			;
	shr	bl,cl			; isolate
	mov	al,hexchar[bx]		;
	stosb				;

	mov	bl,dl			; second nibble
	and	bl,0fh			; isolate
	mov	al,hexchar[bx]		;
	stosb				;
	restore <dx,cx,bx>		; restore registers
	ret				; return

cvh	endp

	subttl	--- Errors and exits
	page
;
;	error messages and exits

errmsg	db	cr,lf,"ERROR! ",bel,stopper
errmsg1 db	"Unable to open ",stopper
errmsg2 db	"Reading central end directory: ",stopper
errmsg3 db	"Central end directory incomplete: ",stopper
errmsg4 db	"Reading central directory: ",stopper
errmsg5 db	"Central directory incomplete: ",stopper

open_err1:
	mov	dx,offset errmsg1	; display message
	jmp	zipv_error		;   and quit

open_err2:
	mov	dx,offset errmsg2	; display message
	jmp	zipv_error		;   and quit

open_err3:
	mov	dx,offset errmsg3	; display message
	jmp	zipv_error		;   and quit

open_err4:
	mov	dx,offset errmsg4	; display message
	jmp	zipv_error		;   and quit

open_err5:
	mov	dx,offset errmsg5	; display message
	jmp	zipv_error		;   and quit

nofiles:
	printl	'No file(s) found '     ; display message
	mov	errlvl,2		; set return code
	jmp	zipv_exit		;   and quit

badver:
	printl	"DOS 2.0 or later is required."
	mov	errlvl,1		; set return code
	jmp	zipv_exit		;   and quit

zipv_error:
	mov	sp,cs:stkptr		; insure stack pointer
	mov	errlvl,3		; return error code
	push	dx			;
	print	errmsg			; make some noise
	pop	dx			;
	call	prints			; display error message
	print	filenm			;  with file name
	cmp	flags,255		; processed any files?
	jne	getnext 		; yes, try some more

zipv_exit:
	mov	sp,cs:stkptr		; insure stack pointer
	mov	al,errlvl		; get error level
	mov	ah,4ch			; exit
	int	21h			;

	subttl	--- data areas
	page

filenm	equ	$			; command line filespec supplied

dta	equ	filenm+80		; dos data transfer area

cde	equ	dta+48			; central directory end record
					; with room for 8k of comments
cdir	equ	cde+(size central_end)+(8*1024) ; central directory

stk	equ	cdir+ (52*1024) 	; and what's left as room for comments

stk_end equ	stk+256 		; local stack

paras	equ	(stk_end+256-cseg)/16	; paragraphs in module

zipv	endp
	end	zipv
