;*---------------------------------------------------------------------------
;  :Program.	wdelta.asm
;  :Contents.	create wdelta file
;  :Author.	Bert Jahn
;  :EMail.	wepl@kagi.com
;  :Address.	Franz-Liszt-Straße 16, Rudolstadt, 07404, Germany
;  :Version.	$Id: wdelta.asm 1.1 1999/07/06 21:58:46 jah Exp jah $
;  :History.	09.05.99 started
;		24.06.99 version 1.0 finished
;		06.07.99 reworked, wpatch separated
;  :Requires.	OS V37+
;  :Copyright.
;		WDelta is Copyright © 1999 Bert Jahn <wepl@kagi.com>
;
;		This program is free software; you can redistribute it and/or
;		modify it under the terms of the GNU General Public License as
;		published by the Free Software Foundation; either version 2 of
;		the License, or (at your option) any later version.
;
;		This program is distributed in the hope that it will be
;		useful, but WITHOUT ANY WARRANTY; without even the implied
;		warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;		PURPOSE. See the GNU General Public License for more details.
;
;		You can find the full GNU GPL online at: http://www.gnu.org/
;
;  :Language.	68000/68020 Assembler
;  :Translator.	Barfly V2.9
;---------------------------------------------------------------------------*
;##########################################################################

	INCDIR	Includes:
	INCLUDE	lvo/exec.i
	INCLUDE	exec/execbase.i
	INCLUDE	exec/memory.i
	INCLUDE	lvo/dos.i

	INCLUDE	wdelta.i
	INCLUDE	macros/ntypes.i

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

GL	EQUR	A4		;a4 ptr to Globals
LOC	EQUR	A5		;a5 for local vars

COUNT		;enables counting on creating wdelta files
;DEBUG		;enables some algo checks during creating
;ASC

	STRUCTURE	ReadArgsArray,0
		ULONG	rda_inname
		ULONG	rda_outname
		ULONG	rda_wdname
		ULONG	rda_fc
		ULONG	rda_qc
		LABEL	rda_SIZEOF

	NSTRUCTURE	Globals,0
		NAPTR	gl_execbase
		NAPTR	gl_dosbase
		NAPTR	gl_rdargs
		NSTRUCT	gl_rdarray,rda_SIZEOF
		NLONG	gl_insize
		NLONG	gl_inptr
		NLONG	gl_outsize
		NLONG	gl_outptr
		NLONG	gl_wdsize
		NLONG	gl_wdptr
	IFD COUNT
		NLONG	gl_ec
		NLONG	gl_es
		NLONG	gl_cc
		NLONG	gl_cs
		NLONG	gl_ac
		NLONG	gl_as
		NLONG	gl_dc
		NLONG	gl_ds
	ENDC
		NALIGNLONG
		NLABEL	gl_SIZEOF

;##########################################################################

	PURE
	SECTION	"",CODE
	OUTPUT	C:WDelta

VER	MACRO
		dc.b	"WDelta 1.1 "
	DOSCMD	"WDate >t:date"
	INCBIN	"t:date"
		dc.b	" by Bert Jahn <wepl@kagi.com>"
	ENDM

		bra	.start
		dc.b	"$VER: "
		VER
		dc.b	" V37+"
	CNOP 0,2
.start

;##########################################################################

		link	GL,#gl_SIZEOF		;GL = globals
		move.l	(4),(gl_execbase,GL)

		move.l	#37,d0
		lea	(_dosname),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOOpenLibrary,a6)
		move.l	d0,(gl_dosbase,GL)
		beq	.nodoslib

		lea	(_ver),a0
		bsr	_Print

		clr.l	(gl_rdarray+rda_fc,GL)
		clr.l	(gl_rdarray+rda_qc,GL)

		lea	(_template),a0
		move.l	a0,d1
		lea	(gl_rdarray,GL),a0
		move.l	a0,d2
		moveq	#0,d3
		move.l	(gl_dosbase,GL),a6
		jsr	(_LVOReadArgs,a6)
		move.l	d0,(gl_rdargs,GL)
		bne	.argsok
		lea	(_readargs),a0
		bsr	_PrintErrorDOS
		bra	.noargs
