Code020  	=	1		; Define for 020 code, comment for 000.
Debug		=	1		; Define for Say() & ShowReg() macros.

	IFND	Code020
	MACHINE	68000
	ENDC
	IFD	Code020
	MACHINE	68020
	ENDC

	XREF	StrCat
	XREF	StrCmp
	XREF	StrCpy
	XREF	StrChr
	XREF	StrEnd
	XREF	StrFirstNum
	XREF	StrLFCat
	XREF	StrLen
	XREF	StrNCmp
	XREF	StrNumCat
	XREF	StrToNum

	XDEF	NumToStr

; Last CodeError code used: 4

; During the translation loop:
; A0 = Pointer to source data
; A1 = Pointer to destination data
; A2 = Pointer to space buffer
; A3 = Pointer to translation table
; A4 = Pointer to InterNet header stripper buffer.
; A5 = Data base pointer. [Not implemented yet]

; D0 = Current char
; D1 = Counter of bytes left in the source buffer.
; D2 = Counter of converted bytes in the destination buffer.
; D3 = Counter of overall converted bytes.

	INCDIR	"INCLUDE:"
	INCLUDE	"Darkness.I"
	INCLUDE	"Exec.Offsets"
	INCLUDE	"Dos.Offsets"
	INCLUDE "exec/types.i"
	INCLUDE	"exec/execbase.i"
	INCLUDE	"exec/memory.i"
	INCLUDE	"hardware/intbits.i"
	INCLUDE	"dos/dos.i"
	INCLUDE	"dos/dosasl.i"
	INCLUDE "libraries/ppbase.i"
	INCLUDE "libraries/powerpacker_lib.i"

	STRUCTURE	FileLink,0
	LONG	fl_Next
	LONG	fl_Size
	STRUCT	fl_FullName,256
	STRUCT	fl_FileName,256
	LABEL	fl_SIZEOF

; Modes which want CRs must be negative.
MODE_TOPC	=	-1
MODE_TOSF7	=	-2

MODE_FROMPC	=	 1
MODE_FROMSF7	=	 2
MODE_TOUPCASE	=	 3
MODE_TOLOWCASE	=	 4
MODE_TONULL	=	 5
MODE_AUTOMODE	=	 6
MODE_TOASCII	=	 7
MODE_COMBINED	=	 8

SIZE_SRCBUF	=	20480
SIZE_DESTBUF	=	102400
SIZE_MAXNEW	=	9		; Maximum size change in one cycle.

CR		=	13
LF		=	10
TAB		=	 9

TRUE		= 	-1
FALSE		=	 0

ANSI_CLEAR	=	 0		; No ANSI code currently active.
ANSI_WAIT	=	 1		; ESC found, but no "[" yet.
ANSI_CODE	=	 2		; In progress of skipping the code.

; A macro to call a library routine.

Call	MACRO
	move.l	_\1Base,a6
	jsr	_LVO\2(a6)
	ENDM

BToLong	MACRO
	IFD	Code020			; Convert TabSize
	extb.l	\1
	ENDC
	IFND	Code020
	ext.w	\1
	ext.l	\1
	ENDC
	ENDM

SaveR	MACRO
	movem.l	d0-d7/a0-a6,-(sp)
	ENDM

LoadR	MACRO
	movem.l	(sp)+,d0-d7/a0-a6
	ENDM

Say	MACRO
	IFD	Debug
	SaveR
	lea	PrintBuf,a0
	lea	.Shit\@,a1
	bsr	StrCpy
	lea	PrintBuf,a0
	bsr	StrLFCat
	bsr	WritePrintBuf
	LoadR
	bra	.Skip\@

.Shit\@:
	dc.b	\1,0

	EVEN

.Skip\@:
	ENDC
	ENDM

ShowPtr	MACRO
	IFD	Debug
	SaveR
	move.l	\1,d2
	bsr	PrintText
	LoadR
	ENDC
	ENDM

ShowReg	MACRO
	IFD	Debug
	SaveR
	lea	.Shit\@,a0
	clr.b	(a0)
	move.l	\1,d0
	bsr	StrNumCat
	lea	.Shit\@,a0
	bsr	StrLFCat
	move.l	#.Shit\@,d2
	bsr	PrintText
	LoadR
	bra	.Skip\@

.Shit\@:
	ds.b	256

	EVEN

.Skip\@:
	ENDC
	ENDM

ProgStart:
	move.l	sp,OldStack
	lea	DT,a5
	clr.b	-1(a0,d0.w)
	move.l	a0,-(sp)
	add.l	d0,a0
	subq.l	#1,a0

	lea	_DosName,a1
	moveq	#37,d0
	Call	Exec,OpenLibrary
	move.l	d0,_DosBase
	beq	Err_NewerKickNeeded

	IFD	Code020
	move.l	_ExecBase,a6		; Tests if we have 68020.
	move.w	AttnFlags(a6),d0
	btst.w	#AFB_68020,d0
	beq	Err_OldProcessor
	ENDC

	Call	Dos,Output
	move.l	d0,OutStruct

	move.l	#Text_Header,d2
	bsr	PrintText

	lea	PPName,a1		; Open PP library if we have it.
	moveq	#35,d0			; If change to higher check 'PPNeed'.
	Call	Exec,OpenLibrary
	move.l	d0,_PPBase

	move.l	4.w,a6			; Set up the interrupt.
	move.l	VBlankFrequency(a6),TickDelay

	moveq	#INTB_VERTB,d0		; Add the counter interrupt.
	lea	VertBInterrupt,a1
	Call	Exec,AddIntServer
	st	Flag_IntActive

	move.l	(a7),a0			; CommandStart
	tst.b	(a0)			; If blank commandline, instructions.
	beq.w	HelpText
	cmp.b	#"?",(a0)
	beq.w	HelpText

	bsr	LoadPrefs		; Load user preferences.
	move.l	(a7)+,a0		; CommandStart

ParseStart:
	cmp.b	#"-",(a0)
	beq.b	CheckOption

Parse:
	cmp.b	#" ",1(a0)		; At least one space after option
	bne.w	Err_BadComLine
	cmp.b	#"p",(a0)
	beq.w	FromPCMode
	cmp.b	#"P",(a0)
	beq.w	ToPCMode
	cmp.b	#"c",(a0)
	beq.w	CombinedMode
	cmp.b	#"s",(a0)
	beq.w	FromSF7Mode
	cmp.b	#"S",(a0)
	beq.w	ToSF7Mode
	cmp.b	#"u",(a0)
	beq.w	ToUpCaseMode
	cmp.b	#"l",(a0)
	beq.w	ToLowCaseMode
	cmp.b	#"a",(a0)
	beq.w	AutoMode
	cmp.b	#"n",(a0)
	beq.w	ModeToNull
	cmp.b	#"o",(a0)
	beq.w	ModeToOnlyASCII
	bra.w	Err_BadComLine

CheckOption:
	cmp.b	#"a",1(a0)
	beq.b	Opt_AStrip
	cmp.b	#"e",1(a0)
	beq.b	Opt_MakeEOLs
	cmp.b	#"i",1(a0)
	beq.b	Opt_INStrip
	cmp.b	#"n",1(a0)
	beq.b	Opt_NoCutSpace
	cmp.b	#"p",1(a0)
	beq	Opt_PPackOut
	cmp.b	#"l",1(a0)
	beq	Opt_LhAPackOut
	cmp.b	#"?",1(a0)
	beq	Credits
	cmp.b	#"t",1(a0)
	beq	Opt_TabConv
	cmp.b	#"s",1(a0)
	beq	Opt_SpaceConv
	cmp.b	#"q",1(a0)
	beq	Opt_QuietMode
	cmp.b	#"b",1(a0)
	beq	Opt_NoBufferMode
	bra	Err_BadComLine

Opt_AStrip:
	cmp.b	#"!",2(a0)
	beq.b	.Off
	addq.l	#2,a0
	st	Flag_AStrip
	bra	Opt_Next

.Off:
	addq.l	#3,a0
	clr.b	Flag_AStrip
	bra	Opt_Next

Opt_INStrip:
	addq.l	#3,a0
	cmp.b	#"!",-1(a0)
	beq.b	.Off
	cmp.b	#"1",-1(a0)
	beq.b	.PutInfo
	cmp.b	#"2",-1(a0)
	beq.b	.NoInfo
	bra	Err_BadComLine

.Off:
	clr.b	Flag_INStrip
	bra.b	Opt_Next

.PutInfo:
	move.b	#1,Flag_INStrip
	bra.b	Opt_Next

.NoInfo:
	move.b	#2,Flag_INStrip
	bra.b	Opt_Next

Opt_NoCutSpace:
	cmp.b	#"!",2(a0)
	beq.b	.Off
	tst.b	Size_MakeEOLs
	bne.w	Err_BadLogic
	st	Mode_NoCutSpace
	addq.l	#2,a0
	bra.w	Opt_Next

.Off:
	addq.l	#3,a0
	clr.b	Mode_NoCutSpace
	bra	Opt_Next

Opt_LhAPackOut:
	cmp.b	#"!",2(a0)
	beq.b	.Off
	tst.b	Flag_CrunchBuf
	bne	Err_BadLogic
	addq.l	#2,a0
	st	Flag_LhAPack
	bra	Opt_Next

.Off:
	addq.l	#3,a0
	clr.b	Flag_LhAPack
	bra	Opt_Next

Opt_PPackOut:
	cmp.b	#"!",2(a0)
	beq.b	.Off
	tst.b	Flag_LhAPack
	bne	Err_BadLogic
	addq.l	#2,a0
	st	Flag_CrunchBuf
	tst.l	_PPBase
	bne.b	Opt_Next
	move.l	#Text_PowerPackNeed,d2
	bra	ShowErr

.Off:
	addq.l	#3,a0
	clr.b	Flag_CrunchBuf
	bra.b	Opt_Next

Opt_TabConv:
	addq.l	#2,a0
	cmp.b	#"!",(a0)
	beq.b	.Off
	cmp.l	#DT,a5
	beq	.ok
	move.w	#$f00,$dff180
	lea	DT,a5

.ok:
	tst.b	(a5,TabSize-DT)
	bne.w	Err_BadLogic
	cmp.b	#" ",(a0)
	beq.b	Opt_TabConv1
	move.l	a0,-(sp)
	bsr	GetNum
	move.l	(sp)+,a0
	bsr	FindWhite
	cmp.l	#16,d0
	bhi	Err_BadComLine
	cmp.l	#1,d0
	bcs	Err_BadComLine
	move.b	d0,TabSize
	bra.b	Opt_Next

.Off:
	addq.l	#1,a0
	tst.b	SpaceSize		; SpaceConv has TabConv always on, don't
	bne	Opt_Next		; turn that off.
	clr.b	TabSize
	bra	Opt_Next

Opt_TabConv1:
	move.b	#8,TabSize
	bra.b	Opt_Next

Opt_SpaceConv:
	addq.l	#2,a0
	cmp.b	#"!",(a0)
	beq.b	.Off
	tst.b	SpaceSize		; If we have a old SpaceConv, new is ok.
	bne.b	.Okay
	tst.b	TabSize
	bne.w	Err_BadLogic

.Okay:
	tst.b	Size_MakeEOLs
	bne.w	Err_BadLogic
	cmp.b	#" ",(a0)
	beq.b	.Default
	move.l	a0,-(sp)
	bsr	GetNum
	move.l	(sp)+,a0
	bsr	FindWhite
	cmp.l	#16,d0
	bhi	Err_BadComLine
	cmp.l	#1,d0
	bcs	Err_BadComLine
	move.b	d0,SpaceSize
	bra.b	Opt_Next

.Default:
	move.b	#8,SpaceSize
	move.b	#8,TabSize
	bra	Opt_Next

.Off
	addq.l	#1,a0
	tst.b	SpaceSize
	beq.b	Opt_Next
	clr.b	SpaceSize
	clr.b	TabSize
	bra	Opt_Next

Opt_QuietMode:
	cmp.b	#"!",2(a0)
	beq	.Off
	st	Mode_Quiet
	addq.l	#2,a0
	bra.b	Opt_Next

.Off:
	clr.b	Mode_Quiet
	addq.l	#3,a0
	bra.b	Opt_Next
	
Opt_MakeEOLs:
	cmp.b	#"!",2(a0)
	beq	.Off
	tst.b	SpaceSize
	bne.w	Err_BadLogic
	move.b	2(a0),d0
	cmp.b	#" ",d0
	beq.w	Err_BadComLine
	sub.b	#"0",d0
	cmp.b	#9,d0
	bhi	Err_BadComLine
	cmp.b	#1,d0
	bcs	Err_BadComLine
	move.b	3(a0),d1
	cmp.b	#" ",d1
	beq.b	Opt_MakeEOLs1
	sub.b	#"0",d1
	cmp.b	#9,d1
	bhi	Err_BadComLine
	cmp.b	#0,d1
	bcs	Err_BadComLine
	ext.w	d0
	mulu	#10,d0
	add.b	d1,d0
	move.b	d0,Size_MakeEOLs
	addq.l	#4,a0
	bra.b	Opt_Next

.Off:
	clr.b	Size_MakeEOLs
	addq.l	#3,a0
	bra.b	Opt_Next

Opt_MakeEOLs1:
	move.b	d0,Size_MakeEOLs
	addq.l	#3,a0
	bra.b	Opt_Next

Opt_NoBufferMode:
	addq.l	#2,a0
	cmp.b	#"!",(a0)
	beq.b	.Off
	st	Mode_NoBuffer
	bra	Opt_Next

.Off:
	addq.l	#1,a0
	clr.b	Mode_NoBuffer

Opt_Next:
	cmp.b	#" ",(a0)
	bne.w	Err_BadComLine
	bsr	SkipSpace
	cmp.l	#0,a0
	beq.w	Err_BadComLine
	bra.w	ParseStart

FromPCMode:
	move.b	#MODE_FROMPC,Mode
	move.l	#Table_FromPC,Table
	bra.w	NameParse

