;***********************************************
;	sfx_.asm -- self-extract module
;***********************************************

page	0, 128
include	amscls.inc

$_init GEN

_TEXT	segment byte public 'CODE'
_TEXT	ends

DGROUP	group	_BSS
		assume	cs:_TEXT, ds:DGROUP

CRC16			equ		0a001h
BufSiz			equ		04000h

NC			=		(200h - 2)
NP			=		14
NT			=		19
NPT			=		080h

CBIT		=		9
PBIT		=		4
TBIT		=		5

DSIZ		=		2000h
DSIZ2		=		DSIZ * 2

LzHead	struc
		HeadSiz db		?
		HeadChk db		?
		HeadID	db		3 dup (?)
		Method	db		?
				db		?
		PacSiz	dw		2 dup (?)
		OrgSiz	dw		2 dup (?)
		FTime	dw		?
		FDate	dw		?
		FAttr	dw		?
		FnLen	db		?
		Fname	db		80h dup (?)
LzHead	ends

_BSS	segment para public 'BSS'
		public	crctbl
		public	cpyhdr, infile, outfile
		public	inpptr, inpbuf, text_
		public	curcrc, orgcrc
		public	myname
		public	pathname, fnnext, swchar
		public	blocksize_

text_			db		DSIZ2 dup (?)
inpbuf			db		BufSiz dup (?)
crctbl			dw		100h dup (?)
cpyhdr			LzHead	1 dup (<?>)
inpptr			dw		1 dup (?)
infile			dw		1 dup (?)
outfile			dw		1 dup (?)
orgcrc			dw		1 dup (?)
curcrc			dw		1 dup (?)
blocksize_		dw		1 dup (?)

len_cnt			dw		17 dup (?)
start			dw		17 dup (?)
weight			dw		17 dup (?)

public	len_cnt
public	start
public	weight


left_			dw		2 * NC - 1 dup (?)
right_			dw		2 * NC - 1 dup (?)

c_table_		dw		4096 dup (?)
pt_table_		dw		256 dup (?)
c_len_			db		NC dup (?)
pt_len_			db		NPT dup (?)

public	left_
public	right_
public	c_table_
public	pt_table_
public	c_len_
public	pt_len_

bitbuf_			dw		1 dup (?)
subbitbuf_		db		1 dup (?)
bitcount_		db		1 dup (?)

myname			db		80h dup (?)
pathname		db		80h dup (?)
fnnext			dw		1 dup (?)
fnptr			dw		1 dup (?)
swchar			db		1 dup (?)
endBBS			label	byte
_BSS			ends

_TEXT	segment byte public 'CODE'
		assume	cs:_TEXT

		org		0100h

		public	start, main
		public	BSSseg
		public	#cright, crlf, space
		public	absent, #myself, broken, extend
		public	#subver

top:
		jmp		main