.argsok
		move.l	#180,d1
		move.l	(gl_rdarray+rda_fc,GL),d0
		beq	.fn
		move.l	d0,a0
		move.l	(a0),d1
.fn		move.l	d1,(gl_rdarray+rda_fc,GL)

		move.l	#18,d1
		move.l	(gl_rdarray+rda_qc,GL),d0
		beq	.fc
		move.l	d0,a0
		cmp.l	#1,(a0)
		ble	.fc
		move.l	(a0),d1
.fc		move.l	d1,(gl_rdarray+rda_qc,GL)

		bsr	_create
		move.l	d0,d7

		move.l	(gl_rdargs,GL),d1
		move.l	(gl_dosbase,GL),a6
		jsr	(_LVOFreeArgs,a6)
.noargs
		move.l	(gl_dosbase,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOCloseLibrary,a6)
.nodoslib
		unlk	GL
		move.l	d7,d0
		rts

;##########################################################################

_create		moveq	#20,d7			;rc

		move.l	(gl_execbase,GL),a0
		btst	#AFB_68020,(AttnFlags+1,a0)
		bne	.20ok
		lea	(_lowcpu),a0
		bsr	_Print
		bra	.badcpu
.20ok
		move.l	(gl_rdarray+rda_inname,GL),a0
		bsr	_LoadFileMsg
		move.l	d0,(gl_inptr,GL)
		beq	.noin
		move.l	d1,(gl_insize,GL)

		move.l	(gl_rdarray+rda_outname,GL),a0
		bsr	_LoadFileMsg
		move.l	d0,(gl_outptr,GL)
		beq	.noout
		move.l	d1,(gl_outsize,GL)

		move.l	(gl_outsize,GL),d0
		add.l	d0,d0
		add.l	#wdlt_wdelta,d0
		move.l	#MEMF_ANY,d1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOAllocVec,a6)
		move.l	d0,(gl_wdptr,GL)
		bne	.wdok
		lea	_nomem,a0
		bsr	_Print
		bra	.nowd