FromSF7Mode:
	move.b	#MODE_FROMSF7,Mode
	move.l	#Table_FromSF7,Table
	bra.w	NameParse

ToSF7Mode:
	move.b	#MODE_TOSF7,Mode
	move.l	#Table_ToSF7,Table
	bra.w	NameParse

CombinedMode:
	move.b	#MODE_COMBINED,Mode
	move.l	#Table_Combined,Table
	bra.w	NameParse

ToPCMode:
	move.b	#MODE_TOPC,Mode
	move.l	#Table_ToPC,Table
	bra.w	NameParse

ToUpCaseMode:
	move.b	#MODE_TOUPCASE,Mode
	move.l	#Table_Uppercase,Table
	bra.b	NameParse

ToLowCaseMode:
	move.b	#MODE_TOLOWCASE,Mode
	move.l	#Table_Lowercase,Table
	bra.b	NameParse

AutoMode:
	tst.b	Mode_NoBuffer		; Mode_NoBuffer=0? means we have buffer
	bne.w	Err_NeedBuffer		; if not
	move.b	#MODE_AUTOMODE,Mode
	bra.b	NameParse

ModeToNull:
	move.b	#MODE_TONULL,Mode
	move.l	#Table_Null,Table
	bra.b	NameParse

ModeToOnlyASCII:
	move.b	#MODE_TOASCII,Mode
	move.l	#Table_Null,Table

NameParse:
	addq.l	#1,a0			; One after Mode
	bsr	SkipSpace
	cmp.l	#0,a0
	beq.w	Err_BadComLine
	move.l	a0,SourceNameStart
	bsr	FindEnd
	move.l	a0,SourceNameEnd	; Save source name end.
	addq.l	#1,a0			; Find the length for source name.
	sub.l	SourceNameStart,a0
	move.l	a0,SourceNameLen

	move.l	SourceNameStart,a0	; Copy the name to SourceName
	move.l	#SourceName,a1
	move.l	SourceNameLen,d0
	bsr	CopyName

	lea	SourceName,a0
	bsr	FormFileLinks
	move.l	#FileLinkBase,CurrentLink
	beq	LinkEnd

StartNewFile:
	move.l	CurrentLink,a0		; Get the next FileLink.
	move.l	(a0,fl_Next),a0
	move.l	a0,CurrentLink
	beq	LinkEnd

	clr.b	Flag_CrunchTried
	move.l	(fl_Size,a0),SourceLen
	lea	(fl_FileName,a0),a1
	move.l	#RealSourceName,a0
	bsr	StrCpy

	move.l	SourceNameEnd,a0
	addq.l	#1,a0
	tst.b	(a0)
	beq.w	NoDest
	bsr	SkipSpace
	move.l	a0,DestNameStart	; If 0, go NoDest
	beq.w	NoDest
	bsr	FindEnd
	addq.l	#1,a0			; Add 1 to DestName end, and get
	sub.l	DestNameStart,a0	; DestNameLen in a0
	move.l	a0,d0
	move.l	d0,DestNameLen
	move.l	DestNameStart,a0	; Copy the destination name to DestName.
	lea	DestName,a1
	bsr	CopyName

	move.l	#DestName,d1		; Try to lock dest filename.
	move.l	#ACCESS_READ,d2
	Call	Dos,Lock
	move.l	d0,DestLock
	beq.w	DestNameCheck		; If no lock, we'll have a file.

	move.l	DestLock,d1		; Otherwise check it
	move.l	#FIB,d2
	Call	Dos,Examine
	move.l	d0,-(sp)		; Save result code
	move.l	DestLock,d1
	Call	Dos,UnLock
	clr.l	DestLock
	move.l	(sp)+,d0		; Boolean
	beq.w	Err_DestCorrupt		; 0 means error
	lea	FIB,a0
	tst.l	fib_DirEntryType(a0)	; Dir or a file?
	bgt	DestIsDir		; > 0 means directory.

DestNameCheck:
	lea	MyAnchor,a0
	btst.b	#APB_ITSWILD,(a0,ap_Flags)
	bne	Err_FileDest
	bra 	OpenFiles

LinkEnd:
	tst.b	Flag_FileFound
	beq	Err_NoSource
	st	Flag_Stop
	bra	EndProgram

DestIsDir:
	move.l	#DestName,d1
	move.l	#RealSourceName,d2
	move.l	#256,d3
	Call	Dos,AddPart
	moveq	#3,d7
	tst.l	d0
	beq	CodeError
	bra.b	OpenFiles

NoDest:
	clr.b	Flag_DestName
	move.l	CurrentLink,a0
	add.l	#fl_FullName,a0		; If no destination name, use the
	lea	DestName,a1		; sourcename (i.e. writing on the
	bsr	CopyUntilNull		; original).
	subq.l	#1,a1

	tst.b	Mode_NoBuffer		; If we have a buffer, add no suffix.
	beq.w	ProtectSrc
	tst.b	Flag_LhAPack		; Or if we are LhA packing the source.
	bne	ProtectSrc

	cmp.b	#MODE_TOPC,Mode		; Add the right type of suffix.
	beq.b	PCSuffix
	cmp.b	#MODE_TOSF7,Mode
	beq.b	SF7Suffix

AmigaSuffix:
	lea	Text_AmigaSuf,a0
	bra.b	AddSuffix

PCSuffix:
	lea	Text_PCSuf,a0
	bra.b	AddSuffix

SF7Suffix:
	lea	Text_SF7Suf,a0

AddSuffix:
	move.b	(a0)+,(a1)+
	bne	AddSuffix

OpenFiles:
	tst.b	Mode_NoBuffer		; We have a buffer, go to OpenFilesBuf.
	beq.w	OpenFilesBuf

	bsr	AllocBuffers
	bsr	OpenCheckPP
	bsr	OpenDest
	moveq	#0,d3
	bra.w	ReadBlock

; Open file CurrentLink.fl_FullName and check if it's PowerPacked.
; If we have PP library, decrunch the file.
; If not, show error.

OpenCheckPP:
	move.l	CurrentLink,a0
	bsr	ClearPrintBuf		; Start a new buffer.
	move.l	#Text_ConvFile1,a0
	bsr	AddPrintBuf
	move.l	CurrentLink,a0
	lea	fl_FileName(a0),a0
	bsr	AddPrintBuf
	move.l	#Text_ConvFile2,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf

	move.l	CurrentLink,d1
	add.l	#fl_FullName,d1
	move.l	#MODE_OLDFILE,d2
	Call	Dos,Open
	moveq	#1,d7			; Unlikely error -code.
	move.l	d0,SourceHandle
	beq.w	CodeError

	bsr	PrintReading
	move.l	SourceHandle,d1		; Read 4 bytes.
	move.l	#TempBuf,d2
	move.l	#4,d3
	Call	Dos,Read
	cmp.l	#4,d0			; Did we read 4 bytes?
	bne	.SeekBack		; No, just seek back.
	move.l	TempBuf,d0		; Get a long from the buffer, and check
	cmp.l	#"PP20",d0		; if it is a PowerPacker datafile.
	beq.w	.PackedData
	cmp.l	#"PX20",d0		; if it is a PowerPacker datafile.
	beq.w	.PackedData

.SeekBack:
	move.l	SourceHandle,d1		; Seek back to the
	moveq	#0,d2			; beginning of the file.
	moveq	#OFFSET_BEGINNING,d3
	Call	Dos,Seek
	bsr	MakeSourceASCII
	rts

.PackedData:
	move.l	SourceHandle,d1
	Call	Dos,Close
	clr.l	SourceHandle

	move.l	_PPBase,a6
	IFD	Code020
	tst.l	a6
	ENDC
	IFND	Code020
	cmp.l	#0,a6
	ENDC
	beq	Err_PowerPacked
	tst.b	Mode_NoBuffer
	bne	Err_NeedBufPP

	move.l	#Text_Decrunching,d2
	bsr	PrintText

	st	Flag_PPUsed
	move.l	CurrentLink,a0
	add.l	#fl_FullName,a0
	moveq	#DECR_NONE,d0
	moveq	#0,d1			; Memory type.
	lea	SourcePointer,a1
	lea	SourceLen,a2
	move.l	#0,a3			; Use default PW function.
	Call	PP,ppLoadData	
	tst.l	d0
	bne	.PackedError		; If error.
	bsr	MakeSourceASCII
	rts

.PackedError:
	cmp.l	#PP_OPENERR,d0		; Should never happen, since we did
	beq	Err_SourceCorrupt	; check that it was a PP file.
	cmp.l	#PP_READERR,d0
	beq	Err_SourceCorrupt
	cmp.l	#PP_NOMEMORY,d0
	beq	Err_NoMem
	cmp.l	#PP_PASSERR,d0
	beq	Err_PassError
	cmp.l	#PP_EMPTYFILE,d0
	beq	Err_SourceCorrupt
	cmp.l	#PP_UNKNOWNPP,d0
	beq	Err_UnknownPP
	moveq	#2,d7
	bra	CodeError

ProtectSrc:
	st	Mode_SrcDeleted

OpenFilesBuf:
	bsr	OpenCheckPP

	tst.b	Flag_PPUsed		; If the file was loaded by PP, we
	beq	OpenFilesNoPP		; don't have to alloc memory or read.
	move.l	SourceLen,ReadBytes
	bra	ReadFinished

OpenFilesNoPP:
	move.l	SourceLen,d0		; Allocate for the whole source file.
	moveq	#0,d1			; No special needs for the memory.
	Call	Exec,AllocMem
	move.l	d0,SourcePointer
	beq.w	Err_NoMem

ReadFile:
	move.l	SourceHandle,d1
	move.l	SourcePointer,d2	; To our file buffer.
	add.l	ReadBytes,d2
	move.l	RBlockSize,d3
	clr.w	TickCount
	Call	Dos,Read
	cmp.l	#-1,d0
	beq.w	Err_ReadFail		; If error reading the file.
	add.l	d0,ReadBytes
	move.l	d0,-(sp)		; Save "bytes read".

	bsr	CalcReadRate		; Determine the optimal block size.

	tst.b	Mode_Quiet		; Check if we should be quiet.
	bne.b	.NoProgInfo

	bsr	ClearPrintBuf		; Start a new buffer.

	move.l	#Text_Read,a0		; Print our progress to Shell.
	bsr	AddPrintBuf

	lea	ReadASCII,a0		; First convert the number into a
	move.l	ReadBytes,d0		; string, and then add the string into
	bsr	NumToStr		; the buffer.
	move.l	a0,ReadASCIIAddr
	move.l	d0,ReadASCIILen

	bsr	AddPrintBuf

	move.l	#Text_Slash,a0
	bsr	AddPrintBuf

	move.l	SourceLenASCIIAddr,a0	; The size of the source file.
	bsr	AddPrintBuf

	move.l	#Text_CR,a0		; And back to the beginning of the line.
	bsr	AddPrintBuf
	bsr	WritePrintBuf

.NoProgInfo:
	move.l	(a7)+,d0		; How many bytes we read, if null, we're
	beq.b	ReadFinished		; finished.

	moveq	#0,d0			; Get the signals.
	moveq	#0,d1
	Call	Exec,SetSignal

	btst	#SIGBREAKB_CTRL_C,d0	; Check if ^C was pressed.
	bne.w	BreakPressed

	bra.w	ReadFile		; Read more of the file.

ReadFinished:
	bsr	AllocBuffers
	move.l	ReadBytes,LeftBytes
	tst.b	Flag_PPUsed
	bne	ReadFinished2

	move.l	SourceHandle,d1		; Close the source, since we're done.
	Call	Dos,Close
	clr.l	SourceHandle		; Note that it's closed.

ReadFinished2:
	cmp.b	#MODE_AUTOMODE,Mode	; AutoMode on?
	beq.b	DetectMode		; Determine the real mode to use.

ReadFinished1:
	bsr	OpenDest
	moveq	#0,d3
	bra.w	MoreData

DetectMode:
	move.l	#Text_Checking,d2	; Tell that we're checking the mode.
	bsr	PrintText

	moveq	#0,d2
	moveq	#0,d3
	moveq	#0,d4
	move.l	SourcePointer,a0
	cmp.l	#10240,LeftBytes	; Less data to determine with, otherwise
	bcs	DetectMode1		; use 10KB.
	move.l	#10240-1,d1

DetectMode2:
	move.b	(a0)+,d0		; Get a byte.
	cmp.b	#"{",d0			; Signs of possible SF7.
	beq.w	DM_SF7
	cmp.b	#"[",d0
	beq.w	DM_SF7
	cmp.b	#"|",d0
	beq.w	DM_SF7
	cmp.b	#"\\",d0
	beq.w	DM_SF7

	cmp.b	#"ä",d0			; Signs of possible Amiga format.
	beq.w	DM_Amy
	cmp.b	#"Ä",d0
	beq.w	DM_Amy
	cmp.b	#"ö",d0
	beq.w	DM_Amy
	cmp.b	#"Ö",d0
	beq.w	DM_Amy

	IFD	Code020
	cmp2.b	BoundPC(pc),d0
	bhi	DM_PC
	ENDC
	IFND	Code020
	cmp.b	#$80,d0
	bcc	.CheckUpper
	bra.b	.Outside

.CheckUpper:
	cmp.b	#$90,d0
	bls	DM_PC

.Outside:
	ENDC
	cmp.b	#$94,d0
	beq.w	DM_PC
	cmp.b	#$99,d0
	beq.w	DM_PC

	cmp.b	#CR,d0			; CR, can't be an Amiga format.
	beq.w	DM_Foreign
	bra	DetectMode3

	IFD	Code020

BoundPC:
	dc.b	$7f
	dc.b	$91

	ENDC

DetectMode3:
	dbf	d1,DetectMode2		; If bytes left to check, do so.

	cmp.l	d2,d3			; xx0
	beq.w	SameWarn1
	cmp.l	d2,d4			; x0x
	beq.w	SameWarn1
	cmp.l	d3,d4			; 0xx
	beq.w	SameWarn2