BSSseg	=		(#endofcode - top + 10fh) / 10h
mes_yn	equ		space - 1
space	db		' ', 0
#cright	db		"LHA's SFX 2.11"
#subver	db		"L (c) Yoshi, 1991"
crlf	db		13, 10, 0
absent	db		'Rename to '
#myself	db		'FILENAME.EXT', 0
overwt	db		'Overwrite ', 0
yesno	db		'[Y/N] ', 0
broken	db		'Broken file ', 0
write	db		'Write', 0
header	db		'Header', 0
crcmes	db		'CRC'
error	db		' Error', 0
auto	db		1, '!'
autoflg db		'.' shr 1
		db		'BAT'
extend	db		0ffh
attrib	db		0

envseg	=		002ch
cmdcnt	=		0080h
cmdline =		0081h

;-----------------------------------------------
;		メインルーチン
;-----------------------------------------------
main:
		cld
		mov		sp, offset top
		mov		ax, cs
		add		ax, BSSseg
		mov		es, ax

		assume	es:DGROUP

		call	@getopt

		public	#getopt
#getopt:
		mov		bx, offset #cright
		call	mesout
		push	es
		pop		ds

		assume	ds:DGROUP
;-----------------------------------------------
;		Get my name
;-----------------------------------------------
		mov		ah, 30h
		int		21h								; get DOS ver.
		mov		bx, ax
		push	ds
		$_if <cmp al, 3>, AE					; if DOS ver. >= 3.00
			mov		es, ss:[envseg]
			xor		ax, ax
			mov		di, ax
			mov		cx, -1
			$_do
				repne	scasb
				scasb
			$_until , E
			inc		ax
			scasw
			push	es
			pop		ds
			mov		dx, di
			$_if , E
				call	openme
			$_endif
		$_endif
brknenv:
		push	cs
		pop		ds
		mov		dx, offset #myself
		call	openme
		$_if <cmp bl, 2>, E					; if DOS ver. = 2
			mov		ax, ss:[0002h]			;  get pathname from trash
			sub		ax, 38h					;  of command.com
			mov		ds, ax
			mov		dx, 0009h
			call	openme
		$_endif
		mov		bx, offset absent
		jmp		errout1
openme:
		mov		ax, 3d00h
		int		21h								; Open Myself
		$_if , C
			ret
		$_endif
		pop		cx								; pop old ip

		pop		ds
		mov		infile, ax

		mov		bx, ax
		xor		cx, cx

ifndef COM
	exehdr	=		20h
else
	exehdr	=		0h
endif

		mov		dx, (#endofcode - top) + exehdr

		public	#seeksize
#seeksize:

		mov		ax, 4200h
		int		21h								; Move a File Pointer
		$_if , C
brokenerr:
			mov		bx, offset broken		; Broken file
			jmp		errout
		$_endif
		push	ds
		pop		es
;---------------------------------------
;		make CRC table
;---------------------------------------
		mov		di, offset crctbl
		xor		dx, dx
		$_do
			mov		ax, dx
			mov		cx, 8
			$_do
				$_if <shr ax, 1>, C
					xor		ax, CRC16
				$_endif
			$_until <LOOP>
			stosw
		$_until <inc dl>, Z
;---------------------------------------

		public mainloop
mainloop:
		$_while <TRUE>

			call	crlfout
; Get Header ---------------------------
			mov		si, offset DGROUP:cpyhdr.HeadSiz
			mov		dx, si
			mov		cx, 1
			mov		[si], ch
			mov		bx, infile
			mov		ah, 3fh
			int		21h						; Read header size
			dec		cx						; cx = 0
			add		cl, [si]
			$_if , Z
				jmp		exit
			$_endif
			inc		dx
			inc		si

			inc		cx
			mov		ah, 3fh
			int		21h						; Read header

; Test Header Sum ----------------------
			lodsb
			push	si					; cpyhdr.HeadID
			dec		cx
			dec		si
			$_do
				inc		si
				sub		al, [si]
			$_until <LOOP>
			jne		errhdr
			pop		si

; Test Header ID -----------------------
			lodsw
			$_if <cmp ax, 'l-'>, NE, OR
				lodsw
				xchg	al, ah
				sub		ax, 'h0'
				mov		bp, ax				; bp = method
			$_c                 , NZ, AND
			$_c  <sub ax, 0004h>, NE, AND
			$_c  <dec ax>       , NE, OR
				lodsb
			$_c  <sub al, '-'>, NZ
errhdr:
				mov		bx, offset header
				jmp		errout
			$_endif

; Get original CRC ---------------------
			mov		bx, offset DGROUP:cpyhdr.Fname
			mov		dx, bx
			mov		cx, [bx - 1]
			add		bl, cl				; doesn't carry up

			xchg	ax, [bx]			; ax = 0, [bx] = CRC
			mov		orgcrc, ax

; Test Special File ? ------------------
			mov		fnptr, dx
			cmp		cx, 2101h				; 01h, '!'
			$_if , E
				mov		ax, 1
				jmp		mn7
			$_endif

			call	@extended

		public	#extended
#extended:


; Display File name --------------------
			mov		word ptr [bx], 0 * 256 + ' '
			mov		bx, dx
			call	disp					; output file name
			mov		byte ptr [bx - 1], 0

			jcxz	mn9						; !.BAT ?

; Check Existence of File --------------
			mov		ax, 4300h				; get file attr
			int		21h						;	(for MS-DOS 3.3)
			jc		mn1

; Overwrite ? --------------------------
			mov		bx, offset overwt	; prompt
			call	mesout
			call	getyn
			je		mn1

; Skip to next File --------------------
			mov		dx, DGROUP:cpyhdr.PacSiz		; skip file
			mov		cx, DGROUP:cpyhdr.PacSiz + 2

			mov		bx, infile
			mov		ax, 4201h
			int		21h					; Move a File Pointer
			jmp		mn6
mn9:
			mov		cs:autoflg, 0dh

; Create a New File --------------------
mn1:
			mov		cx, 0020h
			mov		ah, 3ch
			int		21h					; Create a File
			$_if , C
				jmp		errwrite
			$_endif

; Decode -------------------------------
mn7:
			mov		outfile, ax

			xor		ax, ax
			mov		curcrc, ax
			dec		ax
			mov		inpptr, ax

			push	dx
			$_if <or bp, bp>, NZ
				call	decode
			$_else
				call	copyall
			$_endif
			pop		si

; Set Time-Stamp -----------------------
			mov		bx, outfile
			cmp		bx, 1					; file '!' ?
			je		mn8

			mov		dx, DGROUP:cpyhdr.FDate
			mov		cx, DGROUP:cpyhdr.FTime
			mov		ax, 5701h				; set date
			int		21h
			call	close

; Check CRC ----------------------------
			mov		ax, curcrc
			cmp		ax, orgcrc
			jne		errcrc

			call	@setattr

public	#setattr
#setattr:


			jmp		mn6
mn8:
			call	getyn
			jne		exit1
mn6:
		$_enddo
		mov		bx, infile
		call	close

		public	exit
exit:
		call	@autoexec

		public	#autoexec
#autoexec:
exit1:
		xor		al, al
exit2:
		mov		ah, 4ch
		int		21h

;-----------------------------------------------
;		エラー処理
;-----------------------------------------------
		public	errhdr, errwrite, errout
errcrc:
		call	unlink
		mov		bx, offset crcmes
		jmp		short errout1

errwrite:
		mov		bx, outfile
		call	close
		call	unlink
		mov		bx, offset write

errout:
		call	mesout
		mov		bx, offset error
errout1:
		call	mesout
		mov		al, 1
		jmp		exit2

;-----------------------------------------------
;		get 'Y' or 'N'
;-----------------------------------------------
		public	getyn
getyn	proc	near
		mov		bx, offset yesno				; prompt
		call	mesout
		$_do
			mov		ah, 08h
			int		21h
			and		al, 0dfh
		$_until <cmp al, 'Y'>, E, OR
		$_c		<cmp al, 'N'>, E
		mov		bx, offset mes_yn
		mov		cs:[bx], al
		call	mesout
		cmp		al, 'Y'
		ret
getyn	endp

;-----------------------------------------------
;		バッファの出力
;-----------------------------------------------
		public	putbuf
		public	putbuf2
putbuf	proc	near
	xor		dx, dx	;	mov		dx, offset DGROUP:text_
	mov		cx, di
	sub		cx, dx
putbuf2:
	jcxz	return
	mov		bx, outfile
	mov		ah, 40h
	int		21h
	$_if <sub ax, cx>, NE
		cmp		bx, 1
		jne		errwrite
	$_endif
calccrc:
	mov		si, dx
	mov		bx, curcrc
;	xor		ah, ah						; ah = 0
;	cld
	$_do
		lodsb
		xor		bl, al
		mov		al, bh
		mov		bh, ah
		shl		bx, 1
		mov		bx, crctbl[bx]
		xor		bx, ax
	$_until <LOOP>
	mov		curcrc, bx
	mov		di, dx

	cmp		outfile, 1
	je		return
	mov		ah, 02h
	mov		dl, '.'
	jmp		short int21_ret					; int	21h
											; ret
putbuf	endp

;-----------------------------------------------
;		そのまま出力
;-----------------------------------------------
		public	copyall
copyall proc	near
		xor		di, di
		$_while <TRUE>
				mov		bx, offset DGROUP:cpyhdr.OrgSiz
				sub		[bx], di
				sbb		word ptr 2[bx], 0
				mov		cx, DSIZ2
				$_if , Z, AND
						mov		ax, [bx]
						or		ax, ax
						jz		cpyend
				$_c	 <cmp ax, cx>, B
						mov		cx, ax
				$_endif

				xor		dx, dx	;	mov		dx, offset DGROUP:text_
				mov		bx, infile
				mov		ah, 3fh
				int		21h
				push	cx
				call	putbuf2
				pop		di
		$_enddo
cpyend:
		ret
copyall endp

;-----------------------------------------------
;		ファイルの close
;-----------------------------------------------
		public	close
close	proc	near
		mov		ah, 3eh
		jmp		short int21_ret					; int	21h
												; ret
close	endp

;-----------------------------------------------
;		ファイルの削除
;-----------------------------------------------
		public	unlink
unlink	proc	near
		mov		dx, fnptr
		mov		ah, 41h							; unlink
int21_ret:
		int		21h
return:
		ret
unlink	endp

;-----------------------------------------------
;		CR, LF の出力
;-----------------------------------------------
crlfout	proc	near
		mov		bx, offset crlf
crlfout	endp
;-----------------------------------------------
;		メッセージの出力
;-----------------------------------------------
		public	mesout
mesout	proc	near
		push	ds
		push	cs
		pop		ds
		call	disp
		pop		ds
		ret
mesout	endp

;-----------------------------------------------
;		display ASCIZ char
;-----------------------------------------------
		public	disp
disp	proc	near
		push	ax
		push	dx
		$_do
			mov		dl, [bx]
			inc		bx
			mov		ah, 02h
			int		21h
		$_until <cmp byte ptr [bx], 0>, E
		pop		dx
		pop		ax
		ret
disp	endp

;-----------------------------------------------
;		getc
;			ax: 1 byte (return)
;-----------------------------------------------
		public	getc
getc	proc	near
		mov		bx, inpptr
		$_if <cmp bx, offset inpbuf + BufSiz>, AE
	;-----------------------------------------------
	;		buffer 入力
	;-----------------------------------------------
			public	getbuf
	getbuf	proc	near
			push	cx
			push	dx
			mov		dx, offset DGROUP:inpbuf
			mov		cx, BufSiz
			mov		bx, offset DGROUP:cpyhdr.PacSiz
			sub		[bx], cx
			sbb		word ptr 2[bx], 0
			$_if , C
				add		cx, [bx]
			$_endif
			mov		bx, infile
			mov		ah, 3fh
			int		21h					; Read from an Archive
			mov		bx, dx
			pop		dx
			pop		cx
	getbuf	endp
	;-----------------------------------------------
		$_endif
		mov		al, [bx]
		inc		bx
		mov		inpptr, bx
		ret
getc	endp

;-----------------------------------------------
;		extract routines
;-----------------------------------------------
		public	decode
decode proc	near
	xor		ax, ax
	mov		blocksize_, ax
	mov		bitbuf_, ax
	mov		subbitbuf_, al
	mov		bitcount_, al

	mov		al,16
	call	fillbuf_

	xor		di, di	;	mov		di, offset DGROUP:text_
	jmp		$entry

$loop:
		call	decode_c_st1_
		$_if <or ah, ah>, Z
			stosb
			$_if <cmp di, offset DGROUP:text_[DSIZ2]>, E
				call	putbuf
			$_endif
$entry:
			sub		word ptr cpyhdr.OrgSiz, 1
			jnc		$loop
		$_else
			mov		cx, ax
			sub		cx, 100h - 3
			call	decode_p_st1_
			mov		si, di
			stc
			sbb		si, ax
			push	cx
			$_do
				and		si, DSIZ2 - 1
				movsb
				test	di, DSIZ2
				$_if , NZ
					push	cx
					push	si
					call	putbuf
					pop		si
					pop		cx
				$_endif
			$_until <LOOP>
			pop		cx
			sub		word ptr cpyhdr.OrgSiz, cx
			jnc		$loop
		$_endif
		sbb		word ptr cpyhdr.OrgSiz + 2, 0
		jnc		$loop
	$endloop:
	jmp		putbuf
decode endp


;	static void read_pt_len(short nn, short nbit, short i_special)
;public	read_pt_len_
read_pt_len_	proc	near
	push	si
	mov		al, dl
	call	getbits_
	$_if <cmp ax, si>, A
		jmp		brokenerr
	$_endif
	mov		di, offset DGROUP:pt_len_
	$_if <or ax, ax>, Z
		pop		cx
		rep		stosb
		mov		al, dl
		call	getbits_
		mov		cx, 256
		mov		di, offset DGROUP:pt_table_
		rep		stosw
		ret
	$_else
		mov		dx, cx			; dl = i_special
		add		dx, di
		mov		si, di
		add		si, ax			; ax = n
		$_do
			mov		al, 3
			call	getbits_
			$_if <cmp al, 7>, E
				mov		bx, bitbuf_
				$_while <shl bx, 1>, C
					inc		ax
				$_enddo
				push	ax
				sub		al, 6
				call	fillbuf_
				pop		ax
			$_endif
			stosb
			$_if <cmp di, dx>, E
				mov		al, 2
				call	getbits_
				mov		cx, ax
				xor		al, al
				rep		stosb
			$_endif
		$_until <cmp di, si>, AE
		pop		si						; nn
		mov		bp, offset DGROUP:pt_len_
		lea		cx, [bp + si]	;	lea		cx, DGROUP:pt_len_[si]
		sub		cx, di
		xor		al, al
		rep		stosb
		mov		ax, si
		mov		cx, 8
		mov		di, offset DGROUP:pt_table_
		jmp		make_table_
	$_endif
read_pt_len_	endp

;	static void read_c_len(void)
;public	read_c_len_
read_c_len_	proc	near
	mov		al, CBIT
	call	getbits_
	$_if <cmp ax, NC>, A
		jmp		brokenerr
	$_endif
	mov		di, offset DGROUP:c_len_
	$_if <or ax, ax>, Z
		mov		cx, NC
		rep		stosb
		mov		al, CBIT
		call	getbits_
		mov		cx, 4096
		mov		di, offset DGROUP:c_table_
		rep		stosw
		ret
	$_else
		mov		dx, di
		add		dx, ax			; ax = n
		push	di
		$_do
			mov		ax, bitbuf_
			mov		bl, ah
			xor		bh, bh
			shl		bx, 1
			mov		bx, pt_table_[bx]

			mov		si, offset read_c_len_1
			mov		cx, NT
			jmp		tree1

if 0
			$_while <cmp bx, NT>, AE
				$_if <shl al, 1>, C
					mov		bx, right_[bx]
				$_else
					mov		bx, left_[bx]
				$_endif
			$_enddo
endif

read_c_len_1:
			push	bx
			mov		al, pt_len_[bx]
			call	fillbuf_
			pop		ax
			$_if <sub ax, 2>, BE
				$_if , Z
					mov		al, CBIT
					call	getbits_
					add		ax, 20
					mov		cx, ax
				$_else
					$_if <inc ax>, Z
						mov		al, 4
						call	getbits_
						add		ax, 3
						mov		cx, ax
					$_else
						mov		cx, 1
					$_endif
				$_endif
				xor		al, al
				rep		stosb
			$_else
				stosb
			$_endif
		$_until <cmp di, dx>, AE
		mov		cx, offset DGROUP:c_len_ + NC
		sub		cx, di
		xor		al, al
		rep		stosb
		mov		ax, NC
		pop		bp
		mov		cx, 12
		mov		di, offset DGROUP:c_table_
		jmp		make_table_
	$_endif
read_c_len_	endp

;	ushort decode_c_st1(void)
decode_c	proc	near
;	not entry here
decode_c_st1_2:
	push	di
	mov		al, 16
	call	getbits_
	dec		ax
	mov		blocksize_, ax
	mov		si, NT
	mov		dl, TBIT
	mov		cx, 3
	call	read_pt_len_
	call	read_c_len_
	mov		si, NP
	mov		dl, PBIT
	mov		cx, -1
	call	read_pt_len_
	pop		di
	jmp		decode_c_st1_3
;
;	entry here
;
public	decode_c_st1_
decode_c_st1_:
	sub		blocksize_, 1
	jc		decode_c_st1_2
decode_c_st1_3:
	mov		bx, bitbuf_
	mov		cl, 4
	shr		bx, cl
	shl		bx, 1
	mov		bx, c_table_[bx]
	$_if	<cmp bx, NC>, B
decode_c_st1_1:
		push	bx
		mov		al, c_len_[bx]
		call	fillbuf_
		pop		ax
		ret
	$_endif
	mov		ax, bitbuf_
	shl		al, cl
	mov		si, offset decode_c_st1_1
	mov		cx, NC
tree0:
	$_do
		$_if <shl al, 1>, C
			mov		bx, right_[bx]
		$_else
			mov		bx, left_[bx]
		$_endif
tree1:
	$_until <cmp bx, cx>, B
	jmp		si
decode_c	endp

;	ushort decode_p_st1(void)
public	decode_p_st1_
decode_p_st1_	proc	near
;---------------------------------------------------------------
;	ushort decode_p_st1(void)
;---------------------------------------------------------------
	push	cx
	xor		bh, bh
	mov		bl, byte ptr bitbuf_ + 1
	shl		bx, 1
	mov		bx, pt_table_[bx]
	$_if	<cmp bx, NP>, B
decode_p_st1_1:
		push	bx
		mov		al, pt_len_[bx]
		call	fillbuf_
		pop		ax
		$_if <cmp al, 1>, A
			dec		ax
			mov		cx, ax
			call	getbits_
			mov		bx, 1
			shl		bx, cl
			or		ax, bx
		$_endif
		pop		cx
		ret
	$_endif
	mov		al, byte ptr bitbuf_
	mov		si, offset decode_p_st1_1
	mov		cx, NP
	jmp		tree0

if 0
	$_do
		$_if <shl al, 1>, C
			mov		bx, right_[bx]
		$_else
			mov		bx, left_[bx]
		$_endif
	$_until <cmp bx, NP>, B
	jmp		decode_p_st1_1
endif
decode_p_st1_	endp


;---------------------------------------------------------------
;	void make_table(short nchar, uchar bitlen[],
;	                         ax            bp
;					short tablebits, ushort table[])
;	                             cx            di
;---------------------------------------------------------------
_BSS	segment para public 'BSS'
avail_mt		dw		1 dup (?)
nchar			dw		1 dup (?)
bitlen			dw		1 dup (?)
tablebits		dw		1 dup (?)
table			dw		1 dup (?)
restbits		db		1 dup (?)

public	avail_mt
public	nchar
public	bitlen
public	tablebits
public	table
public	restbits
_BSS	ends

	public	make_table_
make_table_	proc	near
	mov		nchar, ax
	shl		ax, 1
	mov		avail_mt, ax
	mov		tablebits, cx
	mov		table, di
	mov		al, 16
	sub		al, cl
	mov		restbits, al

	mov		ax, 1
	shl		ax, cl
	mov		cx, ax
	xor		ax, ax
	rep		stosw

	xor		si, si
	mov		bx, 8000h
	mov		dx, 1
	$_do
		mov		di, bp
		mov		cx, nchar
		$_do
			mov		al, dl
			repne	scasb
			jne		mt1
			mov		ax, di
			sub		ax, bp
			dec		ax
			push	cx
			push	di
;			; bx = weight
;			; si = code
;			; dx = len
			mov		cl, restbits
			mov		di, si
			shr		di, cl
			shl		di, 1
			add		di, table
			push	bx
			$_if <cmp dx, tablebits>, BE
				shr		bx, cl
				mov		cx, bx
				rep		stosw
			$_else
;		/* 高さ n の tree を作る */
;				; di = taddr
;				; si = 
;				; cx = 
;				; ax = char
				push	si
				mov		cx, tablebits
				shl		si, cl
				neg		cx
				add		cx, dx
				$_do
					$_if <cmp word ptr [di], 0>, E
;				/* 枝がまだ延びていなければ作る */
						mov		bx, avail_mt
						mov		right_[bx], 0
						mov		left_[bx], 0
						mov		[di], bx
						add		avail_mt, 2
					$_endif
					mov		di, [di]
					$_if <shl si, 1>, C
						add		di, offset DGROUP:right_
					$_else
						add		di, offset DGROUP:left_
					$_endif
				$_until <LOOP>
				mov		[di], ax
				pop		si
			$_endif
			pop		bx
			pop		di
			pop		cx
			add		si, bx
			jc		mt2
		$_until <or cx, cx>, Z
mt1:
		inc		dx
		shr		bx, 1
	$_until , C
public mt2
mt2:
	ret
make_table_	endp

;-----------------------------------------------
;		入力からｎビットを得る
;-----------------------------------------------
;
;ushort getbits(uchar n)
;{
	public	getbits_
getbits_:		
	push	cx
	mov		cl, 16
	sub		cl, al
	push	bitbuf_
	call	fillbuf_
	pop		ax
	shr		ax, cl
	pop		cx
	ret

;
;void fillbuf(uchar n)  /* Shift bitbuf n bits left, read n bits */
;{

	public	fillbuf_
fillbuf_:
	push	cx
	push	dx
	mov		ch, al
	mov		cl, bitcount_
	mov		dx, bitbuf_
	mov		al, subbitbuf_
	$_if <cmp ch, cl>, A
		sub		ch, cl
		shl		dx, cl
		rol		al, cl
		add		dl, al
		mov		cl, 8
fb1:
		call	getc
		$_if <cmp ch, cl>, A
			sub		ch, cl
			mov		dh, dl
			mov		dl, al
			jmp		fb1
		$_endif
	$_endif
	sub		cl, ch
	mov		bitcount_, cl
	mov		cl, ch
	xor		ah, ah
	shl		dx, cl
	shl		ax, cl
	add		dl, ah
	mov		bitbuf_, dx
	mov		subbitbuf_, al
	pop		dx
	pop		cx
	ret

		public	#endofshort
#endofshort:

		public	@autoexec
@autoexec:
		$_if <cmp cs:autoflg, 0dh>, E
			push	cs
			pop		es
			mov		bx, (offset resident - top + 100h + 15) / 16
			mov		ah, 4ah
			int		21h
			push	cs
			pop		ds
			mov		si, offset auto
			int		2eh						; execute
		$_endif
		jmp		#autoexec

resident:

;-----------------------------------------------
;		Get options
;-----------------------------------------------
		public	@getopt
@getopt:
		mov		ax, 3700h
		int		21h								; get switch char
		mov		si, cmdline
		mov		es:swchar, dl

		mov		es:fnnext, offset DGROUP:pathname
		$_do
			lodsb
			$_if <cmp al, ' '>, A
				$_if <cmp al, es:swchar>, E, OR
				$_c	 <cmp al, '-'>, E
lp0:
					lodsb
					cmp		al, ' '
					jbe		lp1
					or		al, 20h
					$_switch
					$_case <cmp al, '!'>, E
						shl		cs:autoflg, 1
					$_case <cmp al, 'x'>, E
						inc		cs:extend
					$_case <cmp al, 'a'>, E
						inc		cs:attrib
					$_default
						cmp		al, 'e'
						jne		lp0
						lodsb
					$_endswitch
				$_endif
				dec		si
				mov		di, offset DGROUP:pathname
				push	si
				call	convert
				pop		si
				push	ax
				mov		al, '/'
				call	trans
				mov		al, '/'
				$_if <cmp ah, al>, NE, AND
				$_c  <cmp ah, ':'>, NE
					stosb
				$_endif
				mov		es:fnnext, di
				pop		ax
lp1:
			$_endif
		$_until <cmp al, 0dh>, E
		ret

		public	@extended
@extended:
			mov		si, dx
			mov		di, offset auto + 1		; !.BAT ?
			cmp		cl, 5
			jne		mn5
			push	es
			push	cs
			pop		es
			xor		ch, ch
			rep		cmpsb
			pop		es
			je		mn2

; -x switch ----------------------------
mn5:
			mov		si, dx
			mov		cx, si
			call	convert
			$_if <cmp cs:extend, 0>, E
				mov		dx, cx			; last delim
			$_endif

; -eDIRECTORY --------------------------
			mov		si, dx
			mov		al, [si]
			$_if <cmp al, '/'>, NE
				mov		di, fnnext
				call	trans
				mov		bx, di
				mov		dx, offset DGROUP:pathname
			$_else
				mov		ax, word ptr DGROUP:pathname
				$_if <cmp ah, ':'>, E
					dec		dx
					dec		dx
					mov		di, dx
					mov		[di], ax	; brakes FnLen and
				$_endif					;	upper byte of FAttr
			$_endif

; Make Directories ---------------------
			mov		si, dx
			$_do
				lodsb
				$_if <cmp al, '/'>, E
					mov		byte ptr [si - 1], 0
					mov		ah, 39h ; make dir
					int		21h
					mov		byte ptr [si - 1], '/'
				$_endif
			$_until <cmp si, bx>, AE

			mov		fnptr, dx
			mov		cx, 1
mn2:
			ret

; Set File Attributes ------------------
		public	@setattr
@setattr:
		$_if <cmp attrib, 0>, NE
			mov		dx, si
			mov		cl, byte ptr DGROUP:cpyhdr.FAttr
			xor		ch, ch
			mov		ax, 4301h
			int		21h				; Set File Attributes
		$_endif
		ret

;-----------------------------------------------
;		convert '\' to '/' & terminater
;-----------------------------------------------
conv	proc	near
		$_do
			$_if <cmp al, '\'>, E, OR
			$_c  <cmp al, '/'>, E
				mov		byte ptr -1[si], '/'
				mov		cx, si
			$_endif
; is kanji ---------------------
			and		al, 0e0h
			shl		al, 1
			$_if , C, AND
			$_c  , PE
				inc		si
			$_endif
; ------------------------------
convert:
			lodsb
		$_until <cmp al, ' '>, BE
		dec		si
		mov		byte ptr [si], 0
		ret
conv	endp

;-----------------------------------------------
;		transfer string
;-----------------------------------------------
trans	proc	near
		$_do
			mov		ah, al
			lodsb
			stosb
		$_until <or al, al>, E
		dec		di
		ret
trans	endp

		public	#endofcode
#endofcode:
_TEXT	ends
		end		top