.wdok
		lea	(_setup),a0
		move.l	(gl_rdarray+rda_qc,GL),-(a7)
		move.l	(gl_rdarray+rda_fc,GL),-(a7)
		move.l	a7,a1
		bsr	_PrintArgs
		add.l	#8,a7

		bsr	_create_

		move.l	(gl_wdptr,GL),a2
		move.l	#"WDLT",(a2)+
		move.l	a2,a3
		move.l	(gl_insize,GL),(a2)+
		move.l	(gl_outsize,GL),(a2)+
		move.l	(gl_wdsize,GL),(a2)+
		move.l	(gl_insize,GL),d0
		move.l	(gl_inptr,GL),a0
		bsr	_CRC16
		move.w	d0,(a2)+
		move.l	(gl_outsize,GL),d0
		move.l	(gl_outptr,GL),a0
		bsr	_CRC16
		move.w	d0,(a2)+
		move.l	(gl_wdsize,GL),d0
		move.l	(gl_wdptr,GL),a0
		add.l	#wdlt_wdelta,a0
		bsr	_CRC16
		move.w	d0,(a2)+
		move.l	#wdlt_crchd-4,d0
		move.l	a3,a0
		bsr	_CRC16
		move.w	d0,(a2)+

		move.l	#wdlt_wdelta,d0
		add.l	(gl_wdsize,GL),d0
		move.l	(gl_wdptr,GL),a0
		move.l	(gl_rdarray+rda_wdname,GL),a1
		bsr	_SaveFileMsg

		move.l	#wdlt_wdelta,d0
		add.l	(gl_wdsize,GL),d0
		move.l	d0,-(a7)
		lea	(_outputlen),a0
		move.l	a7,a1
		bsr	_PrintArgs
		addq.l	#4,a7

		moveq	#0,d7			;rc

		move.l	(gl_wdptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.nowd
.freeout
		move.l	(gl_outptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.noout
.freein
		move.l	(gl_inptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.noin
.badcpu
		move.l	d7,d0
		rts

; cmd	00 - equ, 5-bit (1..32)
;	20 - chg, 5-bit (1..32)
;	40 - add, 5-bit (1..32)
;	60 - del, 5-bit (1..32)
;	80 - equ, 13-bit (33..8191+33)
;	a0 - chg, 13-bit (33..8191+33)
;	c0 - add, 13-bit (33..8191+33)
;	e0 - del, 13-bit (33..8191+33)

in	EQUR	a0
out	EQUR	a1
wd	EQUR	a2
in2	EQUR	a3
out2	EQUR	LOC
ta	EQUR	a6	;MUST BE A6!

ein	EQUR	d7	;end input data
eout	EQUR	d1	;end output data
e4in	EQUR	d2	;end input data - 4
e4out	EQUR	d3	;end output data - 4
fn	EQUR	d4	;find next
q	EQUR	d5	;quality
t2	EQUR	d6
t1	EQUR	d0	;MUST BE D0!
t3	EQUR	d3
MAXCNT	= 8191+33
MAXPT	= -1		;maximal pointer

_create_

	MC68020

	IFD COUNT
		clr.l	(gl_ec,GL)
		clr.l	(gl_es,GL)
		clr.l	(gl_cc,GL)
		clr.l	(gl_cs,GL)
		clr.l	(gl_ac,GL)
		clr.l	(gl_as,GL)
		clr.l	(gl_dc,GL)
		clr.l	(gl_ds,GL)
		moveq	#0,t1
	ENDC

	;initialisation
		sub.w	#16,a7			;variables for quality

		move.l	(gl_inptr,GL),in	;input start
		move.l	in,ein
		add.l	(gl_insize,GL),ein	;input end
		move.l	ein,e4in
		subq.l	#4,e4in			;input end-4
		move.l	(gl_outptr,GL),out	;output start
		move.l	out,eout
		add.l	(gl_outsize,GL),eout	;output end
		move.l	eout,e4out
		subq.l	#4,e4out		;output end-4
		move.l	(gl_wdptr,GL),wd
		add.l	#wdlt_wdelta,wd		;skip header

MINDATALEN = 8

	;check if input or output data is smaller than MINDATALEN bytes
		cmp.l	#MINDATALEN,(gl_insize,GL)
		blo	.tosmall
		cmp.l	#MINDATALEN,(gl_outsize,GL)
		bhs	.lenok
	;to small, so simple build wdelta by copying output ("add")
.tosmall	move.l	(gl_outsize,GL),t1
		beq	.smallend
	IFD COUNT
		addq.l	#1,(gl_ac,GL)
		add.l	t1,(gl_as,GL)
	ENDC
.ts3		sub.l	#MAXCNT,t1
		bcs	.ts4
		move.w	#$dfff,(wd)+		;add 8191+33
		move.w	#MAXCNT/4-1,t2
.ts6		move.l	(out)+,(wd)+
		dbf	t2,.ts6
		bra	.ts3
.ts4		add.l	#MAXCNT-1,t1
		bmi	.smallend		;if equal 8191+33
		move.w	t1,t2
		cmp.w	#32,t1
		bhs	.ts5
		or.b	#$40,t1
		move.b	t1,(wd)+		;add 1..33
		bra	.ts7
.ts5		sub.w	#32,t1
		or.w	#$c000,t1
		move.w	t1,(wd)+		;add 33..8191+33
.ts7		move.b	(out)+,(wd)+
		dbf	t2,.ts7
		bra	.smallend

.finish_eq_opt
	IFD DEBUG
		beq	.finish_eq
		illegal
	ENDC
		bra	.finish_eq		;this is for optimizing

	;we have a valid input and output now
	;depending on the equality of the first word we enter the search
	;routine for equal or for sync
.lenok		move.w	(in),t1
		cmp.w	(out),t1
		bne	.searchsync
	QUAD
.ncnteq		move.l	out,t1
.cnteq		cmp.l	eout,out
		bhs	.finish_eq_opt
		cmp.l	ein,in
		bhs	.finish_eq_opt
		cmp.b	(in)+,(out)+
		beq	.cnteq

		subq.l	#1,in			;correct post-increment
		subq.l	#1,out			;correct post-increment

WRITE_EQU MACRO
	IFD DEBUG
		;check if wdelta is larger than output size
		move.l	(gl_outsize,GL),t2
		add.l	(gl_wdptr,GL),t2
		cmp.l	t2,wd
		blo	.i\@
		illegal
.i\@
	ENDC
		move.l	out,t2
		sub.l	t1,t2			;t2 = amount of equal bytes
	IFD DEBUG
		bgt	.5\@			;cannot be zero/negative
		illegal
.5\@
	ENDC
	IFD COUNT
		addq.l	#1,(gl_ec,GL)
		add.l	t2,(gl_es,GL)
	ENDC
	IFD ASC
		movem.l	d0-d2/a0-a2/a6,-(a7)
		move.l	t2,-(a7)
		pea	(_equ)
		move.l	in,d0
		sub.l	(gl_inptr,GL),d0
		sub.l	t2,d0
		move.l	d0,-(a7)
		move.l	out,d0
		sub.l	(gl_outptr,GL),d0
		sub.l	t2,d0
		move.l	d0,-(a7)
		move.l	a7,d2
		move.l	(gl_dosbase,GL),a6
		lea	(_asc1),a0
		move.l	a0,d1
		jsr	(_LVOVPrintf,a6)
		add.w	#16,a7
		movem.l	(a7)+,_MOVEMREGS
	ENDC
.4\@		sub.l	#MAXCNT,t2
		bcs	.3\@
		move.w	#$9fff,(wd)+		;equ 8191+33
		bra	.4\@
.3\@		add.l	#MAXCNT-1,t2
		bmi	.2\@			;is negative if t2 was a multiple of MAXCNT
		cmp.w	#32,t2
		bhs	.1\@
		move.b	t2,(wd)+		;equ 1..33
		bra	.2\@
.1\@		sub.w	#32,t2
		or.w	#$8000,t2
		move.w	t2,(wd)+		;equ 33..8191+33
.2\@
	ENDM

		WRITE_EQU

	;search for new sync
.searchsync	move.l	in,in2
		move.l	out,out2
		move.l	#MAXPT,fn		;(unsigned)
		move.l	#$80000000,(a7)		;(signed) lowest possible quality
		bra	.ss1_in

	;---------------------------------------
	;search "eq", "add", "del"
	QUAD
.ss1		move.l	(in2),t1		;t1 = contens of in2
		move.l	(out2),t2		;t2 = contens of out2
		cmp.l	t1,t2
		beq	.ss1_fchg

		move.l	in,ta			;ta = temp in ptr
.ss1_add	cmp.l	(ta),t2
		beq	.ss1_fadd
.ss1_addr	addq.l	#1,ta
		cmp.l	ta,in2
		bhi	.ss1_add

		move.l	out,ta			;ta = temp out ptr
.ss1_del	cmp.l	(ta),t1
		beq	.ss1_fdel
.ss1_delr	addq.l	#1,ta
		cmp.l	ta,out2
		bhi	.ss1_del

.ss1_in		cmp.l	e4in,in2		;end input ?
		bhs	.ss_endin
		addq.l	#1,in2
		cmp.l	e4out,out2		;end output ?
		bhs	.ss_endout
		addq.l	#1,out2
	;check if end of fn is reached
		cmp.l	fn,out2
		blo	.ss1
	;perform best found command
		jmp	([12,a7])
	;	nop				;because a bug in bdebug!

RANKINITC MACRO
	;add half amount of addable qual
		move.l	(rda_qc+gl_rdarray,GL),q
		mulu	q,q
		lsr.l	#2,q
		add.l	in,q
	;	move.l	in,q
		sub.l	in2,q			;search offset
		asr.l	#1,q
	ENDM
RANKINIT MACRO
	;q  = distance from in/out
		asr.l	#1,q
	ENDM
RANKDO MACRO
		add.l	t3,q
	;	addq.l	#1,q
	ENDM
RANKPOST MACRO
		subq.l	#1,t3
	ENDM

.ss1_fchg
	;save regs
		movem.l	t2/t3/in2/out2,-(a7)
	;calculate quality
		RANKINITC
		move.l	(rda_qc+gl_rdarray,GL),t3
		move.l	t3,t2
		add.l	out2,t2
		cmp.l	eout,t2
		bls	.fchg2
		move.l	eout,t2
.fchg2		cmp.b	(in2)+,(out2)+
		bne	.fchg1
		RANKDO
.fchg1		RANKPOST
		cmp.l	in2,ein
		bls	.fchg3
		cmp.l	out2,t2
		bhi	.fchg2
.fchg3	;restore regs
		movem.l	(a7)+,_MOVEMREGS
	;checks if fn is already set
		tst.l	fn
		bmi	.fchg4
	;check against existing quality
		cmp.l	(a7),q
		ble	.chgr
	;save setup
.fchg5		movem.l	q/out2,(a7)
		move.l	#.chg,(12,a7)
		bra	.chgr
	;set fn
.fchg4		move.l	(rda_fc+gl_rdarray,GL),fn
		add.l	out,fn
		bra	.fchg5

RANKADD	MACRO
	;save regs
		movem.l	t2/t3/ta/out2,-(a7)
	;calculate quality
		move.l	out,q
		sub.l	out2,q
		add.l	in,q
		sub.l	ta,q
		RANKINIT
		move.l	(rda_qc+gl_rdarray,GL),t3
		move.l	t3,t2
		add.l	out2,t2
		cmp.l	eout,t2
		bls	.2\@
		move.l	eout,t2
.2\@		cmp.b	(ta)+,(out2)+
		bne	.1\@
		RANKDO
.1\@		RANKPOST
		cmp.l	ta,ein
		bls	.3\@
		cmp.l	out2,t2
		bhi	.2\@
.3\@	;restore regs
		movem.l	(a7)+,_MOVEMREGS
	;checks if fn is already set
		tst.l	fn
		bmi	.4\@
	;check against existing quality
		cmp.l	(a7),q
		ble	\1
	;save setup
.5\@		movem.l	q/ta/out2,(a7)
		move.l	#.add,(12,a7)
		bra	\1
	;set fn
.4\@		move.l	(rda_fc+gl_rdarray,GL),fn
		add.l	out,fn
		bra	.5\@
	ENDM

.ss1_fadd	RANKADD	.ss1_addr

RANKDEL	MACRO
	;save regs
		movem.l	t2/t3/ta/in2,-(a7)
	;calculate quality
		move.l	out,q
		sub.l	ta,q
		add.l	in,q
		sub.l	in2,q
		RANKINIT
		move.l	(rda_qc+gl_rdarray,GL),t3
		move.l	t3,t2
		add.l	in2,t2
		cmp.l	ein,t2
		bls	.2\@
		move.l	ein,t2
.2\@		cmp.b	(ta)+,(in2)+
		bne	.1\@
		RANKDO
.1\@		RANKPOST
		cmp.l	ta,eout
		bls	.3\@
		cmp.l	in2,t2
		bhi	.2\@
.3\@	;restore regs
		movem.l	(a7)+,_MOVEMREGS
	;checks if fn is already set
		tst.l	fn
		bmi	.4\@
	;check against existing quality
		cmp.l	(a7),q
		ble	\1
	;save setup
.5\@		movem.l	q/ta/in2,(a7)
		move.l	#.del,(12,a7)
		bra	\1
	;set fn
.4\@		move.l	(rda_fc+gl_rdarray,GL),fn
		add.l	out,fn
		bra	.5\@
	ENDM

.ss1_fdel	RANKDEL	.ss1_delr

	;---------------------------------------
	;search "add", "del" ("eq" already found)
	QUAD
.ss2		move.l	(in2),t1		;t1 = contens of in2
		move.l	(out2),t2		;t2 = contens of out2
.chgr
		move.l	in,ta			;ta = temp in ptr
.ss2_add	cmp.l	(ta),t2
		beq	.ss2_fadd
.ss2_addr	addq.l	#1,ta
		cmp.l	ta,in2
		bhi	.ss2_add

		move.l	out,ta			;ta = temp out ptr
.ss2_del	cmp.l	(ta),t1
		beq	.ss2_fdel
.ss2_delr	addq.l	#1,ta
		cmp.l	ta,out2
		bhi	.ss2_del

		cmp.l	e4in,in2		;end input ?
		bhs	.ss_endin
		addq.l	#1,in2
		cmp.l	e4out,out2		;end output ?
		bhs	.ss_endout
		addq.l	#1,out2
	;check if end of fn is reached
		cmp.l	fn,out2
		blo	.ss2
	;perform best found command
		jmp	([12,a7])
	;	nop				;because a bug in bdebug!

.ss2_fadd	RANKADD	.ss2_addr
.ss2_fdel	RANKDEL	.ss2_delr

	;---------------------------------------
	;searches "add", "del" because end of input reached
.ss_endin
	;check if at least 4 bytes are available on out2
		bne	.finish
	;set t1
		move.l	(in2),t1
		bra	.ss_ei_in

.ss_ei		move.l	(out2),t2		;t2 = contens of out2
		move.l	in,ta			;ta = temp in ptr
.ss_ei_add	cmp.l	(ta),t2
		beq	.ss_ei_fadd
.ss_ei_addr	addq.l	#1,ta
		cmp.l	ta,in2
		bhi	.ss_ei_add

		move.l	out,ta			;ta = temp out ptr
.ss_ei_del	cmp.l	(ta),t1
		beq	.ss_ei_fdel
.ss_ei_delr	addq.l	#1,ta
		cmp.l	ta,out2
		bhi	.ss_ei_del

.ss_ei_in	cmp.l	e4out,out2		;end output ?
		bhs	.ss_ei_eo
		addq.l	#1,out2
	;check if end of fn is reached
		cmp.l	fn,out2
		blo	.ss_ei
	;perform best found command
.ss_ei_p	jmp	([12,a7])
	;	nop				;because a bug in bdebug!
.ss_ei_eo	tst.l	fn
		bpl	.ss_ei_p
		bra	.finish

.ss_ei_fadd	RANKADD	.ss_ei_addr
.ss_ei_fdel	RANKDEL	.ss_ei_delr

	;---------------------------------------
	;searches "add", "del" because end of output reached
.ss_endout
	;check if at least 4 bytes are available on out2
		bne	.finish
	;set t2
		move.l	(out2),t2
	;if fn is already set, remap it to "in address"
		tst.l	fn
		bmi	.ss_eo
		sub.l	out,fn			;bytes to check left
		add.l	in,fn

.ss_eo		move.l	in,ta			;ta = temp in ptr
.ss_eo_add	cmp.l	(ta),t2
		beq	.ss_eo_fadd
.ss_eo_addr	addq.l	#1,ta
		cmp.l	ta,in2
		bhi	.ss_eo_add

		move.l	(in2),t1		;t1 = contens of in2
		move.l	out,ta			;ta = temp out ptr
.ss_eo_del	cmp.l	(ta),t1
		beq	.ss_eo_fdel
.ss_eo_delr	addq.l	#1,ta
		cmp.l	ta,out2
		bhi	.ss_eo_del

		cmp.l	e4in,in2		;end input ?
		bhs	.ss_eo_ei
		addq.l	#1,in2
	;check if end of fn is reached
		cmp.l	fn,in2
		blo	.ss_eo
	;perform best found command
.ss_eo_p	jmp	([12,a7])
	;	nop				;because a bug in bdebug!
.ss_eo_ei	tst.l	fn
		bpl	.ss_eo_p
		bra	.finish

.ss_eo_fadd	RANKADD	.ss_eo_addr
.ss_eo_fdel	RANKDEL	.ss_eo_delr

	;---------------------------------------
	;perform "chg"
	;(4,a7) = out2
.chg		move.l	(4,a7),t1
		sub.l	out,t1
		bsr	.do_chg
		bra	.ncnteq

	;---------------------------------------
	;really do "chg"
	;t1 = amount of bytes to change
	;in,out will be changed appropriate
.do_chg		add.l	t1,in			;skip input
	IFD COUNT
		addq.l	#1,(gl_cc,GL)
		add.l	t1,(gl_cs,GL)
	ENDC
	IFD ASC
		movem.l	d0-d2/a0-a2/a6,-(a7)
		move.l	t1,-(a7)
		pea	(_chg)
		move.l	in,d0
		sub.l	(gl_inptr,GL),d0
		move.l	d0,-(a7)
		move.l	out,d0
		sub.l	(gl_outptr,GL),d0
		move.l	d0,-(a7)
		move.l	a7,d2
		move.l	(gl_dosbase,GL),a6
		lea	(_asc1),a0
		move.l	a0,d1
		jsr	(_LVOVPrintf,a6)
		add.w	#16,a7
		movem.l	(a7)+,_MOVEMREGS
	ENDC
.chg3		sub.l	#MAXCNT,t1
		bcs	.chg4
		move.w	#$bfff,(wd)+		;chg 8191+33
		move.w	#MAXCNT/4-1,t2
.chg6		move.l	(out)+,(wd)+
		dbf	t2,.chg6
		bra	.chg3
.chg4		add.l	#MAXCNT-1,t1
		bmi	.ncnteq			;is negative if t1 was a multiple of MAXCNT
		move.w	t1,t2
		cmp.w	#32,t1
		bhs	.chg5
		or.b	#$20,t1
		move.b	t1,(wd)+		;chg 1..33
		bra	.chg7
.chg5		sub.w	#32,t1
		or.w	#$a000,t1
		move.w	t1,(wd)+		;chg 33..8191+33
.chg7		move.b	(out)+,(wd)+
		dbf	t2,.chg7
		rts

	;---------------------------------------
	;perform "del"
	;either only "del" or "chg"+"del" (which can replaced by "del"+"add")
	;(4,a7) = in2 = offset in input stream
	;(8,a7) = ta = offset in output stream
.del		move.l	(8,a7),t1
		sub.l	out,t1
		beq	.del1
		bsr	.do_chg
.del1		move.l	(4,a7),t1
		sub.l	in,t1
	IFD DEBUG
		cmp.l #10000,t1
		blo .i1
		illegal
.i1
	ENDC
	;perform del command
	IFD COUNT
		addq.l	#1,(gl_dc,GL)
		add.l	t1,(gl_ds,GL)
	ENDC
	IFD ASC
		movem.l	d0-d2/a0-a2/a6,-(a7)
		move.l	t1,-(a7)
		move.l	out2,t1
		sub.l	out,t1
		move.l	t1,-(a7)
		move.l	in,d0
		sub.l	(gl_inptr,GL),d0
		move.l	d0,-(a7)
		move.l	out,d0
		sub.l	(gl_outptr,GL),d0
		move.l	d0,-(a7)
		move.l	a7,d2
		move.l	(gl_dosbase,GL),a6
		lea	(_asc2),a0
		move.l	a0,d1
		jsr	(_LVOVPrintf,a6)
		add.w	#16,a7
		movem.l	(a7)+,_MOVEMREGS
	ENDC
		add.l	t1,in			;skip input stream
.del3		sub.l	#MAXCNT,t1
		bcs	.del4
		move.w	#$ffff,(wd)+		;del 8191+33
		bra	.del3
.del4		add.l	#MAXCNT-1,t1
		bmi	.ncnteq
		cmp.w	#32,t1
		bhs	.del5
		or.b	#$60,t1
		move.b	t1,(wd)+		;del 1..33
		bra	.ncnteq
.del5		sub.w	#32,t1
		or.w	#$e000,t1
		move.w	t1,(wd)+		;del 33..8191+33
		bra	.ncnteq

	;---------------------------------------
	;perform "add"
	;either only "add" or "chg"+"add" (which can replaced by "del"+"add")
	;(4,a7) = out2 = offset in output stream
	;(8,a7) = ta = offset in input stream
	;amount "del" = ta - in
	;amount "add" = out2 - out
.add		move.l	(8,a7),t1
		sub.l	in,t1
		beq	.add1
		bsr	.do_chg
.add1		move.l	(4,a7),t1
		sub.l	out,t1
	IFD DEBUG
		cmp.l #10000,t1
		blo .i2
		illegal
.i2
	ENDC
	;perform add command
	IFD COUNT
		addq.l	#1,(gl_ac,GL)
		add.l	t1,(gl_as,GL)
	ENDC
.add3		sub.l	#MAXCNT,t1
		bcs	.add4
		move.w	#$dfff,(wd)+		;add 8191+33
		move.w	#MAXCNT/4-1,t2
.add6		move.l	(out)+,(wd)+
		dbf	t2,.add6
		bra	.add3
.add4		add.l	#MAXCNT-1,t1
		bmi	.chg
		move.w	t1,t2
		cmp.w	#32,t1
		bhs	.add5
		or.b	#$40,t1
		move.b	t1,(wd)+		;add 1..33
		bra	.add7
.add5		sub.w	#32,t1
		or.w	#$c000,t1
		move.w	t1,(wd)+		;add 33..8191+33
.add7		move.b	(out)+,(wd)+
		dbf	t2,.add7
		bra	.ncnteq

	;end of calculation, because
	; - end input stream during eq search
	; - end output stream during eq search
.finish_eq	WRITE_EQU

	;end of calculation, because
	; - end input stream during sync search
	; - end output stream during sync search
.finish
	IFD COUNT
		move.l	ein,t1
		sub.l	in,t1
		beq	.finish1
		addq.l	#1,(gl_dc,GL)
		add.l	t1,(gl_ds,GL)
.finish1
	ENDC
		move.l	eout,t1
		sub.l	out,t1
		beq	.finish_end
	IFD COUNT
		addq.l	#1,(gl_ac,GL)
		add.l	t1,(gl_as,GL)
	ENDC

.endin3		sub.l	#MAXCNT,t1
		bcs	.endin4
		move.w	#$dfff,(wd)+		;add 8191+33
		move.w	#MAXCNT/4-1,t2
.endin6		move.l	(out)+,(wd)+
		dbf	t2,.endin6
		bra	.endin3
.endin4		add.l	#MAXCNT-1,t1
		bmi	.finish_end
		move.w	t1,t2
		cmp.w	#32,t1
		bhs	.endin5
		or.b	#$40,t1
		move.b	t1,(wd)+		;add 1..33
		bra	.endin7
.endin5		sub.w	#32,t1
		or.w	#$c000,t1
		move.w	t1,(wd)+		;add 33..8191+33
.endin7		move.b	(out)+,(wd)+
		dbf	t2,.endin7

.finish_end
.smallend
		add.w	#16,a7

		sub.l	(gl_wdptr,GL),wd
		sub.l	#wdlt_wdelta,wd
		move.l	wd,(gl_wdsize,GL)

	IFD COUNT
		lea	(_debug),a0
		move.l	(gl_ds,GL),-(a7)
		move.l	(gl_dc,GL),-(a7)
		move.l	(gl_as,GL),-(a7)
		move.l	(gl_ac,GL),-(a7)
		move.l	(gl_cs,GL),-(a7)
		move.l	(gl_cc,GL),-(a7)
		move.l	(gl_es,GL),-(a7)
		move.l	(gl_ec,GL),-(a7)
		move.l	a7,a1
		bsr	_PrintArgs
		add.l	#8*4,a7
	ENDC

	MC68000

		rts

;##########################################################################

	INCLUDE	crc16.s

	INCDIR	Sources:
	INCLUDE	dosio.i
	;	CheckBreak
		Print
		PrintLn
	INCLUDE	error.i
		PrintErrorDOS
	INCLUDE	files.i
		LoadFileMsg
		SaveFileMsg

;##########################################################################

	IFD COUNT
_debug		dc.b	"equal%8ld chunks%7ld bytes",10
		dc.b	"changed%6ld chunks%7ld bytes",10
		dc.b	"added%8ld chunks%7ld bytes",10
		dc.b	"deleted%6ld chunks%7ld bytes",10,0
	ENDC
	IFD ASC
_asc1		dc.b	"in=%6lx out=%6lx  %s %3lx bytes",10,0
_equ		dc.b	"equ",0
_chg		dc.b	"chg",0
_asc2		dc.b	"in=%6lx out=%6lx  del %3lx bytes add %3lx bytes",10,0
	ENDC
_outputlen	dc.b	"output length is %ld bytes",10,0
_setup		dc.b	"forward check %ld bytes, quality compare %ld bytes",10,0
_lowcpu		dc.b	"sorry, creating wdelta files requires a MC68020 or better",10,0
_nomem		dc.b	"not enough free memory",10,0
_readargs	dc.b	"read arguments",0
_dosname	dc.b	"dos.library",0
_template	dc.b	"InFile/A"		;file to apply patch
		dc.b	",OutFile/A"		;resulting file
		dc.b	",WDeltaFile/A"		;wdelta file
		dc.b	",FC/K/N"
		dc.b	",QC/K/N"
		dc.b	0

_ver		VER
		dc.b	10,0

;##########################################################################

	END