DetectMode4:
	movem.l	d2-d4,-(a7)
	move.l	#Text_Uses,d2		; Tell what mode it uses.
	bsr	PrintText
	movem.l	(a7)+,d2-d4

	cmp.l	d2,d3			; SF7 or Amy
	bhi	DM_NotSF7

DM_NotAmy:
	cmp.l	d2,d4			; SF7 or PC
	bhi	DM_MakePC
	bra.b	DM_MakeSF7

DM_NotSF7:
	cmp.l	d3,d4			; Amy or PC
	bhi	DM_MakePC

DM_MakeAmy:
	move.b	#MODE_TONULL,Mode	; Amiga file, use Null mode.
	move.l	#Table_Null,Table

	move.l	#Text_NullMode,d2	; Tell the user that.
	bsr	PrintText

	bra.w	ReadFinished1

DM_MakePC:
	move.b	#MODE_FROMPC,Mode	; PC file, use FromPC mode.
	move.l	#Table_FromPC,Table

	move.l	#Text_PCMode,d2		; And tell that.
	bsr	PrintText

	bra.w	ReadFinished1

DM_MakeSF7:
	move.b	#MODE_FROMSF7,Mode	; SF7 file, use FromSF7 mode.
	move.l	#Table_FromSF7,Table
	move.l	#Text_SF7Mode,d2	; Tell it.
	bsr	PrintText
	bra.w	ReadFinished1

SameWarn1:
	cmp.l	d3,d4			; Could be either one.
	beq.w	Err_SameProbability
	bra.w	DetectMode4

SameWarn2:				; Same as above.
	cmp.l	d2,d3
	beq.w	Err_SameProbability
	bra.w	DetectMode4

DetectMode1:				; Since we don't have 10KB for
	move.l	LeftBytes,d1		; comparing, take all we can get.
	subq.l	#1,d1
	bra.w	DetectMode2

DM_SF7:
	addq.l	#1,d2			; One point to SF7.
	bra.w	DetectMode3

DM_Amy:
	addq.l	#1,d3			; One to Amiga.
	bra.w	DetectMode3

DM_PC:
	addq.l	#1,d4			; etc...
	bra.w	DetectMode3

DM_Foreign:
	addq.l	#1,d2			; One point to SF7 and PC.
	addq.l	#1,d4
	bra.w	DetectMode3

ReadBlock:
	tst.b	Mode_NoBuffer
	beq.b	MoreData		; We have a buffer -> MoreData
	movem.l	d0/d2-d7/a0-a6,-(sp)
	bsr	PrintReading
	move.l	SourceHandle,d1		; Otherwise read.
	move.l	SourcePointer,d2
	move.l	Size_SrcBuf,d3
	Call	Dos,Read
	cmp.l	#-1,d0
	beq.w	Err_ReadFail		; Couldn't read?  -> Err_ReadFail.
	add.l	d0,ReadBytes
	add.l	d0,InputBytes
	move.l	d0,d1
	beq.b	RB_CloseFiles		; !ReadBytes -> Quit.
	movem.l	(sp)+,d0/d2-d7/a0-a6
	movem.l	d0/d2-d7/a0-a6,-(sp)
	bsr	PrintStats
	movem.l	(sp)+,d0/d2-d7/a0-a6
	subq.l	#1,d1			; Counter always one less than loops.
	move.l	SourcePointer,a0	; Buffer locations to regs.
	bra.w	CheckOutBuf		; Continue converting.

RB_CloseFiles:				; Same as CloseFiles, but pops
	movem.l	(sp)+,d0/d2-d7/a0-a6	; the regs after ReadBlock messing with
	bra.w	CloseFiles		; them.

MoreData:
	tst.l	LeftBytes		; We have no more bytes left?
	beq.w	CloseFiles		; -> Quit.
	move.l	LeftBytes,d1
	clr.l	LeftBytes
	move.l	SourcePointer,a0
	add.l	InputBytes,a0
	add.l	d1,InputBytes
	subq.l	#1,d1			; Loop counter starts from 0, i.e. -1.
	bra.w	CheckOutBuf

MoreCharacters:
	move.b	(a0)+,d0		; Get a new byte from the buffer.
	and.w	#$ff,d0			; a3 contains the table base-address.
	move.l	d3,-(sp)
	move.b	(a3,d0.w),d0		; Replace the original character.
	beq.b	NoChar			; $00 - Trash this byte.

	tst.b	Flag_AStrip
	beq.b	.NoAStrip
	bsr	ANSIStrip
	bra.b	NoChar

.NoAStrip:
	tst.b	Flag_INStrip
	beq.b	.NoINStrip
	bsr	InterNetStrip
	bra.b	NoChar

.NoINStrip:
	bsr	WhiteProcess
	tst.l	d0			; Null = Insert nothing.
	beq.b	NoChar
	bsr	InsertInDest

NoChar:
	move.l	(sp)+,d3
	addq.l	#1,d3			; Total bytes converted.
	subq.l	#1,d1			; One less byte in the read buffer.
	bmi	ReadBlock		; Went negative, load more.

CheckOutBuf:				; Have we converted a full buffer yet?
	tst.b	Flag_StatsDue
	bne.b	.DoStats

.ContCheckOutBuf:
	move.l	Size_DstBuf,d0
	sub.l	#SIZE_MAXNEW,d0
	cmp.l	d0,d2
	bcs	MoreCharacters		; Everything okay, continue conversion.
	bra	WriteDestBuf

.DoStats:
	bsr	PrintStats
	bra	.ContCheckOutBuf

WriteDestBuf:
	movem.l	d1/d3-d7/a0/a2-a5,-(sp)
	move.l	d3,-(sp)
	bsr	PrintWriting
	move.l	DestHandle,d1		; Write the converted data.
	move.l	d2,d3			; Number of bytes to write.
	add.l	d2,WrittenBytes		; Add the buffer to WrittenBytes.
	move.l	DestPointer,d2
	Call	Dos,Write
	cmp.l	#-1,d0
	beq.w	Err_WriteFail
	tst.b	Mode_SrcDeleted		; If the sourcefile has been destroyed,
	bne.b	.NoBreak		; don't allow breaking.
	move.l	(sp)+,d3
	bsr	PrintStats
	moveq	#0,d0			; Get the signals.
	moveq	#0,d1
	Call	Exec,SetSignal
	btst	#SIGBREAKB_CTRL_C,d0	; Check if ^C was pressed
	bne.w	BreakPressed

.NoBreak:
	movem.l	(sp)+,d1/d3-d7/a0/a2-a5
	moveq	#0,d2			; No converted bytes now.
	move.l	DestPointer,a1
	bra.w	MoreCharacters

CloseFiles:
	tst.l	EOLs
	beq	.NoEOLsLeft
	addq.l	#1,d2
	bsr	InsertSingleEOL
	tst.b	Mode			; If ToPC or ToSF7, add a CR too.
	bpl	.NoEOLsLeft
	addq.l	#1,d2

.NoEOLsLeft:
	bsr	PrintWriting
	move.l	d2,d3			; Do we have stuff in DestBuf?
	beq.b	CF_TellData		; No, show the final stats.
	move.l	DestHandle,d1		; We do, flush it.
	add.l	d2,WrittenBytes		; Add the buffer to WrittenBytes.
	move.l	DestPointer,d2
	Call	Dos,Write
	cmp.l	#-1,d0
	beq.w	Err_WriteFail

CF_TellData:
	bsr	ClearPrintBuf		; Tell the file size change.
	move.l	#Text_Final,a0
	bsr	AddPrintBuf

	move.l	WrittenBytes,d0

	sub.l	ReadBytes,d0
	bmi	CloseFiles1		; Negative

	move.l	d0,d7
	beq.b	CloseFiles2		; If zero, no sign.

	move.l	#Text_PosSign,a0
	bsr	AddPrintBuf

	bra.b	CloseFiles2

CloseFiles1:
	neg.l	d0
	move.l	#Text_NegSign,a0
	bsr	AddPrintBuf

CloseFiles2:
	lea	NumberBuf,a0
	bsr	NumToStr
	bsr	AddPrintBuf

	move.l	#Text_DoubleSpace,a0
	bsr	AddPrintBuf

	move.l	WrittenBytes,d0
	move.l	ReadBytes,d1
	bsr	Percentage

	lea	NumberBuf,a0
	bsr	NumToStr

	bsr	AddPrintBuf

	move.l	#Text_PercentSign,a0
	bsr	AddPrintBuf

	move.l	#Text_LF,a0
	bsr	AddPrintBuf
	tst.b	Flag_CrunchBuf
	bne	.OnlyOneLF
	move.l	#Text_LF,a0
	bsr	AddPrintBuf

.OnlyOneLF:
	bsr	WritePrintBuf
	bra.w	EndProgram

HelpText:
	st	Flag_Stop
	move.l	#Text_HelpText,d2
	bsr	PrintText
	bra.w	EndProgram

Credits:
	st	Flag_Stop
	move.l	#Text_Credits,d2
	bsr	PrintText
	bra.w	EndProgram

********************
** ERROR ROUTINES **
********************

CodeError:
	st	Flag_Stop
	move.l	d7,-(sp)
	move.l	#Text_CodeError,d2
	bsr	PrintText
	lea	NumberBuf,a0
	move.l	(sp)+,d0
	bsr	NumToStr
	move.l	a0,d2
	move.l	d0,d3
	bsr	PrintTextLen
	move.l	#Text_LF,d2
	bsr	PrintText
	bra.w	EndProgram

Err_CrunchReadWrite:
	move.l	#Text_CrunchReadWrite,d2
	bra	ShowErrNonFatal

Err_CrunchOverflow:
	move.l	#Text_CrunchOverflow,d2
	bra	ShowErrNonFatal

Err_NoCrunchMem:
	move.l	#Text_NoCrunchMem,d2
	bra	ShowErrNonFatal

Err_NoCrunchFile:
	move.l	#Text_NoCrunchFile,d2
	bra	ShowErrNonFatal

Err_NeedBufPP:
	move.l	#Text_NeedBufPP,d2
	bra	ShowErr

Err_UnknownPP:
	move.l	#Text_UnknownPP,d2
	bra	ShowErr

Err_PassError:
	move.l	#Text_WrongPass,d2
	bra	ShowErr

Err_FileDest:
	move.l	#Text_FileDest,d2
	bra	ShowErr

	IFD	Code020

Err_OldProcessor:
	move.l	#Text_OldProcessor,d2
	bra	ShowErr

	ENDC

Err_NewerKickNeeded:
	move.l	#Text_NewKickNeed,d2
	bra	ShowErr

Err_NoSource:
	move.l	#Text_NoSource,d2
	bra.b	ShowErr

Err_BadComLine:
	move.l	#Text_BadComLine,d2
	bra.b	ShowErr

Err_NoDest:
	move.l	#Text_NoDest,d2
	bra.b	ShowErr

Err_NoComLineSpace:
	move.l	#Text_NoComLineSpace,d2
	bra.b	ShowErr

Err_BadLogic:
	move.l	#Text_BadLogic,d2
	bra.b	ShowErr

Err_NoMem:
	move.l	#Text_NoMemory,d2
	bra.b	ShowErr

Err_PowerPacked:
	move.l	#Text_PowerPacked,d2
	bra.b	ShowErr

Err_SeekFail:
Err_ReadFail:
Err_SourceCorrupt:
	move.l	#Text_BadSource,d2
	bra.b	ShowErr

Err_DestCorrupt:
	move.l	#Text_BadDest,d2
	bra.b	ShowErr

Err_SourceIsDir:
	move.l	#Text_SourceIsDir,d2
	bra.b	ShowErr

Err_WriteFail:
	move.l	#Text_WriteFail,d2
	bra.b	ShowErr

Err_NeedBuffer:
	move.l	#Text_NeedBuffer,d2
	bra.b	ShowErr

Err_SameProbability:
	move.l	#Text_SameProbability,d2
	bra.b	ShowErr

BreakPressed:
	st	Flag_Stop
	move.l	#Text_Break,d2
	bsr	PrintText
	bra.b	EndProgramErr

ShowErrNonFatal:
	move.l	d2,-(sp)
	bsr	ClearPrintBuf
	lea	Text_Warning,a0
	bsr	AddPrintBuf
	move.l	(sp)+,a0
	bsr	AddPrintBuf
	lea	Text_ClearEOL,a0
	bsr	AddPrintBuf
	lea	Text_LF,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf
	bra.b	EndProgram

ShowErr:
	move.l	d2,-(sp)
	bsr	ClearPrintBuf
	lea	Text_Error,a0
	bsr	AddPrintBuf
	move.l	(sp)+,a0
	bsr	AddPrintBuf
	lea	Text_ClearEOL,a0
	bsr	AddPrintBuf
	lea	Text_LF,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf
	bra.b	EndProgramErr

EndProgram:
	clr.b	Mode_DeleteErrDest
	bra	EndProgramNoErr

EndProgramErr:
	st	Flag_Stop

EndProgramNoErr:
	move.l	SourceHandle,d1
	beq.b	EndProgram1
	Call	Dos,Close
	clr.l	SourceHandle

EndProgram1:
	move.l	DestHandle,d1
	beq.b	EndProgram2
	Call	Dos,Close
	clr.l	DestHandle

EndProgram2:
	move.l	SourceLock,d1
	beq.b	EndProgram3
	Call	Dos,UnLock
	clr.l	SourceLock

EndProgram3:
	move.l	DestLock,d1
	beq.b	EndProgram4
	Call	Dos,UnLock
	clr.l	DestLock

EndProgram4:
	tst.b	Mode_DeleteErrDest
	beq.b	EndProgram5
	bsr	ClearPrintBuf
	lea	Text_Quote,a0
	bsr	AddPrintBuf
	lea	DestName,a0
	bsr	AddPrintBuf
	lea	Text_Deleted,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf
	move.l	#DestName,d1
	Call	Dos,DeleteFile

EndProgram5:
	move.l	BigBufPtr,a1
	tst.l	a1
	beq.b	EndProgram6
	move.l	BigBufSize,d0
	Call	Exec,FreeMem
	clr.l	BigBufPtr
	bra	EndProgram6

EndProgram6:
	tst.b	Mode_NoBuffer
	bne.b	EndProgram7
	move.l	SourcePointer,a1
	tst.l	a1
	beq.b	EndProgram7
	move.l	SourceLen,d0
	Call	Exec,FreeMem
	clr.l	SourcePointer

EndProgram7:
	move.l	OldDirLock,d1
	beq	EndProgram8
	Call	Dos,CurrentDir
	clr.l	OldDirLock

EndProgram8:
	move.l	CrBuf,a1
	IFD	Code020
	tst.l	a1
	ENDC
	IFND	Code020
	cmp.l	#0,a1
	ENDC
	beq	EndProgram9
	move.l	CrBuf,a1
	move.l	CrSize,d0
	Call	Exec,FreeMem
	clr.l	CrBuf

EndProgram9:
	move.l	CrFile,d1
	beq	EndProgram10
	Call	Dos,Close
	clr.l	CrFile

EndProgram10:
	move.l	CrCrunchInfo,a0
	IFD	Code020
	tst.l	a0
	ENDC
	IFND	Code020
	cmp.l	#0,a0
	ENDC
	beq	EndProgram11
	Call	PP,ppFreeCrunchInfo
	clr.l	CrCrunchInfo

EndProgram11:
	tst.b	Flag_Stop
	bne.b	EndProgram12
	tst.b	Flag_CrunchBuf
	bne.b	.Cont
	tst.b	Flag_LhAPack
	bne.b	.Cont
	bra.b	EndProgram12

.Cont:
	tst.b	Flag_CrunchTried
	bne.b	EndProgram12
	bsr	CrunchDestFile

EndProgram12:
	lea	CrunchSrcName,a0
	tst.b	(a0)
	beq.b	EndProgram13
	move.l	a0,d1
	Call	Dos,DeleteFile
	lea	CrunchSrcName,a0
	clr.b	(a0)

EndProgram13:
	tst.b	Flag_DestName		; We had a destination, continue.
	bne.b	EndProgram14
	tst.b	Flag_LhAPack		; The file wasn't LhA'ed.
	beq.b	EndProgram14
	move.l	#SourceName,d1		; LhA & No destination = Delete source.
	Call	Dos,DeleteFile

EndProgram14:
	tst.b	Flag_Stop
	bne	EndProgram15
	bsr	ClearVars
	bra	StartNewFile

EndProgram15:
	tst.b	Flag_AnchorUsed
	beq	EndProgram16
	move.l	#MyAnchor,d1
	Call	Dos,MatchEnd

EndProgram16:
	move.l	_PPBase,a1
	IFD	Code020
	tst.l	a1
	ENDC
	IFND	Code020
	cmp.l	#0,a1
	ENDC
	beq	EndProgram17
	Call	Exec,CloseLibrary

EndProgram17:
	tst.b	Flag_IntActive
	beq.b	EndProgram18
	moveq	#INTB_VERTB,d0		; Remove the counter interrupt.
	lea	VertBInterrupt,a1
	Call	Exec,RemIntServer

EndProgram18:
	move.l	FileLinkBase,a2
	cmp.l	#0,a2
	beq	EndProgramFinal

.ContFree:
	move.l	a2,a1
	move.l	(a2,fl_Next),a2		; Get the link after this one.
	move.l	#fl_SIZEOF,d0
	Call	Exec,FreeMem
	cmp.l	#0,a2
	bne	.ContFree

EndProgramFinal:
	move.l	#Text_CursorOn,d2
	bsr	PrintText
	move.l	_DosBase,a1
	Call	Exec,CloseLibrary
	moveq	#0,d0			; *!* Add some error codes.
	move.l	OldStack,sp		; At least it's ok this way...
	rts

*********************
** VERTB INTERRUPT **
*********************

; On a 14.3MHz CPU the interrupt code takes .03% of the total cycles/sec.
; Without the code, we could convert 13 more bytes/sec, as the conversion
; rate is currently 50kB/sec.

VertBIntCode:
	addq.b	#1,(a1)			; Add the frame counter.              12
	addq.w	#1,4(a1)		; Add the tick counter.               16
	move.b	1(a1),d0		; Get TickDelay.			      12
	cmp.b	(a1),d0			; One second passed?                   8
	bls.b	.StuffDue		;                                   10/8
	moveq	#0,d0			;                                      4
	rts				;                                     16

.StuffDue:
	clr.b	(a1)			; Reset counter.                      12
	st	2(a1)			; Set statistics due flag.            16
	moveq	#0,d0			;                                      4
	rts				;                                     16

**********
** SUBS **
**********

ANSIStrip:
	cmp.b	#ANSI_WAIT,Flag_ANSIState
	beq	.Wait
	bcs	.Clear
	bhi	.Code
	move.w	#$f00,$dff180
	rts

.Wait:
	cmp.b	#"[",d0
	beq	.On
	move.b	#ANSI_CLEAR,Flag_ANSIState
	move.l	d0,-(sp)
	move.l	#$1b,d0			; *!* Only if IN strip is on.
	bsr	InsertANSIOn
	move.l	(sp)+,d0
	bsr	InsertANSIOn
	rts

.On:
	move.b	#ANSI_CODE,Flag_ANSIState
	rts

.Code:
	cmp.b	#"A",d0
	bcc	.Check1
	bra.b	.Check2

.Check1:
	cmp.b	#"Z",d0
	bls	.Off

.Check2:
	cmp.b	#"a",d0
	bcc	.Check3
	rts

.Check3:
	cmp.b	#"z",d0
	bls	.Off
	rts

.Off:
	move.b	#ANSI_CLEAR,Flag_ANSIState
	rts

.Clear:
	cmp.b	#$1b,d0
	beq.b	.GoWait
	cmp.b	#$9b,d0
	beq.b	.On
	bsr	InsertANSIOn
	rts

.GoWait:
	move.b	#ANSI_WAIT,Flag_ANSIState
	rts

InsertANSIOn:
	tst.b	Flag_INStrip
	beq.b	.NoINStrip
	bsr	InterNetStrip
	rts

.NoINStrip:
	bsr	WhiteProcess
	tst.l	d0			; Null = Insert nothing.
	bne.b	.Insert
	rts

.Insert:
	bsr	InsertInDest
	rts	

InsertInDest:
	move.b	d0,(a1)+		; Store the translated byte in the buf.
	addq.l	#1,d2			; Add the bytes to be saved.
	addq.w	#1,Col			; And add the column counter.
	rts

InterNetStrip:
	move.b	d0,(a4)+		; Insert the byte.
	addq.w	#1,INBufSize		; If it was an EOL, we have a full line.
	cmp.b	#LF,d0
	beq.b	.FullLine
	cmp.b	#CR,d0
	beq.b	.FullLine
	rts

.FullLine:
	SaveR
	move.w	INBufSize,d0
	lea	InterNetBuf,a4
	clr.b	(a4,d0.w)
	tst.b	Flag_INStripActive	; If strip is not active, check if it
	beq.b	.TestInterNet		; should be made active.
	clr.w	INBufSize		; Otherwise kill this line, and check
	cmp.b	#LF,(a4)		; if stripping should continue.
	beq.b	.CutOff
	cmp.b	#CR,(a4)
	beq.b	.CutOff
	LoadR
	lea	InterNetBuf,a4
	rts

.CutOff:
	clr.b	Flag_INStripActive
	cmp.b	#1,Flag_INStrip
	beq	.InsertInfo
	LoadR
	bsr	ResetArea
	lea	InterNetBuf,a4
	rts

.InsertInfo:
	lea	InterNetBuf,a0
	lea	Text_INRemoved,a1
	bsr	StrCpy
	move.w	#81,INBufSize
	LoadR
	bsr	ResetArea
	lea	InterNetBuf,a4
	add.l	#81,a4
	rts

.TestInterNet:
	move.l	a4,a0			; Check if there's a period in the line.
	moveq	#".",d0
	bsr	StrChr
	tst.l	d0
	bne.b	.Cont			; If so, a possible header line.
	bra.b	.FeedLine		; If not, just feed the line on.

.Cont:
	move.l	a4,a0			; Check for an exclamation mark, if
	moveq	#"!",d0			; found this could be a header start.
	bsr	StrChr
	tst.l	d0
	bne.b	.Cont1
	bra.b	.FeedLine		; Otherwise just feed the line.

.Cont1:
	move.l	a4,a0			; Check if the line starts "From ".
	lea	Text_INFrom,a1
	moveq	#5,d0
	bsr	StrNCmp
	tst.l	d0
	beq.b	.PossibFrom
	move.l	a4,a0			; Check if the line starts "Path: ".
	lea	Text_INPath,a1
	moveq	#6,d0
	bsr	StrNCmp
	tst.l	d0
	beq.b	.CutOn
	bra.b	.FeedLine		; Otherwise it's not a header start.

.PossibFrom:
	move.l	a4,a0			; If "From ", must also have a date and
	bsr	StrFirstNum		; time, which means numbers.
	tst.l	d0
	bne.b	.CutOn			; Found, turn on the cut.

.FeedLine:
	LoadR
	move.w	INBufSize,d7
	ext.l	d7			; *!*
	subq.w	#1,d7
	lea	InterNetBuf,a4

.FeedByte:
	addq.l	#1,d3			; Total bytes converted.
	move.b	(a4)+,d0
	bsr	WhiteProcess
	tst.l	d0			; Null = Insert nothing.
	beq.b	.NoInsert
	bsr	InsertInDest

.NoInsert
	dbf.b	d7,.FeedByte
	lea	InterNetBuf,a4
	clr.w	INBufSize
	rts

.CutOn:
	clr.w	INBufSize
	st	Flag_INStripActive
	LoadR
	lea	InterNetBuf,a4
	rts

WhiteProcess:
	cmp.b	#" ",d0			; Process white.
	beq.b	FoundSpace
	bhi.b	FoundBlack
	cmp.b	#TAB,d0
	beq.b	FoundTab
	cmp.b	#LF,d0
	beq.b	FoundLF
	bra.b	FoundBlack

FoundSpace:
	tst.b	TabSize			; Test for Tab-Space conversion.
	beq.b	.NoSpaceTab
	addq.l	#1,SpaceNumber
	addq.w	#1,Col
	tst.b	SpaceSize
	bne.b	.SpaceConv
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

.SpaceConv:
	bsr	SpaceConv
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

.NoSpaceTab:
	bsr	BufChar
	moveq	#0,d0			; Insert nothing in write buffer.
	rts	

FoundTab:
	tst.b	TabSize			; Test for Tab-Space conversion.
	beq	.NoSpaceTab
	bsr	TabConv
	tst.b	SpaceSize
	bne	.SpaceConv
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

.SpaceConv:
	bsr	SpaceConv
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

.NoSpaceTab:
	bsr	BufChar
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

FoundLF:
	clr.w	Col
	tst.b	Mode_NoCutSpace
	bne.b	.NoEndSpaceRem
	addq.l	#1,EOLs
	bsr	ResetArea
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

.NoEndSpaceRem:
	bsr	FlushArea
	bsr	InsertOneEOL	
	moveq	#0,d0			; Insert nothing in write buffer.
	rts

FoundBlack:
	bsr	InsertEOLs
	move.b	Size_MakeEOLs,d3
	beq	.NoMakeEOLs
	BToLong	d3
	cmp.l	SpaceNumber,d3
	bhi	.NoMakeEOLs
	bsr	ResetArea
	bsr	InsertSingleEOL
	addq.l	#1,d2
	rts

.NoMakeEOLs:
	bsr	FlushArea	
	rts

; Gets the number starting at A0, and ending in a non-number. Returns it in
; D0.

GetNum:
	lea	.MySpace,a1

.Loop:
	cmp.b	#"0",(a0)
	bcc.b	.CheckLow
	bra.b	.End

.CheckLow:
	cmp.b	#"9",(a0)
	bls.b	.Copy
	bra.b	.End

.Copy:
	move.b	(a0)+,(a1)+
	bra.b	.Loop

.End:
	clr.b	(a1)
	lea	.MySpace,a0
	bsr	StrToNum
	rts

.MySpace:
	ds.b	11

	CNOP	0,4

; Finds a space, tab, LF, CR or a null from a string pointed by A0. Returns
; location in A0.

FindWhite:
	cmp.b	#" ",(a0)
	beq	.Found
	cmp.b	#TAB,(a0)
	beq	.Found
	cmp.b	#LF,(a0)
	beq	.Found
	cmp.b	#CR,(a0)
	beq	.Found
	tst.b	(a0)
	beq	.Found
	addq.l	#1,a0
	bra	FindWhite

.Found:
	rts

LoadPrefs:
	move.l	#PrefName,d1
	move.l	#MODE_OLDFILE,d2
	Call	Dos,Open
	move.l	d0,PrefHandle
	beq	.PrefsError

	move.l	d0,d1
	move.l	#FIB,d2
	Call	Dos,ExamineFH
	tst.l	d0
	beq	.PrefsError

	lea	FIB,a0
	move.l	fib_Size(a0),Size_Prefs
	move.l	Size_Prefs,d0
	moveq	#0,d1
	Call	Exec,AllocMem
	move.l	d0,PrefPtr
	move.l	d0,PrefDecode
	beq	.PrefsError

	move.l	PrefHandle,d1
	move.l	PrefPtr,d2
	move.l	Size_Prefs,d3
	Call	Dos,Read
	cmp.l	#-1,d0
	beq	.PrefsError

.ContDecode:
	move.l	PrefDecode,a0
	bsr	SkipCrap
	tst.b	(a0)
	beq	EndPrefs
	bsr	CopySymbol
	tst.l	d0
	beq	EndPrefs
	move.l	a0,PrefDecode
	bsr	DetermineArg
	move.l	d0,-(sp)

	lea	CopySymbolBuf,a0
	lea	Text_ANSIStrip,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_ANSIStrip

	lea	CopySymbolBuf,a0
	lea	Text_INStrip,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_INStrip

	lea	CopySymbolBuf,a0
	lea	Text_ConvBuf,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_ConvBuf

	lea	CopySymbolBuf,a0
	lea	Text_MakeEOLs,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_MakeEOLs

	lea	CopySymbolBuf,a0
	lea	Text_EndSpaceRemoval,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_EndSpaceRemoval

	lea	CopySymbolBuf,a0
	lea	Text_PowerPackOutput,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_PowerPackOutput

	lea	CopySymbolBuf,a0
	lea	Text_SpacesToTabs,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_SpacesToTabs

	lea	CopySymbolBuf,a0
	lea	Text_TabsToSpaces,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_TabsToSpaces

	lea	CopySymbolBuf,a0
	lea	Text_Quiet,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_Quiet

	lea	CopySymbolBuf,a0
	lea	Text_TickDelay,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_TickDelay

	lea	CopySymbolBuf,a0
	lea	Text_TempDir,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_TempDir

	lea	CopySymbolBuf,a0
	lea	Text_LhAPack,a1
	bsr	StrCmp
	tst.l	d0
	beq	.Opt_LhAPack

	addq.l	#4,sp			; Pop D0 ("arg") from stack.
	lea	PrintBuf,a0
	lea	Text_UnknownOpt,a1
	bsr	StrCpy
	lea	PrintBuf,a0
	lea	CopySymbolBuf,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_Quote,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_Period,a1
	bsr	StrCat

	lea	PrintBuf,a0
	bsr	StrLFCat
	bsr	WritePrintBuf
	bra	EndPrefs

.Opt_ANSIStrip:
	move.l	(sp)+,d0
	bmi	.Opt_ANSIStripTrue
	clr.b	Flag_AStrip
	bra	.ContDecode

.Opt_ANSIStripTrue:
	st	Flag_AStrip
	bra	.ContDecode

.Opt_INStrip:
	move.l	(sp)+,d0
	bmi	.BadOptArg
	bne.b	.Opt_INStripTrue
	clr.b	Flag_INStrip
	bra	.ContDecode

.Opt_INStripTrue:
	cmp.l	#1,d0
	bne.b	.Opt_INStripCheck
	move.b	d0,Flag_INStrip
	bra	.ContDecode

.Opt_INStripCheck:
	cmp.l	#2,d0
	bne.b	.BadOptArg
	move.b	d0,Flag_INStrip
	bra	.ContDecode

.Opt_ConvBuf:
	move.l	(sp)+,d0
	bmi	.Opt_ConvBufTrue
	st	Mode_NoBuffer
	bra	.ContDecode

.Opt_ConvBufTrue:
	clr.b	Mode_NoBuffer
	bra	.ContDecode

.Opt_Quiet:
	move.l	(sp)+,d0
	bmi	.Opt_QuietTrue
	bra	.ContDecode

.Opt_QuietTrue:
	st	Mode_Quiet
	bra	.ContDecode

.Opt_MakeEOLs:
	move.l	(sp)+,d0
	beq	.ContDecode
	cmp2.b	.MakeEOLsRange,d0
	bcs	.BadOptArg
	move.b	d0,Size_MakeEOLs
	bra	.ContDecode

.MakeEOLsRange:
	dc.b	1
	dc.b	99

.Opt_EndSpaceRemoval:
	move.l	(sp)+,d0
	beq	.Opt_EndSpaceRemoval1
	bra	.ContDecode

.Opt_EndSpaceRemoval1:
	tst.b	Size_MakeEOLs
	bne.b	.OptConflict
	st	Mode_NoCutSpace
	bra	.ContDecode

.Opt_PowerPackOutput:
	move.l	(sp)+,d0
	bne.b	.Opt_PowerPackOutput1
	bra.b	.ContDecode

.Opt_PowerPackOutput1:
	st	Flag_CrunchBuf
	bra.b	.ContDecode

.Opt_TempDir:
	move.l	(sp)+,d0
	cmp.l	#-1,d0
	beq	.ContDecode		; TempDir was OFF.
	cmp.l	#-2,d0
	bne	.BadTempDir		; The argument wasn't a string? Error.
	lea	TempDir,a0
	lea	StrBuf,a1
	bsr	StrCpy
	move.l	#TempDir,d1
	move.l	#ACCESS_READ,d2
	Call	Dos,Lock
	move.l	d0,d1
	beq	.BadTempDir		; Can't find TempDir? Error.
	move.l	d0,-(sp)
	move.l	#FIB,d2
	Call	Dos,Examine
	move.l	d0,-(sp)
	move.l	4(sp),d1
	Call	Dos,UnLock
	move.l	(sp)+,d0		; Can't examine TempDir? Error.
	beq	.BadTempDir
	addq.l	#4,sp			; Get rid of the lock on the stack.
	lea	FIB,a0
	tst.l	fib_DirEntryType(a0)	; Not a directory? Error.
	beq	.BadTempDir
	bmi	.BadTempDir
	bra.w	.ContDecode

.BadTempDir:
	clr.b	TempDir
	bra	.BadOptArg

.Opt_SpacesToTabs:
	move.l	(sp)+,d0
	beq	.ContDecode
	cmp2.b	.SpacesToTabsRange,d0
	bcs	.BadOptArg
	tst.b	TabSize
	bne.b	.OptConflict
	move.b	d0,SpaceSize
	move.b	d0,TabSize
	bra	.ContDecode

.SpacesToTabsRange:
	dc.b	2
	dc.b	16

.Opt_TabsToSpaces:
	move.l	(sp)+,d0
	beq	.ContDecode
	cmp2.b	.TabsToSpacesRange,d0
	bcs	.BadOptArg
	tst.b	SpaceSize
	bne.b	.OptConflict
	move.b	d0,TabSize
	bra	.ContDecode

.TabsToSpacesRange:
	dc.b	1
	dc.b	16

.Opt_TickDelay:
	move.l	(sp)+,d0
	cmp2.b	.TickRange,d0
	bcs	.TickVB
	move.b	d0,TickDelay
	bra	.ContDecode

.TickVB:
	move.l	4.w,a6
	move.l	VBlankFrequency(a6),TickDelay
	bra	.ContDecode

.TickRange:
	dc.b	1
	dc.b	255

.Opt_LhAPack:
	move.l	(sp)+,d0
	beq.b	.Opt_LhAPackOff
	cmp.l	#-1,d0
	bne	.BadOptArg
	tst.b	Flag_CrunchBuf
	bne.b	.OptConflict
	st	Flag_LhAPack
	bra	.ContDecode

.Opt_LhAPackOff:
	clr.b	Flag_LhAPack
	bra	.ContDecode

.BadOptArg:
	lea	PrintBuf,a0
	lea	Text_BadOptArg,a1
	bsr	StrCpy

	lea	PrintBuf,a0
	lea	CopySymbolBuf,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_Quote,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_Period,a1
	bsr	StrCat

	lea	PrintBuf,a0
	bsr	StrLFCat
	bsr	WritePrintBuf
	bra	EndPrefs

.OptConflict:
	lea	PrintBuf,a0
	clr.b	(a0)
	lea	Text_Error,a1
	bsr	StrCat
	lea	PrintBuf,a0
	lea	Text_OptConflict,a1
	bsr	StrCat
	lea	PrintBuf,a0
	bsr	StrLFCat
	bsr	WritePrintBuf
	bra	EndPrefs

.PrefsError:
	move.l	#Text_PrefsError,d2
	bsr	PrintText

EndPrefs:
	move.l	PrefHandle,d1
	beq	.EndPrefs1
	Call	Dos,Close

.EndPrefs1:
	move.l	PrefPtr,a1
	tst.l	a1
	beq	.EndPrefs2
	move.l	Size_Prefs,d0
	Call	Exec,FreeMem

.EndPrefs2:
	rts

SkipCrap:
	move.b	(a0),d0
	cmp2.b	CapRange,d0
	bcs	.CheckLow
	rts

.CheckLow:
	move.b	(a0),d0
	cmp2.b	LowRange,d0
	bcs	.CheckOther
	rts

.CheckOther:
	cmp.b	#";",(a0)
	bne	.SkipChar
	bsr	SkipLine
	subq.l	#1,a0

.SkipChar:
	addq.l	#1,a0
	tst.b	(a0)
	bne	SkipCrap
	rts

CopySymbol:
	lea	CopySymbolBuf,a1

.ContCopy:
	move.b	(a0),d0
	cmp2.b	CapRange,d0
	bcs	.CheckLow
	move.b	(a0)+,(a1)+
	bra	.ContCopy

.CheckLow:
	move.b	(a0),d0
	cmp2.b	LowRange,d0
	bcs	.CheckOther
	move.b	(a0)+,(a1)+
	bra	.ContCopy

.CheckOther:
	tst.b	(a0)
	bne	.StillLeft
	moveq	#0,d0
	rts

.StillLeft:
	cmp.b	#"=",(a0)		; Only a-Z & =, otherwise skip the whole
	bne	.SkipThisLine		; line.
	addq.l	#1,a0			; Skip the "=".
	clr.b	(a1)
	moveq	#-1,d0
	rts

.SkipThisLine:
	bsr	SkipLine
	bra	CopySymbol

SkipLine:
	cmp.b	#"\n",(a0)+
	bne	.SkipLine2
	rts

.SkipLine2:
	tst.b	(a0)
	bne	SkipLine
	rts

DetermineArg:
	lea	StrBuf,a1

.NextChar:
	cmp.b	#'"',(a0)
	beq.b	.String
	cmp.b	#"O",(a0)		; Copy bytes that match O,N,F,0-9.
	beq.b	.GoodChar
	cmp.b	#"N",(a0)
	beq.b	.GoodChar
	cmp.b	#"F",(a0)
	beq.b	.GoodChar
	cmp.b	#"0",(a0)
	bcc.b	.CheckOther
	bra.b	.Decode

.CheckOther:
	cmp.b	#"9",(a0)
	bls.b	.GoodChar
	bra.b	.Decode

.GoodChar:
	move.b	(a0)+,(a1)+
	bra.b	.NextChar

.Decode:
	clr.b	(a1)
	lea	StrBuf,a0
	cmp.b	#"O",(a0)
	beq.b	.Boolean
	bsr	StrToNum
	rts

.Boolean:
	cmp.b	#"N",1(a0)
	beq.b	.True
	moveq	#0,d0			; False.
	rts

.True:
	moveq	#-1,d0
	rts

.String:
	move.w	#256,d0
	addq.l	#1,a0			; Skip the initial quote.

.Copy:
	cmp.b	#'"',(a0)
	beq.b	.Finished
	tst.b	(a0)
	beq.b	.BadString
	move.b	(a0)+,(a1)+
	subq.w	#1,d0
	beq.b	.BadString
	bra.b	.Copy

.Finished:
	clr.b	(a1)
	moveq	#-2,d0
	rts

.BadString:
	moveq	#0,d0
	rts

PrintReading:
	tst.b	Mode_Quiet
	beq	.DoPrint
	rts

.DoPrint:
	SaveR
	lea	PrintBuf,a0
	clr.b	(a0)
	lea	Text_Reading,a1
	bsr	StrCat
	lea	PrintBuf,a0
	lea	Text_ClearEOL,a1
	bsr	StrCat
	lea	PrintBuf,a0
	lea	Text_CR,a1
	bsr	StrCat
	bsr	WritePrintBuf
	LoadR
	rts

PrintWriting:
	tst.b	Mode_Quiet
	beq	.DoPrint
	rts

.DoPrint:
	SaveR
	lea	PrintBuf,a0
	clr.b	(a0)
	lea	Text_Writing,a1
	bsr	StrCat
	lea	PrintBuf,a0
	lea	Text_ClearEOL,a1
	bsr	StrCat
	lea	PrintBuf,a0
	lea	Text_CR,a1
	bsr	StrCat
	bsr	WritePrintBuf
	LoadR
	rts

; Allocates the read and write buffers for the file depending on free
; memory.

AllocBuffers:
	move.l	CurrentLink,a0
	move.l	SourceLen,d0
	tst.b	Mode_NoBuffer		; We have a full read buffer, so
	beq.b	.OnlyDest		; allocate only the write buffer.
	move.l	d0,d1
	lsr.l	#3,d1
	add.l	d0,d0
	add.l	d1,d0			; D0 = 212% D0
	bra.b	.DoAlloc

.OnlyDest:
	move.l	d0,d1
	lsr.l	#3,d1
	add.l	d1,d0			; D0 = 112% D0

.DoAlloc:
	move.l	d0,-(sp)
	moveq	#0,d1
	Call	Exec,AllocMem
	tst.l	d0
	beq	.NewTry
	move.l	d0,BigBufPtr
	move.l	(sp)+,BigBufSize

	tst.b	Mode_NoBuffer		; We have a full read buffer, so
	beq.b	.SetOnlyDest		; allocate only the write buffer.
	move.l	BigBufSize,d0
	lsr.l	#1,d0
	move.l	BigBufPtr,SourcePointer
	move.l	d0,Size_SrcBuf
	move.l	BigBufPtr,DestPointer
	add.l	d0,DestPointer
	move.l	d0,Size_DstBuf
	rts

.SetOnlyDest:
	move.l	BigBufSize,Size_DstBuf
	move.l	BigBufPtr,DestPointer
	rts

.NewTry:
	move.l	(sp)+,d0
	lsr.l	#2,d0			; D0 = 75% D0
	move.l	d0,d1
	add.l	d0,d0
	add.l	d1,d0
	cmp.l	#102400,d0		; Lower limit of 100kB for buffer(s).
	bcs	.NoAllocPossib
	bra	.DoAlloc

.NoAllocPossib:
	move.l	#Text_NoMemConvert,d2
	bra	ShowErr

CrunchDestFile:
	st	Flag_CrunchTried
	bsr	ClearPrintBuf
	lea	Text_Crunching1,a0
	bsr	AddPrintBuf
	lea	DestName,a0
	bsr	AddPrintBuf
	lea	Text_Crunching2,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf

	tst.b	Flag_LhAPack
	bne	DoLhAPack

	move.l	#CrunchSrcName,d1	; Open the DestName file.
	move.l	#ACCESS_READ,d2
	Call	Dos,Lock
	move.l	d0,DestLock
	beq.w	Err_NoCrunchFile	; If no lock, cannot crunch.
	move.l	DestLock,d1		; Otherwise check it
	move.l	#FIB,d2
	Call	Dos,Examine
	move.l	d0,-(sp)		; Save result code
	move.l	DestLock,d1
	Call	Dos,UnLock
	clr.l	DestLock
	move.l	(sp)+,d0		; Boolean
	beq.w	Err_NoCrunchFile	; If no Examine(), cannot crunch.
	lea	FIB,a0
	move.l	fib_Size(a0),CrSize

	move.l	CrSize,d0
	moveq	#0,d1
	Call	Exec,AllocMem
	move.l	d0,CrBuf
	beq	Err_NoCrunchMem

	move.l	#CrunchSrcName,d1
	move.l	#MODE_OLDFILE,d2
	Call	Dos,Open
	move.l	d0,CrFile

	bsr	PrintReading
	move.l	CrFile,d1
	move.l	CrBuf,d2
	move.l	CrSize,d3
	Call	Dos,Read
	cmp.l	#-1,d0
	beq	Err_CrunchReadWrite

	move.l	CrFile,d1
	Call	Dos,Close
	clr.l	CrFile

	move.l	#CRUN_BEST,d0
	move.l	#SPEEDUP_BUFFLARGE,d1

	lea	CrunchProgress,a0
	tst.b	Mode_Quiet
	beq	.NoQuiet
	sub.l	a0,a0

.NoQuiet:
	sub.l	a1,a1
	Call	PP,ppAllocCrunchInfo
	move.l	d0,CrCrunchInfo
	beq	Err_NoCrunchMem

	move.l	CrCrunchInfo,a0
	move.l	CrBuf,a1
	move.l	CrSize,d0
	Call	PP,ppCrunchBuffer
	move.l	d0,CrDestSize
	cmp.l	#PP_CRUNCHABORTED,d0
	beq	BreakPressed
	cmp.l	#PP_BUFFEROVERFLOW,d0
	beq	Err_CrunchOverflow

	move.l	#DestName,d1
	move.l	#MODE_NEWFILE,d2
	Call	Dos,Open
	move.l	d0,CrFile
	beq	Err_CrunchReadWrite

	move.l	CrFile,d0
	move.l	#CRUN_BEST,d1
	move.l	#FALSE,d2
	moveq	#0,d3
	Call	PP,ppWriteDataHeader
	tst.l	d0
	beq	Err_CrunchReadWrite

	bsr	PrintWriting
	move.l	CrFile,d1
	move.l	CrBuf,d2
	move.l	CrDestSize,d3
	Call	Dos,Write
	cmp.l	#-1,d0
	beq	Err_CrunchReadWrite

	move.l	CrFile,d1
	Call	Dos,Close
	clr.l	CrFile

	move.l	CrBuf,a1
	move.l	CrSize,d0
	Call	Exec,FreeMem
	clr.l	CrBuf

	move.l	CrCrunchInfo,a0
	Call	PP,ppFreeCrunchInfo
	clr.l	CrCrunchInfo

	move.l	CrSize,-(sp)
	move.l	CrDestSize,-(sp)
	move.l	CrSize,-(sp)
	st	Flag_StatsDue
	bsr	CrunchProgress
	add.l	#12,sp

	move.l	#Text_LF,d2
	bsr	PrintText
	move.l	#Text_LF,d2
	bsr	PrintText
	rts

DoLhAPack:
	lea	StrBuf,a0
	lea	Text_LhALine,a1
	bsr	StrCpy
	lea	StrBuf,a0
	bsr	StrEnd
	lea	DestName,a1
	bsr	MakeLhAName
	lea	StrBuf,a0
	lea	Text_Space,a1
	bsr	StrCat
	lea	StrBuf,a0
	lea	CrunchSrcName,a1
	bsr	StrCat
	move.l	#StrBuf,d2
	bsr	PrintText
	move.l	#Text_LF,d2
	bsr	PrintText

	move.l	#StrBuf,d1
	moveq	#0,d2
	moveq	#0,d3
	Call	Dos,Execute
	tst.l	d0
	beq	EndProgramErr
	move.l	#Text_LF,d2
	bsr	PrintText
;	move.l	#Text_LF,d2
;	bsr	PrintText
	rts

; A0  Ptr for the converted name.
; A1  Ptr to the original name.

MakeLhAName:
	movem.l	a0-a1,-(sp)
	move.l	a1,a0
	bsr	StrLen
	movem.l	(sp)+,a0-a1
	cmp.l	#4,d0
	bcs.b	.TooShort
	move.l	a0,-(sp)		; Copy the original name to destination.
	bsr	StrCpy
	move.l	(sp)+,a0
	bsr	StrEnd
	subq.l	#4,a0
	lea	Text_LhASuffix,a1	; ".LhA"
	cmp.b	#".",(a0)
	beq.b	.KillOldSuffix
	addq.l	#4,a0
	bsr	StrCpy
	rts

.KillOldSuffix:
	bsr	StrCpy			; Copy the suffix on the old suffix.
	rts

.TooShort:
	move.l	a0,-(sp)		; Copy the original name to destination.
	bsr	StrCpy
	move.l	(sp)+,a0
	bsr	StrEnd
	lea	Text_LhASuffix,a1	; ".LhA"
	bsr	StrCpy
	rts

CrunchProgress:
	tst.b	Flag_StatsDue
	bne.b	.DoStats
	moveq	#-1,d0
	rts

.DoStats:
	clr.b	Flag_StatsDue
;	move.l	4(sp),d0		; Length of processed data.
;	move.l	8(sp),d1		; Length of crunched data.
;	move.l	12(sp),d2		; Length of raw data.

	moveq	#0,d0			; Get the signals.
	moveq	#0,d1
	Call	Exec,SetSignal
	btst	#SIGBREAKB_CTRL_C,d0	; Check if ^C was pressed.
	bne.b	.Abort

	lea	PrintBuf,a0
	clr.b	(a0)
	lea	Text_Done,a1
	bsr	StrCat

	lea	PrintBuf,a0
	move.l	4(sp),d0
	move.l	12(sp),d1
	bsr	Percentage
	bsr	StrNumCat

	lea	PrintBuf,a0
	lea	Text_PercentSign,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_Gain,a1
	bsr	StrCat

	move.l	8(sp),d0
	move.l	4(sp),d1
	bsr	Percentage
	moveq	#100,d1
	sub.l	d0,d1
	move.l	d1,d0
	lea	PrintBuf,a0
	bsr	StrNumCat

	lea	PrintBuf,a0
	lea	Text_PercentSign,a1
	bsr	StrCat

	lea	PrintBuf,a0
	lea	Text_CR,a1
	bsr	StrCat

	bsr	WritePrintBuf
	
	moveq	#-1,d0
	rts

.Abort:
	moveq	#0,d0
	rts

; A0 - Ptr to pattern.

FormFileLinks:
	move.l	a0,d1
	move.l	#MyAnchor,d2
	pea	FileLinkBase
	Call	Dos,MatchFirst
	st	Flag_AnchorUsed
	tst.l	d0
	bne	.NoMatch

.GetNextFile:
	move.l	#fl_SIZEOF,d0		; Allocate a new FileLink.
	move.l	#MEMF_CLEAR,d1
	Call	Exec,AllocMem
	move.l	(sp)+,a0		; Link it to the old FileLink.
	move.l	a0,a5
	move.l	d0,(a0)
	move.l	d0,a1			; Prepare copying data from the anchor

.UseOldLink:
	lea	MyAnchor+ap_Info,a0	; to the FileLink.
	tst.l	(fib_DirEntryType,a0)
	bgt	.SkipDir		; Skip directories.
	st	Flag_FileFound		; Now we have at least one file.
	move.l	(fib_Size,a0),(fl_Size,a1)
	move.l	a1,-(sp)		; Store for .GetNextFile linkage.
	lea	(fib_FileName,a0),a0
	lea	(fl_FileName,a1),a1
	exg	a0,a1
	bsr	StrCpy
	move.l	(sp),a1
	add.l	#fl_FullName,a1
	lea	MyAnchor+ap_Buf,a0
	exg	a0,a1
	bsr	StrCpy

	move.l	#MyAnchor,d1
	Call	Dos,MatchNext
	tst.l	d0
	bne	.NoMatch
	bra	.GetNextFile

.SkipDir:
	move.l	a1,-(sp)
	move.l	#MyAnchor,d1
	Call	Dos,MatchNext
	move.l	(sp)+,a1
	tst.l	d0
	beq	.UseOldLink
	move.l	#fl_SIZEOF,d0
	Call	Exec,FreeMem
	clr.l	(a5)
	bra	.NoMatchNoStack

.NoMatch:
	addq.l	#4,sp

.NoMatchNoStack:
	lea	MyAnchor,a0
	tst.l	ap_FoundBreak(a0)
	bne	BreakPressed
	Call	Dos,IoErr
	cmp.l	#ERROR_NO_MORE_ENTRIES,d0
	bne	.RealError
	rts

.RealError:
	st	Flag_Stop
	cmp.l	#ERROR_OBJECT_NOT_FOUND,d0
	beq	Err_NoSource
	cmp.l	#ERROR_DEVICE_NOT_MOUNTED,d0
	beq	Err_NoSource
	move.l	d0,d1
	move.l	#Text_Error,d2
	move.l	#PrintBuf,d3
	move.l	#256,d4
	Call	Dos,Fault
	lea	PrintBuf,a0
	bsr	StrLFCat
	bsr	WritePrintBuf
	bra	EndProgramErr

InsertEOLs:
	move.l	EOLs,d3
	bne	.EOLsWaiting
	rts

.EOLsWaiting:
	clr.l	EOLs
	add.l	d3,d2			; Add the number of LFs.
	tst.b	Mode			; If ToPC or ToSF7, add a CR too.
	bpl	.DoInsertEOLs
	add.l	d3,d2			; Add the number of CRs.

.DoInsertEOLs:
	subq.l	#1,d3

.DoInsert:
	bsr	InsertSingleEOL
	dbf	d3,.DoInsert
	rts

; Inserts an EOL according to Mode, and adds D2.

InsertOneEOL:
	move.b	#LF,(a1)+
	tst.b	Mode			; If ToPC or ToSF7, add a CR too.
	bmi	.ForeignEOL
	addq.l	#1,d2
	rts

.ForeignEOL:
	move.b	#CR,(a1)+
	addq.l	#2,d2
	rts

; Inserts an EOL according to Mode, but does not add D2.

InsertSingleEOL:
	move.b	#LF,(a1)+
	tst.b	Mode			; If ToPC or ToSF7, add a CR too.
	bmi	.ForeignEOL
	rts

.ForeignEOL:
	move.b	#CR,(a1)+
	rts

FlushArea:
	tst.b	TabSize
	bne	.SpaceTabConv
	lea	SpaceBuf,a2
	move.l	SpaceNumber,d3
	beq	.NothingToCopy
	add.l	d3,d2
	subq.l	#1,d3

.CopyArea:
	move.b	(a2)+,(a1)+
	dbf	d3,.CopyArea

.NothingToCopy:
	bsr	ResetArea
	rts

.SpaceTabConv:
	tst.b	PreSpace
	beq	.NoPreSpace
	move.b	#" ",(a1)+
	addq.l	#1,d2

.NoPreSpace:
	move.l	Tabs,d3
	beq	.NoTabs
	add.l	d3,d2
	subq.l	#1,d3

.InsertTabs:
	move.b	#TAB,(a1)+
	dbf	d3,.InsertTabs

.NoTabs:
	move.l	SpaceNumber,d3
	beq	.NoSpaces
	add.l	d3,d2
	subq.l	#1,d3

.InsertSpaces
	move.b	#" ",(a1)+
	dbf	d3,.InsertSpaces

.NoSpaces:
	bsr	ResetArea
	rts

ResetArea:
	tst.b	TabSize
	beq	.NoSpaceTabConv
	clr.l	SpaceNumber
	clr.l	Tabs
	clr.b	PreSpace
	rts

.NoSpaceTabConv:
	lea	SpaceBuf,a2
	clr.l	SpaceNumber
	rts

BufChar:
	move.b	d0,(a2)+		; No Space-Tab conversion active,
	addq.l	#1,SpaceNumber		; buffer all area found.
	addq.w	#1,Col
	rts

SpaceConv:
	cmp.l	#1,SpaceNumber		; If Spacenumber<1, don't try to convert
	bcc	.ContConv		; to tabs.  No use, and time wasted in
	rts

.ContConv:
	move.w	Col,d5
	ext.l	d5
	move.l	SpaceNumber,d3
	move.b	SpaceSize,d4
	IFD	Code020			; Convert TabSize
	extb.l	d4
	ENDC
	IFND	Code020
	ext.w	d4
	ext.l	d4
	ENDC
	divu.w	d4,d5			; If column is divisible by SpaceSize,
	swap	d5			; it can be converted to a tab.
	tst.w	d5
	beq.b	.CanConv
	rts

.CanConv:
	cmp.l	#1,SpaceNumber		; If only one space is won, instead
	beq.b	.GotPreSpace		; of conversion, make it PreSpace.
	addq.l	#1,Tabs			; More tabs.
	clr.l	SpaceNumber		; Take the spaces out.
	rts

.GotPreSpace:
	st	PreSpace
	clr.l	SpaceNumber		; Reset SpaceNumber.
	rts

TabConv:
	move.b	TabSize,d4		; TabSize = 0 means no Tabs2Spaces conv
	IFD	Code020			; Convert TabSize
	extb.l	d4
	ENDC
	IFND	Code020
	ext.w	d4
	ext.l	d4
	ENDC
	move.w	Col,d3			; Get current column
	ext.l	d3
	divu.w	d4,d3			; Divide column with TabSize -> we get
	swap	d3			; the offset from last tab as chars.
	sub.w	d3,d4			; Get the # of spaces to the next tab
	add.l	d4,SpaceNumber		; Add the converted spaces to SpaceBuf.
	add.w	d4,Col			; And add column too.
	rts

OpenDest:
	tst.b	Flag_CrunchBuf
	bne.b	.CheckTempFile
	tst.b	Flag_LhAPack
	bne.b	.CheckTempFile
	move.l	#DestName,d1		; Open the DestName file.

.DoOpen:
	move.l	#MODE_NEWFILE,d2
	Call	Dos,Open
	move.l	d0,DestHandle
	beq.w	Err_NoDest
	st	Mode_DeleteErrDest	; Delete the dest file in case of error.
	moveq	#0,d2
	move.l	DestPointer,a1
	move.l	Table,a3		; Get the table.
	lea	SpaceBuf,a2
	lea	InterNetBuf,a4
	rts

.CheckTempFile:
	lea	CrunchSrcName,a0	; The default is to write on the dest.
	lea	DestName,a1
	bsr	StrCpy
	lea	TempDir,a0
	move.l	#CrunchSrcName,d1
	tst.b	(a0)
	beq.b	.DoOpen			; No TempDir, write on destination.
	lea	StrBuf,a0
	lea	TempDir,a1
	bsr	StrCpy
	move.l	#StrBuf,d1
	move.l	CurrentLink,d2
	add.l	#fl_FileName,d2
	move.l	#256,d3
	Call	Dos,AddPart
	moveq	#4,d7
	tst.l	d0
	beq	CodeError
	lea	CrunchSrcName,a0
	lea	StrBuf,a1
	bsr	StrCpy
	move.l	#CrunchSrcName,d1
	bra.b	.DoOpen

MakeSourceASCII:
	lea	SourceLenASCII,a0	; Make a string out of the file length.
	move.l	SourceLen,d0
	bsr	NumToStr
	move.l	a0,SourceLenASCIIAddr
	move.l	d0,SourceLenASCIILen
	rts
	
CalcReadRate:
	move.w	TickCount,d1
	ext.l	d1
	add.l	d1,ReadTime
	move.l	ReadTime,d1
	move.l	ReadBytes,d0
	move.b	TickDelay,d2
	IFD	Code020
	and.l	#$ff,d2
	divu.l	d1,d0			; Bytes/tick.
	mulu.l	d2,d0			; Bytes/sec.
	ENDC
	IFND	Code020
	and.w	#$ff,d0
	divu.w	d1,d0
	bvs	.Overflow
	ext.l	d0
	mulu.w	d2,d0
	ENDC
	cmp.l	#10240,d0
	bcs	.TooLow
	move.l	d0,RBlockSize
	rts

.TooLow:
	move.l	#10240,RBlockSize
	rts

.Overflow:
	move.l	#65535,d0
	mulu.w	d2,d0
	move.l	d0,RBlockSize
	rts

PrintStats:
	movem.l	d1-d3/a0-a1,-(sp)
	moveq	#0,d0			; Get the signals.
	moveq	#0,d1
	Call	Exec,SetSignal
	movem.l	(sp)+,d1-d3/a0-a1
	btst	#SIGBREAKB_CTRL_C,d0	; Check if ^C was pressed.
	bne	BreakPressed
	clr.b	Flag_StatsDue
	tst.b	Mode_Quiet		; See if we should be quiet.
	beq.b	.DoPrint
	rts

.DoPrint:
	movem.l	d1-d7/a0-a6,-(sp)
	move.l	d3,-(sp)
	bsr	ClearPrintBuf
	move.l	#Text_Converted,a0	; The progress info for fully buffered
	bsr	AddPrintBuf		; input.
	lea	NumberBuf,a0
	move.l	(sp)+,d0		; The bytes in the current buffer and
;	add.l	WrittenBytes,d0		; the bytes already written.
	bsr	NumToStr
	bsr	AddPrintBuf
	move.l	#Text_Slash,a0
	bsr	AddPrintBuf
	move.l	SourceLenASCIIAddr,a0
	bsr	AddPrintBuf
	move.l	#Text_ClearEOL,a0
	bsr	AddPrintBuf
	move.l	#Text_CR,a0
	bsr	AddPrintBuf
	bsr	WritePrintBuf
	movem.l	(sp)+,d1-d7/a0-a6
	rts

ClearVars:
	lea	SpaceBuf,a2
	clr.l	EOLs
	clr.l	WrittenBytes
	clr.l	ReadBytes
	clr.l	LeftBytes
	clr.l	InputBytes
	clr.l	SpaceNumber
	clr.b	PreSpace
	clr.b	Flag_PPUsed
	rts

ClearPrintBuf:
	move.l	#PrintBuf,PrintBufPtr
	rts

AddPrintBuf:
	move.l	PrintBufPtr,a1

apb_Copy:
	move.b	(a0)+,(a1)+
	bne.b	apb_Copy
	subq.l	#1,a1			; A1 is 1 past the null. We want to
	move.l	a1,PrintBufPtr		; overwrite the null.
	rts

WritePrintBuf:
	move.l	#PrintBuf,d2
	bsr	PrintText
	rts

PrintText:
	move.l	d2,a0
	move.l	_DosBase,a6
	IFD	Code020
	tst.l	a6
	ENDC
	IFND	Code020
	cmp.l	#0,a6
	ENDC
	beq	OpenErrDos
	tst.l	OutStruct
	beq	OpenErrDos

PrintText1:
	tst.b	(a0)+
	bne.b	PrintText1

	sub.l	d2,a0
	subq.w	#1,a0
	move.l	a0,d3
	move.l	OutStruct,d1
	jsr	_LVOWrite(a6)
	tst.l	_DosBase
	beq	CloseErrDos
	rts

OpenErrDos:
	movem.l	d0-d7/a0-a5,-(sp)
	lea	_DosName,a1
	moveq	#0,d0
	Call	Exec,OpenLibrary
	move.l	d0,ErrDosBase
	move.l	d0,a6
	IFD	Code020
	tst.l	a6
	ENDC
	IFD	Code020
	cmp.l	#0,a6
	ENDC
	bne	OpenErrDos2
	movem.l	(sp)+,d0-d7/a0-a5
	rts

OpenErrDos2:
	move.l	d0,a6
	jsr	_LVOOutput(a6)
	move.l	d0,OutStruct
	bne	OpenErrDos1
	movem.l	(sp)+,d0-d7/a0-a5
	rts

OpenErrDos1:
	movem.l	(sp)+,d0-d7/a0-a5
	bra	PrintText1

CloseErrDos:
	move.l	ErrDosBase,a1
	Call	Exec,CloseLibrary
	rts

PrintTextLen:
	move.l	OutStruct,d1
	Call	Dos,Write
	rts

; Skips spaces in a string pointed to by A0, returns A0 as zero if it ran out
; of string.

SkipSpace:
	cmp.b	#" ",(a0)
	beq.b	SkipSpace1
	rts

SkipSpace1:
	addq.l	#1,a0
	tst.b	(a0)
	bne.b	SkipSpace
	sub.l	a0,a0
	rts

FindEnd:
	cmp.b	#'"',(a0)		; If the first letter is a quote,
	beq.b	FindEnd_Quote		; go to FindEnd_Quote

FindEnd_Space:
	addq.l	#1,a0			; Get the next position, if it is a
	cmp.b	#" ",(a0)		; Space, we found the end
	beq.b	FindEnd_Space1
	tst.b	(a0)			; If it's the end of comline, we found
	beq.b	FindEnd_Space1		; the end of the name.
	bra.b	FindEnd_Space

FindEnd_Space1:
	subq.l	#1,a0
	rts

FindEnd_Quote:
	addq.l	#1,a0
	tst.b	(a0)			; If end of comline, error.
	beq.b	FindEnd_Quote2
	cmp.b	#'"',(a0)
	bne.b	FindEnd_Quote
	rts

FindEnd_Quote2:
	sub.l	a0,a0
	rts

CopyUntilNull:
	move.b	(a0)+,(a1)+
	bne.b	CopyUntilNull
	rts

	INCDIR	"SRC:Routines/"

	IFD	Code020
	INCLUDE	"NumToStr-020.S"
	ENDC

	IFND	Code020
	INCLUDE	"NumToStr.S"
	ENDC

	INCLUDE	"Percentage.S"
	INCLUDE	"CopyName.S"

**********
** DATA **
**********

	SECTION	FastData,DATA

MyAnchor:
	dc.l	0			; ap_Base
	dc.l	0			; ap_Last
	dc.l	SIGBREAKF_CTRL_C	; ap_BreakBits
	dc.l	0			; ap_FoundBreak
	dc.b	0			; ap_Flags
	dc.b	0
	dc.w	256			; ap_Strlen
	ds.b	fib_SIZEOF
	ds.b	256

VertBInterrupt:
	dc.l	0			; Successor.
	dc.l	0			; Predecessor.
	dc.b	NT_INTERRUPT		; Type.
	dc.b	0			; Pri.
	dc.l	Text_VertBIntName	; Ptr to name.
	dc.l	TimeCounter		; Ptr to TimeCounter, IS_DATA.
	dc.l	VertBIntCode		; Ptr to VBLANK code.

RBlockSize:				; Bytes of data for a single Read().
	dc.l	10240

ReadTime:				; Time taken in all Read()'s.
	dc.l	1

***********************
** Conversion tables **
***********************

Table_ToPC:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;00
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/" ;20
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?" ;30
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O" ;40
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_" ;50
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o" ;60
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","{","|","}","~",$B1
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$9b,$00,$00,$00,$00 ;90
	dc.b	" ",$AD,$9B,$9C,"$",$9D,"|",$15,'"',"C",$A6,$AE,$AA,"-","R","-"
	dc.b	$F8,$F1,$FD,"3","'",$E6,$14,$F9,",","1",$A7,$AF,$AC,$AB,"3",$A8
	dc.b	$85,$A0,$8F,"A",$8E,$8F,$92,$80,$8A,$90,$88,$89,$8D,$A1,$8C,$8B
	dc.b	"D","N",$95,$A2,$93,"O",$99,"x","0",$97,$A3,$96,$9A,"Y","B",$E1
	dc.b	$85,$A0,"a","a",$84,$83,$91,$87,$8A,$82,$88,$89,$8D,$A1,$8C,$8B
	dc.b	$EB,"n",$95,$A2,$93,"o",$94,$F6,"0",$97,$A3,$96,$81,"y","B",$98

Table_Null:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;10
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/"
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?"
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_"
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","{","|","}","~",$7F
	dc.b	$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
	dc.b	$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F
	dc.b	$A0,"¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯"
	dc.b	"°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿"
	dc.b	"À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï"
	dc.b	"Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß"
	dc.b	"à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï"
	dc.b	"ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ý","þ","ÿ"

Table_Lowercase:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;10
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/"
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?"
	dc.b	"@","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","[","\\","]","^","_"
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","{","|","}","~",$7F
	dc.b	$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
	dc.b	$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F
	dc.b	$A0,"¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯"
	dc.b	"°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿"
	DC.B	"à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï"
	dc.b	"ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ý","þ","ß"
	dc.b	"à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï"
	dc.b	"ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ý","þ","ÿ"

Table_Uppercase:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;10
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/"
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?"
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_"
	dc.b	"`","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","{","|","}","~",$7F
	dc.b	$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
	dc.b	$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F
	dc.b	$A0,"¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯"
	dc.b	"°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿"
	dc.b	"À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï"
	dc.b	"Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß"
	dc.b	"À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï"
	dc.b	"Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ÿ"

Table_ToSF7:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;10
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/"
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?"
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_"
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","{","|","}","~",$7F
	dc.b	$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
	dc.b	$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F
	dc.b	$A0,"¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯"
	dc.b	"°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿"
	dc.b	"À","Á","Â","Ã","[","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï"
	dc.b	"Ð","Ñ","Ò","Ó","Ô","Õ","\\","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß"
	dc.b	"à","á","â","ã","{","å","æ","ç","è","é","ê","ë","ì","í","î","ï"
	dc.b	"ð","ñ","ò","ó","ô","õ","|","÷","ø","ù","ú","û","ü","ý","þ","ÿ"

Table_FromSF7:
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0A,$00,$00,$00,$00,$00 ;10
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/"
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?"
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","Ä","Ö","Å","^","_"
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","ä","ö","å","~",$7F
	dc.b	$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
	dc.b	$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F
	dc.b	$A0,"¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯"
	dc.b	"°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿"
	dc.b	"À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï"
	dc.b	"Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß"
	dc.b	"à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï"
	dc.b	"ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ý","þ","ÿ"

Table_FromPC:	;0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0a,$00,$00,$00,$00,$00 ;00
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/" ;20
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?" ;30
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O" ;40
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_" ;50
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o" ;60
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","" ;70
	dc.b	"Ç","ü","é","å","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å" ;80
	dc.b	"È","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü",$a2,"£",$a5,"P","f" ;90
	dc.b	"á","í","ó","ú","ñ","Ñ","ª","º","¿",".",".","½","¼","¡","«","»" ;A0
	dc.b	$7f,$7f,$7f,"|","+","#","+",".","#","#","|","#","#","'","#","." ;B0
	dc.b	"`","+","+","+","-","+","#","+","#","#","#","#","#","=","#","#" ;C0
	dc.b	"+","#","+","`","#","#",".","+","#","'",".",$7f,"æ","[","]","^" ;D0
	dc.b	"c","ß","r","+","E","ó",$b5,"i","o","0","O","ð","ø","ø","E","A" ;E0
	dc.b	"=","±",">","<","í","j","÷","~","°","·","·","V","n","²","·"," " ;F0

Table_Combined:	;0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$0a,$00,$00,$00,$00,$00 ;00
	dc.b	$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1b,$00,$00,$00,$00 ;10
	dc.b	" ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/" ;20
	dc.b	"0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?" ;30
	dc.b	"@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O" ;40
	dc.b	"P","Q","R","S","T","U","V","W","X","Y","Z","Ä","Ö","Å","^","_" ;50
	dc.b	"`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o" ;60
	dc.b	"p","q","r","s","t","u","v","w","x","y","z","ä","ö","å","~","" ;70
	dc.b	"Ç","ü","é","å","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å" ;80
	dc.b	"È","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü",$a2,"£",$a5,"P","f" ;90
	dc.b	"á","í","ó","ú","ñ","Ñ","ª","º","¿",".",".","½","¼","¡","«","»" ;A0
	dc.b	$7f,$7f,$7f,"|","+","#","+",".","#","#","|","#","#","'","#","." ;B0
	dc.b	"`","+","+","+","-","+","#","+","#","#","#","#","#","=","#","#" ;C0
	dc.b	"+","#","+","`","#","#",".","+","#","'",".",$7f,"æ","[","]","^" ;D0
	dc.b	"c","ß","r","+","E","ó",$b5,"i","o","0","O","ð","ø","ø","E","A" ;E0
	dc.b	"=","±",">","<","í","j","÷","~","°","·","·","V","n","²","·"," " ;F0

	INCDIR	"SRC:Port/"

Flag_DestName:				; We have a real destination.
	dc.b	$ff

CapRange:
	dc.b	"A"
	dc.b	"Z"

LowRange:
	dc.b	"a"
	dc.b	"z"

_DosName:
	dc.b	"dos.library",0

PPName:
	PPNAME

PrefName:
	dc.b	"ENV:Port.Prefs\0"

***********
** TEXTS **
***********

Text_VertBIntName:
	dc.b	"Port VBlank Timer",0

Text_CodeError:
	INCBIN	"PortCodeError"
	dc.b	0

Text_HelpText:
	INCBIN	"PortOpts1"
	dc.b	0

Text_Credits:
	INCBIN	"PortOpts2"
	dc.b	0

Text_Header:
	INCBIN	"Port.Header"
	dc.b	0

Text_CursorOff:
	dc.b	"\c0 p",0

Text_CursorOn:
	dc.b	"\c1 p",0

Text_Error:
	dc.b	"Error!  ",0

Text_Warning:
	dc.b	"Warning:  ",0

; These need the LF even though they are error messages, because there must
; be one LF between the messages of each different file.

Text_CrunchReadWrite:
	dc.b	"Could not read/write the file for PowerPacking\n\0"

Text_NoCrunchMem:
	dc.b	"Not enough memory for PowerPacking.\n\0"

Text_CrunchOverflow:
	dc.b	"Buffer overflow.  File was not PowerPacked.\n\0"

Text_NoCrunchFile:
	dc.b	"Could not lock the file for PowerPacking.\n\0"

Text_NeedBufPP:
	dc.b	"Cannot use NoBuffer mode with PowerPacked files.\0"

Text_Decrunching:
	dc.b	"Loading & decrunching a PowerPacked file...\n\0"

Text_UnknownPP:
	dc.b	"The file is packed with an unknown version of PowerPacker.\0"

Text_WrongPass:
	dc.b	"Incorrect password, can't decrypt.\0"

Text_FileDest:
	dc.b	"Can't have a file destination for wildcards.\0"

	IFD	Code020

Text_OldProcessor:
	dc.b	"At least 68020 is needed.\0"

	ENDC

Text_NewKickNeed:
	dc.b	"At least system V37 is needed.\0"

Text_PrefsError:
	dc.b	"Error reading preferences, defaults used.\n\n\0"

Text_BadComLine:
	dc.b	"Bad commandline.",0

Text_Reading:
	dc.b	"Reading...\0"

Text_Writing:
	dc.b	"Writing...\0"

Text_ANSIStrip:
	dc.b	"ANSIStrip\0"

Text_MakeEOLs:
	dc.b	"MakeEOLs\0"

Text_INStrip:
	dc.b	"InterNetStrip\0"

Text_EndSpaceRemoval:
	dc.b	"EndSpaceRemoval\0"

Text_PowerPackOutput:
	dc.b	"PowerPackOutput\0"

Text_SpacesToTabs:
	dc.b	"SpacesToTabs\0"

Text_TabsToSpaces:
	dc.b	"TabsToSpaces\0"

Text_Quiet:
	dc.b	"Quiet\0"

Text_TickDelay:
	dc.b	"TickDelay\0"

Text_TempDir:
	dc.b	"TempDir\0"

Text_LhAPack:
	dc.b	"LhAPack\0"

Text_INFrom:
	dc.b	"From \0"

Text_INPath:
	dc.b	"Path: \0"

Text_UnknownOpt:
	dc.b	"Unknown preferences option \"\0"

Text_BadOptArg:
	dc.b	"Bad argument for preferences option \"\0"

Text_ConvBuf:
	dc.b	"ConversionBuffer\0"

Text_NoSource:
	dc.b	"Could not open source file.",0

Text_NoDest:
	dc.b	"Could not open destination file.",0

Text_SourceIsDir:
	dc.b	"Source cannot be a directory.",0

Text_WriteFail:
	dc.b	"Can't write data.",0

Text_NoComLineSpace:
	dc.b	"The mode must be separated with at least one space.",0

Text_BadLogic:
	dc.b	"Conflicting options.",0

Text_OptConflict:
	dc.b	"Conflicting options in preferences.",0

Text_NoMemConvert:
	dc.b	"Not enough memory to convert the file.",0

Text_NoMemory:
	dc.b	"Not enough memory to load the file.",0

Text_PowerPacked:
	dc.b	"File is a PowerPacked, \"powerpacker.library\" is needed to read.\0"

Text_PowerPackNeed:
	dc.b	"\"powerpacker.library\" V35+ is required.\0"

Text_BadSource:
	dc.b	"Source file corrupted.",0

Text_BadDest:
	dc.b	"Destination corrupted.",0

Text_NeedBuffer:
	dc.b	"Auto-mode only works with buffered input.",0

Text_Crunching1:
	dc.b	"Packing \"\0"

Text_SameProbability:
	dc.b	"Can't decide between modes.",0

Text_INRemoved:
	dc.b	"\nHEADER-REMOVED--HEADER-REMOVED--HEADER-REMOVED--HEADER-REMOVED--HEADER REMOVED\n\n",0

Text_Deleted:
	dc.b	'" deleted.\n\0'

Text_ConvFile1:
	dc.b	"Converting file \"\0"

Text_Crunching2:
Text_ConvFile2:
	dc.b	"\"...\n\0"

Text_Done:
	dc.b	"Done: \0"

Text_Gain:
	dc.b	"  Gain: \0"

Text_Input:
	dc.b	"Input: ",0

Text_Output:
	dc.b	"  Output: ",0

Text_Read:
	dc.b	"Read: ",0

Text_Converted:
	dc.b	"Converted: ",0

Text_Checking:
	dc.b	"Checking file type...\c0K\r\0"

Text_LhALine:
	dc.b	"LhA m ",0

Text_LhASuffix:
	dc.b	".LhA",0

Text_Uses:
	dc.b	"Type: ",0

Text_NullMode:
	dc.b	"Amiga\c0K\n\n"

Text_SF7Mode:
	dc.b	"SF7\c0K\n\0"

Text_PCMode:
	dc.b	"PC\c0K\n\0"

Text_Break:
	dc.b	"-BREAK-\c0K\n\0"

Text_ClearEOL:
	dc.b	"\c0K\0"

Text_AmigaSuf:
	dc.b	".AMY\0"

Text_PCSuf:
	dc.b	".PC\0"

Text_SF7Suf:
	dc.b	".SF7\0"

Text_CR:
	dc.b	CR,0

Text_LF:
	dc.b	LF,0

Text_Final:
	dc.b	"File size change: \0"

Text_NegSign:
	dc.b	"-",0

Text_PosSign:
	dc.b	"+",0

Text_PercentSign:
	dc.b	"%\c0K\0"

Text_DoubleSpace:
	dc.b	"  ",0

Text_Slash:
	dc.b	"/",0

Text_Space:
	dc.b	" ",0

Text_Period:
	dc.b	".",0

Text_Quote:
	dc.b	'"',0


	SECTION	FastBlank,BSS

DT:					; Section base address.

FIB:
	ds.b	fib_SIZEOF

PrefDecode:				; Ptr to the current place in data.
	ds.l	1

PrefPtr:				; Ptr to loaded preferences data.
	ds.l	1

Size_Prefs:				; Size of the loaded preferences data.
	ds.l	1

PrefHandle:				; Preferences file handle.
	ds.l	1

BigBufPtr:				; Ptr for conversion buffer(s).
	ds.l	1

BigBufSize:				; Size of the conversion buffer(s).
	ds.l	1

TempBuf:				; Buffer for checking PP 4 byte ID.
	ds.l	1

CrDestSize:				; Size of the packed buffer.
	ds.l	1

CrCrunchInfo:				; Ptr to PP CrunchInfo structure.
	ds.l	1

CrBuf:					; Ptr to the buffer to crunch.
	ds.l	1

CrFile:					; File handle for file to crunch.
	ds.l	1

CrSize:					; Size of the file to be crunched.
	ds.l	1

FileLinkBase:				; Pointer to the first FileLink.
	ds.l	1

CurrentLink:				; Pointer to the current FileLink.
	ds.l	1

ErrDosBase:				; DosBase used in case of error.
	ds.l	1

PrintBufPtr:
	ds.l	1

OldStack:
	ds.l	1

DestNameLen:
	ds.l	1

SourceLock:
	ds.l	1

DestLock:
	ds.l	1

EOLs:
	ds.l	1

ReadASCIIAddr:
	ds.l	1

Table:					; Ptr to the current translation table.
	ds.l	1

SourceLen:				; Size of the source file in bytes.
	ds.l	1

Tabs:					; Counter of buffered tabs.
	ds.l	1

WrittenBytes:
	ds.l	1

ReadBytes:
	ds.l	1

LeftBytes:
	ds.l	1

InputBytes:
	ds.l	1

SourceHandle:
	ds.l	1

DestHandle:
	ds.l	1

OutStruct:
	ds.l	1

DestNameStart:
	ds.l	1

SourceNameStart:
	ds.l	1

SourceNameEnd:
	ds.l	1

SourceNameLen:
	ds.l	1

Commandstarrt:
	ds.l	1

_DosBase:
	ds.l	1

_PPBase:
	ds.l	1

SpaceNumber:
	ds.l	1

ReadASCIILen:
	ds.l	1

SourceLenASCIILen:
	ds.l	1

SourceLenASCIIAddr:
	ds.l	1

OldDirLock:
	ds.l	1

SourcePointer:				; Ptr to the read buffer.
	ds.l	1

DestPointer:				; Ptr to the write buffer.
	ds.l	1

Size_SrcBuf:				; Size of the read buffer.
	ds.l	1

Size_DstBuf:				; Size of the write buffer.
	ds.l	1

INBufSize:				; Number of bytes buffered by INStrip.
	ds.w	1

Col:
	ds.w	1

; VBLANK interrupt's IS_DATA.

TimeCounter:				; Frame counter.
	ds.b	1
TickDelay:				; Update tick delay.
	ds.b	1
Flag_StatsDue:				; Statistics due -flag.
	ds.b	1
	ds.b	1			; Padding.
TickCount:				; VB counter for read sync.
	ds.w	1

RealSourceName:
	ds.b	108			; Max filename size in FIB

CopySymbolBuf:				; Buffer for CopySymbol.
	ds.b	160

CrunchSrcName:				; Name of the file to crunch.
	ds.b	256

TempDir:				; Name of the temporary directory.
	ds.b	256

StrBuf:
	ds.b	256

SourceName:
	ds.b	256

DestName:
	ds.b	256

PrintBuf:
	ds.b	256

SpaceBuf:
	ds.b	1024

InterNetBuf:
	ds.b	1024

NumberBuf:
	ds.b	11

ReadASCII:
	ds.b	11

SourceLenASCII:
	ds.b	11

Flag_IntActive:				; VBLANK interrupt is active.
	ds.b	1

Flag_AnchorUsed:			; Indicates that we need to MatchEnd().
	ds.b	1

Flag_Stop:				; Indicates that exit should be taken.
	ds.b	1

Flag_FileFound:				; At least one file was found.
	ds.b	1

Flag_PPUsed:				; PowerPacker library was used to load
	ds.b	1			; the file.

Flag_CrunchBuf:				; PowerPack the output file.
	ds.b	1

Flag_LhAPack:				; LhA pack the output file.
	ds.b	1

Flag_AStrip:				; Strip ANSI codes.
	ds.b	1

Flag_CrunchTried:			; Already tried crunching this file.
	ds.b	1

Flag_INStrip:				; Strip InterNet headers.
	ds.b	1			; 1-"HEADER STRIPPED" 2-Nothing.

Flag_INStripActive:			; Current data is of the header.
	ds.b	1

Flag_ANSIState:				; Are we waiting for a CSI etc.
	ds.b	1

Mode:
	ds.b	1

TabSize:
	ds.b	1

SpaceSize:
	ds.b	1

Size_MakeEOLs:
	ds.b	1

PreSpace:
	ds.b	1

Mode_NoCutSpace:
	ds.b	1

Mode_Quiet:
	ds.b	1

Mode_NoBuffer:
	ds.b	1

Mode_DeleteErrDest:
	ds.b	1

Mode_SrcDeleted:
	ds.b	1
