****************************************************************************
*
* RAM-based Console-Device text- and binary file viewer.
* RAM-based virtual screen picture/image viewer.
*
** THIS IS THE SPEICIAL VERSION, 4.4-LE - REAL "LINE EDIT" IMPLEMENTED!!!!!
*
*
* Copyright 1992 - 1999 Jörg van de Loo
*			Hövel 15
*			47559 Kranenburg
*			Germany
*
* No e-mail address ( - released to the public!).
*
* -13.06.1992, 22:58:59- V1.0 - Text viewer (PowerPacker (© Nico François) support)
* -14.06.1992  23:55:43- V2.0 - Text and picture viewer (thanks to Holger Gzella for picture decoding)
* -24.09.1992, 14:47:32- V3.0 - Text, picture and binary files viewer
*  ...
* -04.04.1993, 23:07:01- V3.6 - Rewritten for OS 3 (mainly, console handling...)
* -18.06.1994, 21:05:22- V3.7 - Up from this version 100% OS 3 compatible, also brush support
*				(complete re-work of picture decoding)
* -24.06.1994, 15:33:28- V3.8
* -26.06.1994, 01:54:47- V3.9
* -28.06.1994, 14:42:19- V3.A
* -30.06.1994, 00:23:00- V3.B  - Bug fixed version
* -08.01.1995, 22:04:00- V3.BA - better Monitor handling plus ACBM files viewer -
*				 pure sentimental - want to see old Amiga Basic used
*				 pictures.
*				 Now Viewer supports also a masking plane ....
* -15.05.1996, 12:45:47- V3.C1 - FinalCopy-II and IFF-Text ASCII extracting support
* -25.05.1996, 16:03:25- V3.D3 - Pweeh, string search routine implemented....
*				 I crashed my system totally with lost of the source
*				 because I forgot to give DisplayBeep() a parameter (NULL).
*				 With MasterSekaV1.71 I recovered the lost source.
* -23.08.1997, 21:22:54- V3.D38 - Viewer can now display 8bit images 100% correctly on a CyberGrafX (41.2+) screen
* -28.12.1997, 23:03:31- V3.D39 - After heavy request AutoRequester now supports keys (AMIGA-V, AMIGA-B)
* -19.02.1998, 09:53:16- V3.D3A - Viewer is now compatible (97%) to the Picasso96 software package
*				  and to other alien gfx-board software packages (I hope so).
* -18.10.1998, 21:44:21- V3.D3B - Viewer is now able to display 24 bit images on my gfx-card (CyberVision3D)
* -09.04.1999, 22:26:29- V3.E00 - Conversion from HAM8 to 24 bit added (Picasso96 now 100% compatible to Viewer!!!)
* -23.04.1999, 20:04:31- V3.ED0 - HAM6 to 24 bit tune-up implemented (removed code for HAM6 to 16 bit - too less brillance)
* -01.05.1999, 23:31:48- V3.EDE - Removed bug that caused machine to crash upon displaying non-super bitmap images
*				  on native AMIGAs and which was introduced with the code to display HAM8 images on
*				  a 24 bit screen (set two `bne´ to wrong labels where one lead to an invalid stack)
* -12.08.1999, 19:47:20- V4.0 - Added function to play either compressed or uncompressed 8SVX mono sound files from
*				fast memory.
* -19.11.1999, 15:32:17- V4.4 - Added support for 9 to 16 bitplane images (versions 4.1 - 4.3 extremly faulty)
*
*
*
*
* Simple Text-, Binary- and Image-file viewer for the Amiga Operation System.
*
* This material is released "as it", no warranties are made!
*
* The program-code is position independent and resident capable.
* It  requires  kickstart  1.2  or  higher and an Amiga Custom-Chip-Set (due
* some  code  which  can be easily rewritten for non based Amiga Custom Chip
* Set computers). AA- (AGA) resolution support added for pic-viewer of V3.7.
*
* Tested  successfully  under  SegTracker,  Enforcer, Mungwall, IOTorture in 
* many circumstances.
*
* The  executeable  based  on this source may freely distributed so long the
* copyright notice is unmodified - known as FreeWare.
*
* The  source-code  may improved by anyone who wants to do it - in this case
* please read the "PRG-ShouldRead" file first - for the agreements.
*
* This  source-code  may  enclosed  to  _ANY_  assembler  package  (also  in
* modified  form)  for  an example "how to code in 680x0 assembler", but the
* copyright notice must be at least unaltered.
*
*
* Noone can say: Copyright "Whose name" - I'm (J.v.d.Loo) the copyright holder!
*
*
* This  program  was  written  using  HiSoft's  Devpac  Amiga  3 assembler -
* without its special advantages.
*
*
* If  anyone  takes  money  for  this  source-code,  object-file or enclosed |
* documentation  and  someone  tells me - the fellow who took the money will |
* meet  me  - more than 6 foots tall, more than 200 pounds - and what's very |
* dangerous  -  carrier of the stinking sock - but my Master told me to take |
* off  my  shoes only in an emergency - the smell is not the worst - he said |
* - but the burning eyes...						     |
*
*
* NOTES:
* This source file can be assembled unmodified at least with:
*	HiSoft's Devpac Amiga Assembler 3   (commercial) [fast assembler]
*	Samu Noujua's SNMA Assembler 1.99   (freeware)   [fast assembler]
*	Frank Wille's PhxAss Assembler 4.18 (shareware)  [medium assembler/ fast linker]
*
* For  the  Macro-System's Draco computer you have to remove all lines which
* are accessing the hardware directly.
*
* List of what to do...
* 	Printer  status should be tested via parallel/and or serial devices,
* 	using QUERY-command.
*	Picture  display  routine must first open the screen, then a window.
*	'Blit' the image to the window rastport instead of screen's bitmap.
*	May  replace code for scrolling SuperBitMaps through 'Blits' because
*	the  most 3rd graphic board software doesn't support changes of View
*	dx/dy,  or  they  don't  support  custom  bitmaps and then the image
*	screen's bitmap is only as tall as the standard monitor resolution.
*	Status  of  left-  and  right mousebuttons can be easily checked via
*	IDCMPs of the (added) image window.
*	The other code is system-conform (I hope...).


	IFD	__G2

	OUTPUT	RAM:Viewer		; Child's name when using Devpac

	MACHINE	MC68000			; Processor selection

	ENDC

*	OPT	D+

	include	exec/types.i
	include	exec/memory.i
	include	exec/ports.i
	include	exec/lists.i
	include	exec/devices.i
	include	exec/execbase.i

	include	graphics/gfx.i
	include	graphics/text.i
	include	graphics/rastport.i
	include	graphics/gfxbase.i
	include	graphics/graphics_lib.i

	include	intuition/intuition.i
	include	intuition/screens.i
	include	intuition/intuitionbase.i
	include	intuition/intuition_lib.i

	include	dos/dos.i

	include	devices/audio.i


***********************************
*
* Define needed constants and arrays
*
    STRUCTURE	_Table,68		; Begin at offset 68 (end of table used by startup-code)

	ULONG	_dummy000		; Only to make "FIB" staying on a through eight
*					  divisible address - you may use "ALIGNLONG"
*					  MACRO instead...

	STRUCT	_FIB,272		; FileInfoBlock

	STRUCT	_NewScreen,ens_SIZEOF	; Screen's structure
	STRUCT	_StdTags,56		; Screen's taglist (up from OS 2.0)

	STRUCT	_WindowRecord,nw_SIZEOF	; Window's structure
	STRUCT	_ErrWindowStruc,nw_SIZEOF ; Ditto

	STRUCT	_Gad1,gg_SIZEOF
	STRUCT	_Gad2,gg_SIZEOF
	STRUCT	_GTxt1,it_SIZEOF
	STRUCT	_GTxt2,it_SIZEOF

	STRUCT	_Gad3,gg_SIZEOF		; Audio Hit Gadget, no text

	STRUCT	_ArpReqStruc,32		; Only 26 bytes are needed
	STRUCT	_UserFontStruc,8	; Font-record

	ALIGNLONG

	ULONG	_RealIWidth		; No boundary
	ULONG	_ImageWidth		; 16 bit boundary

* BMHD-settings follow..... - used for picture
	UWORD	_Width			; May be taller than displayable... (64 bit boundary)
	UWORD	_Height			; ditto
	UWORD	_XPos
	UWORD	_YPos
	UBYTE	_Depth
	UBYTE	_Masking
	UBYTE	_Compresstyp
	UBYTE	_BMHDFlags		; Was before ks 3.0 unused (bmhd_pad)
	UWORD	_TransColour
	UBYTE	_XAspect
	UBYTE	_YAspect
	UWORD	_PlaneWidth		; Visible size
	UWORD	_PlaneHeight		; ditto
	UWORD	_Dummy			; Strictly for longword adjustment
	ULONG	_ViewPortMod
	STRUCT	_Colourmap,1024		; Max. room for 256 colours

	ULONG	_TypeOfMem		; Which memory type used for bitmap allocation? (~0 = CHIP, 0 = ANY)
	LONG	_ViewPortShare		; Can we change through RasInfo the visible part of an image ( 0=yes,1=yes,-1=no)
	ULONG	_HAMSet			; Depth of image in case image is HAM encoded

	UWORD	_OldY			; Used only for ks lower than v36
	UWORD	_OldX			; Used only for ks lower than v36

	UWORD	_BgPen			; Colour-index for background of window's title

	STRUCT	_DisplayInfo,dis_SIZEOF	; Buffer for DisplayInfoData

	ALIGNLONG			; <- EXEC/EXEC_TYPES.I

	APTR	_GfxBase
	APTR	_IntuitionBase
	APTR	_ReqToolsBase
	APTR	_ArpBase
	APTR	_CyberGfxBase
	APTR	_ScreenPtr

	APTR	_ReqPtr			; ReqTools requester record

	ULONG	_argError		; Not zero upon argument error
	ULONG	_LinesInFile		; Number of lines in file
	ULONG	_UPFSize		; Uncompressed file size
	ULONG	_IncSize		; Increased uncompressed file size
	ULONG	_Line			; Current line where cursor stays
	ULONG	_PageWidth
	UWORD	_StdPageSize		; Std. scrollwidth for console in lines

	ALIGNLONG

	APTR	_ErrWindowPtr		; Intuition window record
	APTR	_DecrunchAddr		; Address decrunched file
	APTR	_StdprWindowPtr		; Old pointer for system requesters
	APTR	_PtrToWTitle		; Pointer to window's title text
	APTR	_UserProject		; Info-file (for icon.library)
	APTR	_WindowPtr		; Intuition window record
	APTR	_IAddr			; Window's object that raised message

	STRUCT	_WindowTitle,148	; Room for window's title (title is
*					  changed each time a new file is loaded)

	LABEL	_WriteIo		; Startaddress for console-write message
	STRUCT	_Msg,20			; Message length, 20 byte
	STRUCT	_Io,12			; Console-write IO, 12 bytes
	STRUCT	_WriteReq,16		; Console-write request, 16 bytes
	STRUCT	_WriteReply,34		; ReplyPort for Console-write

	STRUCT	_ReadIo,48		; Console-read message including IO and REQ
	STRUCT	_ReadReply,34		; Console-read reply port

	ALIGNLONG

	APTR	_TextPtr		; Address file in memory
	APTR	_BufferSize		; Allocated size
	LONG	_FileSize		; File's real size

	BPTR	_LockSave		; Key to file (closed)
	BPTR	_FileHandle		; Handle (closed)

	APTR	_UserFontPtr		; Font record (perhaps opened)
	APTR	_OldFontPtr		; System's default font

	APTR	_SearchStrPtr		; Pointer to search address (from where to continue)
	ULONG	_SearchStrLen		; Length of search string
	ULONG	_CharBuffer		; Read char of IO-request to build complete search string
	STRUCT	_IOReqString,256	; Buffer which contains search string

	STRUCT	_IOInlineBuf,64		; Buffer for converting IO-status report to ascii


	APTR	arg_1			; Shell arguments....
	APTR	arg_2
	APTR	arg_3

	STRUCT	WB_arg_1,60		; WBench arguments (tooltypes) (max.: 14!!!)

	BPTR	lock_1			; Overgiven files (Workbench, -the trick
	APTR	file_1			;  with the shift...)
*	BPTR	lock_2
*	APTR	file_2
*	BPTR	lock_3
*	APTR	file_3


	STRUCT	_Drive,256		; Buffer for volume's/directory's name
	STRUCT	_File,108		; The filename itself
	STRUCT	_FileName,364		; Merged name in dos-convention

	STRUCT	_UserFontBuf,108	; Into this buffer the name of the font
*					  the user want to use is copied from the
*					  tooltypes - so that we can modify it

	STRUCT	_ConBuffer,256		; Buffer for console commands

	APTR	_SourceFileSize		; Same as FileSize (used by picture)
	APTR	_SourceFilePtr		; Same as TextPtr + 2 (used by picture)

	APTR	_RGB24Ptr
	ULONG	_RGB24Size

	APTR	_Bitplane		; Address decompressed ILBM file (chip mem)
	ULONG	_AllPlaneSize		; Size of all planes (connected bitplanes)

	STRUCT	_BitmapStruc,bm_SIZEOF+(4*16)	; Screen's or image's bitmap (for safety, 24 bit depth)

	ULONG	_CMapNumEntries		; Colourmap entries (max. 256)

	APTR	_RGB32Values		; Pointer to 32Bit colours of ILBM-file
	STRUCT	_RGB32Colours,((256*3)+2)*4	; Room for 256 32Bit colours (see LoadRGB32())

	UWORD	_RMB			; State of right mouse button
	UWORD	_Max			; Local used (haven't got enough unused registers)

	UWORD	_MouseID		; Saved mouse event

	UWORD	_PageSize		; Number of lines of one page
	UWORD	_XOffset		; X and Y offset for console window,
	UWORD	_YOffset		; specified in ToolType


	UBYTE	_NoLineFlag		; Flag, if it is non-zero, the lines are
*					  not counted, e.g. when restoring window
*					  contents
	UBYTE	_NoWarnFlag		; When this flag is set, displaying
*					  warnings is supressed
	UBYTE	_NoCheckPrtFlag		; When this is set, the printer is not checked
	UBYTE	_WrapFlag		; When this is set, make a word wrap when
*					  the contents of one line do not fit in window
	UBYTE	_PageSizeFlag		; When this flag is set, the user has got defined the
*					  scrollwidth
	UBYTE	_ReqFlag		; Indicates which requester is used,
*					  0 == no requester opened till now
*					  1 == ReqTools
*					  2 == Arp
*					 -1 == bad luck, ReqTools nor Arp could be opened
	UBYTE	_LoadFlag		; Indicates loading or saving, 0 == saving

	UBYTE	_BlitFlag		; Local used, means blit image to screen
	UBYTE	_SuperBitMap		; Local used, means screen uses a superbitmap
	UBYTE	_RIChanged		; Local used, RasInfo is changed, so call
*					  MakeScreen() and RetinkDisplay()

	ALIGNLONG

	APTR	_AudioBuffer		; Address audio datas in Chip-Mem
	ULONG	_AudioBufferSize	; How tall is that buffer?
	ULONG	_AudioPeriod		; How many samples per second?
	APTR	_VHDRPtr
	APTR	_BODYPtr
	ULONG	_BODYSize
	APTR	_IOAudio
	UBYTE	_AudGadget

	LABEL	_TableSize		; Pweeh, size of the defined constants and
*					  arrays, is automatically allocated when
*					  this program is started (done by startup-code)


*
** Include the startup-code
*
	include	RAD:include/startup.easy	; Simple but effective startup-code
*						  - perhaps you should change directory...

*
** RAW-key equates....
*
CRSR_UP		equ	$4C			; Page Up
CRSR_DN		equ	$4D			; Page down
CRSR_BK		equ	$4E			; one line back
CRSR_FD		equ	$4F			; one line further
L_Key		equ	$28			; load new
E_Key		equ	$12			; enlarge window
H_Key		equ	$25			; help page
I_Key		equ	$17			; info
A_Key		equ	$20			; about page
T_Key		equ	$14			; top of file
B_Key		equ	$35			; bottom of file
W_Key		equ	$11			; window contents to prt
P_Key		equ	$19			; print file to prt
F_Key		equ	$23			; print file to file
C_Key		equ	$33			; window contents to file 
PG_UP		equ	$3F			; page up
PG_DN		equ	$1F			; page down
RETURN		equ	$44			; one line down
ENTER		equ	$43			; one line down
HOME		equ	$3D			; top of file
END		equ	$1D			; button of file
R_SHIFT		equ	$61			; one line back (step)
R_Key		equ	$13			; refresh Window
S_Key		equ	$21			; Search (find)
N_Key		equ	$36			; Next search (find)
PrtSc		equ	$5D			; print screen to prt
HELP_Key	equ	$5F			; Display title


* - ReqTools
	IFND	_LVOrtAllocRequestA
_LVOrtAllocRequestA	EQU	-30
	ENDC

	IFND	_LVOrtFreeRequestA
_LVOrtFreeRequestA	EQU	-36
	ENDC

	IFND	_LVOrtChangeReqAttrA
_LVOrtChangeReqAttrA	EQU	-48
	ENDC

	IFND	_LVOrtFileRequestA
_LVOrtFileRequestA	EQU	-54
	ENDC

* - Arp
	IFND	_LVOArpFileRequest
_LVOArpFileRequest	EQU	-294
	ENDC

* - DiskFont
	IFND	_LVOOpenDiskFont
_LVOOpenDiskFont	EQU	-30
	ENDC

* - CyberGraphics
	IFND	_LVOWritePixelArray
_LVOWritePixelArray	EQU	-126
	ENDC

	IFND	RECTFMT_RGB
RECTFMT_RGB	EQU	0
	ENDC

*************************************************************
*
* This subroutine parses the Shell arguments.
* Inputs: none (routine uses global constants).
* Result: ErrorCode placed in "_argError", see "EQU's" below.
*
* Remarks: Only three arguments are parsed (if available).
*

ed_QuoteNotAllowed	EQU	1	; Possible errorcodes
ed_MissingEndQuote	EQU	10	; stored in "_argError"

_getArg
	movea.l	_argv(A5),A0
	lea	arg_1(A5),A1
	moveq	#0,D2
	bra.s	_getArg1.1
_getArg.1
	addq.b	#4,D2
	cmpi.b	#12,D2			; 3 args * à 4 bytes = 12
	beq.s	_argEnd
	cmpi.b	#' ',(A0)
	beq.s	_skipUnused
_getArg1.1
	cmpi.b	#10,(A0)
	beq.s	_argEnd
_getArg.2
	cmpi.b	#'"',(A0)
	beq.s	_inQuotes
_noQuotes
	move.l	A0,(A1,D2.w)
_stdLoop
	cmpi.b	#'"',(A0)
	beq.s	_argError.1
	cmpi.b	#10,(A0)
	beq.s	_noMoreArg
	cmpi.b	#' ',(A0)
	beq.s	_nextArgument
	addq.l	#1,A0
	bra.s	_stdLoop
_nextArgument
	clr.b	(A0)+
	bra.s	_getArg.1
_inQuotes
	addq.l	#1,A0
	move.l	A0,(A1,D2.w)
_quoteLoop
	cmpi.b	#10,(A0)
	beq.s	_argError.2
	cmpi.b	#'"',(A0)
	beq.s	_nextArgument
	addq.l	#1,A0
	bra.s	_quoteLoop
_noMoreArg
	clr.b	(A0)
1$
	addq.b	#4,D2
	cmpi.b	#12,D2			; max: 3 arguments
	beq.s	_argEnd
	clr.l	(A1,D2.w)
	bra.s	1$
_argEnd
	rts				; back
_skipUnused
	addq.l	#1,A0
	cmpi.b	#' ',(A0)
	beq.s	_skipUnused
	bra.s	_getArg1.1
_argError.1
	moveq	#ed_QuoteNotAllowed,D0
	bsr.s	_setArgError
	subq.b	#4,D2
	bra.s	_noMoreArg
_argError.2
	moveq	#ed_MissingEndQuote,D0
	bsr.s	_setArgError
	subq.b	#4,D2
	bra.s	_noMoreArg
_setArgError
	move.l	D0,_argError(A5)
	rts

******************************************************************************
*
* Routine to parse from Workbench overgiven files.
* Inpts: D0 - how many arguments (files) allowed to store
*        D1 - how many arguments are there?,
*	 A0 - pointer to sm_ArgList (global - startup-code -> WBench-message),
*	 A1 - address array for lock of file and filename, -
*	      - array must look like this:
*		BPTR Lock
*		APTR File (string pointer)
*		BPTR Lock
*		APTR File (string pointer)
*		... and so on
* Results: none
*

_GetWBFiles
	subq.l	#1,D1
	beq.s	3$
	bcs.s	3$
	addq.l	#4,A0
	bra.s	2$
1$
	addq.l	#4,A0
	move.l	(A0),(A1)+		; Lock
	addq.l	#4,A0
	move.l	(A0),(A1)+		; Filename
	subq.l	#1,D1			; argc -1
	beq.s	3$
2$
	dbf	D0,1$
3$
	rts

****************************************************
*
* Subroutine to set the returncode for this program,
* use Shell-command why to investigate the error.
*
* Inputs: D0 - errorcode
* Results: none
*

_SetError
	move.l	D0,_errno(A5)
_setError4Task
	movea.l	_SysBase(A5),A0
	movea.l	276(A0),A0		; ThisTask
	move.l	D0,pr_Result2(A0)
	rts

******************************************
*
* Entry point, called out of startup-code.
*

_main	; Startup-Code enters here...
	bsr.w	_InitStandard		; Init windows

	tst.l	_WBenchMsg(A5)
	bne.s	.GetWBArgs		; If we are started from workbench
	bsr.w	_getArg			; otherwise parse Shell arguments
	bra.s	.argsOk
.GetWBArgs
	tst.l	_argc(A5)		; Any file given (from WB)?
	beq.s	0$

	moveq	#1,D0			; Max. allowed number of arguments!
	move.l	_argc(A5),D1		; Number of arguments stored (WB)
	movea.l	_argv(A5),A0		; sm_ArgList pointer
	lea	lock_1(A5),A1		; Address buffer
	bsr.s	_GetWBFiles		; Call subroutine to parse files

0$
	moveq	#13,D0			; 14 Entries
	tst.l	_ToolTypesArray(A5)
	beq.s	.argsOk

	movea.l	_ToolTypesArray(A5),A0	; Pointer to ToolTypeArray
	lea	WB_arg_1(A5),A1		; Address first WB-Text
1$
	tst.l	(A0)
	beq.s	.argsOk			; If no more texts are set...
	move.l	(A0)+,(A1)+		; WB-Arg-Text -> Arg[1..] a.s.o.
	dbf	D0,1$

.argsOk		
	move.l	#20,_errno(A5)
	bsr.w	_SetPrefs		; See there
	bsr.w	_OpenROMLibs		; Open libraries
	tst.l	_WBenchMsg(A5)		; WB-start?
	beq.s	4$			; No? - then it was a Shell-start
	bsr.w	_SetDirection		; Get user datas
	bsr.w	_CheckWarning
	bsr.w	_CheckExecute		; Execute (if a specification) a command
4$
	bsr.w	_SetWindow		; Set window limits
	bsr.w	_CheckWrap		; Check Word-Wrap (ToolTypes)
	move.l	#100,_errno(A5)
	bsr.w	_OpenWindow
	tst.l	D0
	beq.w	_Out_02			; Don't bomb

**********************************************
*
* Open console device for reading and writing.
*

	move.l	#80,_errno(A5)
	movea.l	_SysBase(A5),A6		; Make ReadReplyPort
	lea	_ReadReply(A5),A0
	move.l	_OwnTask(A5),MP_SIGTASK(A0)	; Task to be signalled
	lea	MP_MSGLIST(A0),A0		; Console-read reply port
	NEWLIST	A0

	lea	_WriteReply(A5),A0	; Make WriteReplyPort
	lea	MP_MSGLIST(A0),A0	; Console-read reply port
	NEWLIST	A0

	lea 	_ReadIo(A5),A1
	move.l	_WindowPtr(A5),IO_DATA(A1)
	move.l	#wd_SIZEOF,IO_LENGTH(A1)
	moveq	#0,D0			; Unit
	moveq	#0,D1			; Flags
	lea	_DeviceName(pc),A0
	jsr	_LVOOpenDevice(A6)	; Open console device
	tst.l	D0
	beq.s	.ConsoleIsOpen
	lea	_ErrorOpenDevTxt(pc),A0	; else...
	bsr.w	_DisplayError
	bra.w	_Out_01

.ConsoleIsOpen
	lea	_ReadIo(A5),A0		; ReadIo<->WriteIo 
	lea	_WriteIo(A5),A1
	move.l	IO_DEVICE(A0),IO_DEVICE(A1)	; Device
	move.l	IO_UNIT(A0),IO_UNIT(A1)		; Unit

	lea	_ReadReply(A5),A2
	move.l	A2,MN_REPLYPORT(A0)

	lea	_WriteReply(A5),A2
	move.l	A2,MN_REPLYPORT(A1)

	clr.l	_errno(A5)

***********************
*
* Some useful stuff....
*

	bsr.w	_CursorOff		; Cursor invisible
	bsr.w	_SetPtr4Req		; Twist pointer for system-requesters
	bsr.w	_SetScrollWidth		; Seek and set scrollwidth
	bsr.w	_SetPageWidthAndLen	; Seek and set page sizes

	lea	_ConBuffer(A5),A0	; Address buffer
	move.w	#$9B48,(A0)		; Cursor Home
	moveq	#2,D0			; 2 chars for output
	bsr.w	_ConOut_Rel		; Write down to console...

	tst.l	arg_1(A5)		; Any file placed?
	bne.w	_CLILoad		; Yes..
	tst.l	file_1(A5)		; Or is there a file?
	bne.w	_WBLoad			; Yes...
*					  Otherwise....
_InitRequester
	bsr.w	OpenReq			; Open for requests needed libraries
	tst.b	_ReqFlag(A5)		; ReqTools or Arp opened?
	bmi.w	_End_1			; No, bad luck
_NextTry
	st.b	_LoadFlag(A5)		; We want to load...
	bsr.w	_GetFile		; Build request and get file
	cmpi.l	#-1,D0			; Hard error?
	beq.w	_End_1			; Ok, finish immediately
	tst.l	D0			; No file?
	beq.s	_NoFileChosen		; Too bad
	
	bsr.w	_ReadFile		; Read that file
	tst.l	D0			; Any error?
	beq.s	_Loop			; Yes...

*
** Now we check the file. If it returns to this point all went ok.
** We check for ascii files, binary files, PP20 files, ILBM files.
*
	bsr.w	_CheckFile

	bsr.w	_IgnoreSettings		; ANSI-Filter

	bsr.w	_SetViewerPrefs		; Preferences

	bra.w	_FirstPage		; Display first page

_NoFileChosen
	lea	_NoFileMsg(pc),A0
	bsr.w	_DisplayError
	tst.l	D0			; User said: "Cancle" loading
	beq.w	_End			; If so, terminate...

***********************************************
*
* Main routine, is waiting until an event occurs.
*

_Loop
	clr.b	_NoLineFlag(A5)		; Allow line counting
	bsr.w	_ComLine		; Make window-title

.noComLine
	bsr.w	_SetActionWait		; Allow intuition to send us RAW-key messages

	tst.l	_TextPtr(A5)		; Any text to display?
	beq.s	.NoNextTxt		; If not

	tst.b	_AudGadget(A5)
	bne.s	.NoNextTxt

	tst.w	_MouseID(A5)		; This inidicates if a mousebutton
*					  was already touched, if it was touched,
	bne.w	.MouseWasTouched	; we have to jump to an other routine...

.NoNextTxt
	move.l	A2,-(sp)
	movea.l	_WindowPtr(A5),A2
	movea.l	wd_UserPort(A2),A2
	movea.l	A2,A0
	movea.l	_SysBase(A5),A6
	jsr	_LVOWaitPort(A6)	; Wait until a message has reached us

	movea.l	A2,A0
	jsr	_LVOGetMsg(A6)
	movea.l	D0,A1
	movea.l	D0,A2
	jsr	_LVOReplyMsg(A6)

	move.l	20(A2),D0		; im_Class
	move.w	24(A2),D1		; im_Code
	move.l	28(A2),_IAddr(A5)
	movea.l	(sp)+,A2
*
** Some notes at this point: normally you should remember the received things i.e.
** im_Class, im_Code, im_IAddress and so on into private constants and _THEN_
** reply the message to avoid conflicts with intuition. Because intuition does
** only send us (at most) each 1/10 second a message - and this is assembler -
** _AND_ we awoke yet (running task) it's not too critical to save the message
** things not - _BUT_ - if intuition is rewritten for (may be) Kickstart 41/42
** and it's then a lot faster, the replying without saving will cause BIG trouble.
*
	cmpi.l	#$8,D0			; MouseButtons?
	beq.s	4$			; Startup for mouse-buttons!!!!

	cmpi.l	#$40,D0
	beq.s	3$

	bsr.w	_SetNILWait		; Tell intuition we don't want to have message
*					  for now, do it via a PA_IGNORE flag which
*					  blocks messages for our window

	clr.w	_MouseID(A5)		; Erase ID

	movem.l	D0-D1,-(sp)
1$
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	jsr	_LVOGetMsg(A6)		; Ignore following messages until
	tst.l	D0			; flag is active...
	beq.s	2$

	movea.l	D0,A1
	jsr	_LVOReplyMsg(A6)	; Free message
	bra.s	1$
2$
	movem.l	(sp)+,D0-D1

	cmpi.l	#$200,D0		; CLOSEWINDOW ?
	beq.w	_End			; If so...

	cmpi.l	#$400,D0		; RAWKEY?
	beq.w	_RawKey			; If so...

3$
	cmpi.l	#$40,D0			; Gadget up ?
	bne.w	_Loop
	movea.l	_IAddr(A5),A0
	cmpi.w	#3,gg_GadgetID(A0)	; Gadget id = 3?
	bne.w	_Loop
	bra.w	_AudioHit

*
** If the first time a mousebutton was clicked, we are at this point.
*
4$
	tst.b	_AudGadget(A5)
	bne.w	_Loop

	move.w	D1,_MouseID(A5)

	cmpi.w	#$69,D1			; Right one?
	bne.s	.LeftOne
	move.w	D1,_MouseID(A5)
.RO1
	move.w	#CRSR_FD,D1
	bra.s	_RawKey

.LeftOne
	cmpi.w	#$68,D1			; Left one?
	bne.s	.NotValid		; Not a valid message...
	move.w	D1,_MouseID(A5)
.LO1
	move.w	#CRSR_BK,D1
	bra.s	_RawKey
.NotValid
	clr.w	_MouseID(A5)
	bra.w	_Loop

*
** A mouse-button was clicked a while ago, we have now to check if the mousebutton
** was released.
*
.MouseWasTouched
	move.l	A2,-(sp)
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	movea.l	_SysBase(A5),A6
	jsr	_LVOGetMsg(A6)		; Do we have a message?
	tst.l	D0
	beq.s	.further		; No, just do it like a mousebutton was clicked
	movea.l	D0,A1
	movea.l	D0,A2
	jsr	_LVOReplyMsg(A6)
	cmpi.l	#$8,im_Class(A2)	; MouseButtons?		| SEE NOTES ABOUT
	bne.s	.further		; see above		| MESSAGES A PIECE
	cmpi.w	#$68+$80,im_Code(A2)	; Left one released?	| FURTHER ABOVE....
	beq.s	.EndMouse
	cmpi.w	#$69+$80,im_Code(A2)	; or right one released?
	bne.s	.further
.EndMouse
	movea.l	(sp)+,A2
	clr.w	_MouseID(A5)		; Clear ID (code), indicates that no mouse-
	bra.w	_Loop			; button is held down

.further
	movea.l	(sp)+,A2
	cmpi.w	#$68,_MouseID(A5)	; Left mousebutton?
	beq.s	.LO1
	bra.s	.RO1			; else it was the right one!
*
** Startup for console action
*
_RawKey
	lea	_ConBuffer(A5),A0	; Buffer
	move.w	D1,(A0)			; Store there the raw-key
	bra.w	_ConsoleEvent		; just go ahead


**********************
*
* Our end has come....
*

_End_1
	lea	_NoReqTxt(pc),A0	; Fail with message (couldn't open file-
	bsr.w	_DisplayError		; requester)
_End
	movea.l	4.w,A6
	suba.l	A1,A1
	jsr	_LVOFindTask(A6)
	movea.l	D0,A0
	movea.l	pr_ReturnAddr(A0),A0	; Program's exit address
	subq.l	#8,A0
	movea.l	(A0),A5			; Restore basetable pointer

	movea.l	_OwnTask(A5),A0		; Restore pointer for system-requesters
	move.l	_StdprWindowPtr(A5),184(A0)

	tst.l	_UserProject(A5)	; .info-file there?
	beq.s	0$
	movea.l	_IconBase(A5),A6
	movea.l	_UserProject(A5),A0
	jsr	_LVOFreeDiskObject(A6)	; Free the info-file resources
0$
	movea.l	_SysBase(A5),A6
	lea	_ReqToolsBase(A5),A2	; ReqTools-library open?
	tst.l	(A2)
	beq.s	1$			; No
	movea.l	A6,A4			; Save Exec
	movea.l	(A2),A6			; ReqTools-Base
	movea.l	_ReqPtr(A5),A1		; File-requester-record
	jsr	_LVOrtFreeRequestA(A6)	; Free it
	movea.l	A6,A1			; ReqTools-Base A1
	movea.l	A4,A6			; Exec
	jsr	_LVOCloseLibrary(A6)
1$
	tst.l	_ArpBase(A5)		; Arp-Library open?
	beq.s	2$			; No
	movea.l	_ArpBase(A5),A1
	jsr	_LVOCloseLibrary(A6)
2$
	tst.l	_CyberGfxBase(A5)
	beq.s	3$
	movea.l	_CyberGfxBase(A5),A1
	jsr	_LVOCloseLibrary(A6)
3$
	move.l	_BufferSize(A5),D0	; Something allocated?
	beq.s	4$			; No
	movea.l	_TextPtr(A5),A1		; Else
	jsr	_LVOFreeMem(A6)		; free it
4$
	bsr.w	_FreeAudio

	movea.l	_SysBase(A5),A6
	lea	_ReadIo(A5),A1
	jsr	_LVOCloseDevice(A6)	; Close console-device
_Out_01
	bsr.w	_CloseWindow		; Close main-window
_Out_02
	bsr.w	_CloseROMLibs		; Close 'em

	rts				; Back into startup-code

********************************************
*
* One routine with a few entries to call....
*
* It will write down to the console-window
* the overgiven text.
*

_ConOut		; Write down 1 char, the char is in the "_ConBuffer"
	movea.l	_SysBase(A5),A6
	lea	_WriteIo(A5),A1		; Io-structure for writing
	move.l	#1,IO_LENGTH(A1)	; 1 char for output

_ContConOut	; Write down x-chars, the chars are in the "_ConBuffer"
	move.w	#CMD_WRITE,IO_COMMAND(A1)	; Command = Write
	lea	_ConBuffer(A5),A0	; Address char

_ContConOut_01	; Check first for tab-width (take 1 tab as 8 blanks)
	bsr.s	_CheckTAB
_ContConOut_02	; Just do it (writing)
	move.l	A0,IO_DATA(A1)		; Address string
	movea.l	_SysBase(A5),A6
	jsr	_LVODoIO(A6)		; Do it, but wait until done
	lea	_ConBuffer(A5),A0
	rts

_ConOut_Rel	; Relative length, rigid address (number of chars in D0)
	lea	_WriteIo(A5),A1
	move.l	D0,IO_LENGTH(A1)
	bra.s	_ContConOut

_ConOut_Reloc	; Relative length, relative address (number of chars in D0,
*						     address string in A0)
	movea.l	_SysBase(A5),A6
	lea	_WriteIo(A5),A1
	move.l	D0,IO_LENGTH(A1)
	move.w	#CMD_WRITE,IO_COMMAND(A1)	; Command = Write
	bra.s	_ContConOut_01

*****************************************************
*
* Compute length for one line, take 1 tab as 8 blanks.
*

_CheckTAB
	tst.b	_WrapFlag(A5)		; Word Warp allowed?
	bne.w	.CT_End			; If so...

	tst.l	_PageWidth(A5)
	beq.w	.CT_End

	movem.l	D0-D3/A0-A2,-(sp)
	move.l	_PageWidth(A5),D3	; Number of Displayable columns
	addq.w	#1,D3
	move.l	D0,D2			; Number of chars to print down
	movea.l	A0,A2			; Address string
.CT_Next
	movea.l	A2,A0			; Current string
	moveq	#0,D0			; Number of Chars
	moveq	#0,D1			; Number of columns
.CT_Search
	addq.w	#1,D0			; Number of chars plus 1
	addq.w	#1,D1			; Number of columns plus 1
	cmp.l	D1,D3			; Compare width maximum of possible
*					  displayable columns
	bls.s	.CT_Store

	cmpi.b	#10,(A2)		; LineFeed
	beq.s	.CT_Store
	cmpi.b	#9,(A2)			; TAB
	beq.s	.CT_AddTAB
	cmpi.b	#27,(A2)		; ESC
	beq.s	.CT_IgnoreESC

	addq.l	#1,A2
	subq.w	#1,D2			; Number of chars minus 1
	beq.s	.CT_Store
	bra.s	.CT_Search

.CT_Store
	lea	_WriteIo(A5),A1		; Io-structure for writing
	move.w	#CMD_WRITE,IO_COMMAND(A1)	; Command = Write
	move.l	D0,IO_LENGTH(A1)	; Chars for output
	move.l	A0,IO_DATA(A1)		; Address string
	movea.l	_SysBase(A5),A6
	jsr	_LVODoIO(A6)		; Do it, but wait until done

	tst.w	D2
	beq.s	.CT_End_1

	moveq	#-1,D0
1$
	subq.w	#1,D2
	beq.s	.CT_End_1
	cmpi.b	#10,(A2)+		; LineFeed
	dbeq	D0,1$

	bra.s	.CT_Next

.CT_AddTAB
	addq.w	#7,D1
	andi.w	#-8,D1
	addq.l	#1,A2
	subq.w	#1,D2
	beq.s	.CT_Store
	bra.s	.CT_Search

.CT_IgnoreESC
	subq.w	#1,D1
	addq.l	#4,A2			; Ignore 4 chars (currently no real length
	addq.w	#3,D0			; checking (Sequencer) is done...)
	subq.w	#4,D2
	beq.s	.CT_Store
	bcs.s	2$
	bra.s	.CT_Search
2$
	subq.l	#1,A2
	subq.w	#1,D0
	addq.w	#1,D2
	bcs.s	2$
	bra.s	.CT_Store

.CT_End_1
	movem.l	(sp)+,D0-D3/A0-A2
.CT_End
	rts

***********************************************
*
* Read from console-window - but don't wait for
* the result.
*
* Inputs: D0 - number of chars to read
* Results: Chars in gloabal "_ConBuffer"
*

_QueueRead
	lea	_ReadIo(A5),A1
	move.l	D0,IO_LENGTH(A1)	; Number of chars to read
	move.l	A0,IO_DATA(A1)
	move.w	#CMD_READ,IO_COMMAND(A1) ; Command READ
	movea.l	_SysBase(A5),A6
	jmp	_LVOSendIO(A6)		; Send command

_GetConMsg
	moveq	#20,D0
	lea	_ConBuffer(A5),A0
	bsr.s	_QueueRead		; Get the message
	movea.l	_SysBase(A5),A6
	lea	_ReadReply(A5),A0
	jmp	_LVOGetMsg(A6)


************************************************************
*
* Open graphic and intuition libraries,
* required version is 33 (ks 1.2).
*
* Inputs: None
* Result: GfxBase and IntuitionBase
*	  (NULL not possible!!! - noone works with a ks. lower 33!!!)
* At the moment I know only one person who got a ks. lower than 33, 32,
* OS1.1 PAL - Amiga 1000, the machine with the WOM; no, he doesn't sells it...
*

_OpenROMLibs
	movea.l	_SysBase(A5),A6
	lea	_IntuitionName(pc),A1
	moveq	#33,D0
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_IntuitionBase(A5)
	moveq	#33,D0
	lea	_GfxName(pc),A1
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_GfxBase(A5)
	rts

****************************************
*
* Close graphic and intuition libraries.
*
* Inputs: None
* Results: None
*

_CloseROMLibs
	movea.l	_SysBase(A5),A6
	movea.l	_IntuitionBase(A5),A1
	jsr	_LVOCloseLibrary(A6)
	movea.l	_GfxBase(A5),A1
	jmp	_LVOCloseLibrary(A6)


*******************************************
*
* Open main window which is used as console
* window.
*
* We take from the tooltypes (if wb-start)
* the specified X- and Y-offset for our
* window and of course the font the user
* specified (in tooltypes) for this window.
*
* Inputs: None
* Results: _UserFontPtr (may be NULL)
*	   _WindowPtr (may be NULL)
*

_OpenWindow
	lea	WB_arg_1(A5),A0
.NextTType
	tst.l	(A0)			; Argument there?
	beq.s	_NoOffsetDeclared	; No
	movea.l	(A0)+,A1		; Address overgiven string
	lea	_OffsetSpecName(pc),A2	; Address string to compare
	moveq	#12,D0			; 13 chars to compare
.CheckTType
	cmpm.b	(A1)+,(A2)+		; Compare strings
	bne.s	.NextTType		; "WINDOWOFFSET="
	dbf	D0,.CheckTType
	movea.l	A1,A0			; Pointer to following string

	moveq	#0,D0
	move.b	(A0),D0
	lsl.w	#8,D0
	move.b	1(A0),D0
	lsl.l	#8,D0
	move.b	2(A0),D0
	lsl.l	#8,D0
	move.b	3(A0),D0
	cmpi.l	#'AUTO',D0		; Auto adjustment?
	bne.s	.Value	
	tst.b	4(A0)
	bne.s	.Value

	movea.l	_IntuitionBase(A5),A1
	movea.l	ib_ActiveScreen(A1),A1
	moveq	#0,D0
	move.b	sc_BarHeight(A1),D0
	addq.w	#1,D0
	move.w	D0,_YOffset(A5)
	bra.s	_NoOffsetDeclared	; ...altough it is...
.Value
	moveq	#0,D0			; No mask
	bsr.w	_StrToLong
	tst.l	D1
	bmi.s	_NoOffsetDeclared	; Upon error
.XOffsetGot
	move.w	D0,_XOffset(A5)		; Save X-Offset

	moveq	#0,D0			; No mask
	bsr.w	_StrToLong
	tst.l	D1
	bmi.s	_NoOffsetDeclared	; Upon error
.YOffsetGot
	move.w	D0,_YOffset(A5)		; Save Y-Offset

*
** Look for the font...
*
_NoOffsetDeclared
	lea	WB_arg_1(A5),A0
.NextTType
	tst.l	(A0)			; Argument there?
	beq.w	_NoFontDeclared		; No
	movea.l	(A0)+,A1		; Address overgiven string
	lea	_FontSpecName(pc),A2	; Address string to compare
	moveq	#4,D0			; 5 chars to compare
.CheckTType
	cmpm.b	(A1)+,(A2)+		; Compare strings
	bne.s	.NextTType		; "FONT="
	dbf	D0,.CheckTType
	movea.l	A1,A0			; Pointer to following string

	lea	_UserFontBuf(A5),A1	; Our private buffer
	tst.b	(A0)			; End of user's string?
	beq.w	_NoFontDeclared
1$
	move.b	(A0)+,(A1)+		; Copy font's name
	beq.w	_NoFontDeclared		; If an interrupted end...
	cmpi.b	#',',(A0)		; Comma = number follows!
	bne.s	1$

	move.b	#'.',(A1)+		; Add string ".font" to font's name
	move.b	#'f',(A1)+
	move.b	#'o',(A1)+
	move.b	#'n',(A1)+
	move.b	#'t',(A1)+
	clr.b	(A1)

	moveq	#0,D0			; No mask
	bsr.w	_StrToLong
	cmpi.l	#-1,D1
	beq.s	_NoFontDeclared

_OpenUserFont
	lea	_UserFontStruc(A5),A0	; FontAttr-record
	move.w	D0,4(A0)		; Save height of font
	move.b	#$40|1,7(A0)		; Designed and ROM-Font (on first try)
	lea	_UserFontBuf(A5),A1	; Buffer with font's name
	move.l	A1,(A0)			; Set name in FontAttr-record
	movea.l	_GfxBase(A5),A6
	jsr	_LVOOpenFont(A6)	; Try to open the font
	tst.l	D0			; Font opened?
	beq.s	.OpenDiskFont		; If not...
	movea.l	D0,A1			; TextFont
	lea	_UserFontStruc(A5),A0	; FontAttr-record
	move.w	4(A0),D1		; Get height of font
	cmp.w	20(A1),D1		; Height of opened font same as...
	beq.s	_GotFont		; Of course...

	movea.l	_GfxBase(A5),A6		; Otherwise close
	jsr	_LVOCloseFont(A6)	; opened font (got not the right height)

.OpenDiskFont
	lea	_DiskFontName(pc),A1	; "diskfont.library"
	moveq	#33,D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOOpenLibrary(A6)	; Open the library
	tst.l	D0
	beq.s	_NoFontDeclared		; Damned!

	movea.l	D0,A6			; DiskfontBase
	lea	_UserFontStruc(A5),A0	; Addr. FontAttr-record
	move.b	#$40|2,7(A0)		; Designed and DISK-Font!
	jsr	_LVOOpenDiskFont(A6)	; Load the disk-resident-font
	tst.l	D0			; Got font?
	beq.s	1$			; No...
	move.l	D0,D2			; Save font-pointer
	movea.l	A6,A1			; DiskFontBase
	movea.l	_SysBase(A5),A6
	jsr	_LVOCloseLibrary(A6)	; Close "diskfont.library"
	move.l	D2,D0			; Font-pointer
	bra.s	_GotFont
1$
	movea.l	A6,A1			; DiskfontBase
	movea.l	_SysBase(A5),A6
	jsr	_LVOCloseLibrary(A6)
	bra.s	_NoFontDeclared		; Error exit
_GotFont
	move.l	D0,_UserFontPtr(A5)	; Save font-pointer

*
** Attempt to open the window with (if) overgiven X- and Y-Offsets
** and (if) user specified font.
*
_NoFontDeclared
	movea.l	_SysBase(A5),A6
	jsr	_LVOForbid(A6)

	movea.l	_IntuitionBase(A5),A6
	move.l	ib_ActiveScreen(A6),_ScreenPtr(A5)	; Get active screen

	lea	_WindowRecord(A5),A0	; Window-record
	move.l	_ScreenPtr(A5),nw_Screen(A0) ; On this screen our window should appear
	movea.l	_ScreenPtr(A5),A1	; Address screen-record

	move.w	_XOffset(A5),D0
	beq.s	0$
	add.w	D0,(A0)			; Set left edge of window
0$
	move.w	_YOffset(A5),D0
	beq.s	1$
	add.w	D0,nw_TopEdge(A0)	; Set top edge of window
1$
	tst.w	nw_Width(A0)
	bne.s	2$
	move.w	sc_Width(A1),nw_Width(A0)
2$
	tst.w	nw_Height(A0)
	bne.s	3$
	move.w	sc_Height(A1),nw_Height(A0)
3$
	move.w	_XOffset(A5),D0
	beq.s	4$
	sub.w	D0,nw_Width(A0)
4$
	move.w	_YOffset(A5),D0
	beq.s	5$
	sub.w	D0,nw_Height(A0)
5$
	jsr	_LVOOpenWindow(A6)	; Open the window
	move.l	D0,-(sp)
	movea.l	_SysBase(A5),A6
	jsr	_LVOPermit(A6)
	move.l	(sp)+,D0
	move.l	D0,_WindowPtr(A5)	; Save window pointer
	beq.w	7$

	movem.l	D0/A2-A3,-(sp)
	movea.l	D0,A3			; Window
	movea.l	wd_BorderRPort(A3),A2	; RastPort of titlebar

	movea.l	_IntuitionBase(A5),A6
	cmpi.w	#35,LIB_VERSION(A6)	; Kickstart 2.x or higher?
	bls.s	.Read			; No...
	movea.l	wd_WScreen(A3),A0	; Window's screen
	jsr	_LVOGetScreenDrawInfo(A6)	; Get drawing infos
	tst.l	D0
	beq.s	.Read
	movea.l	D0,A1			; DrawInfos
	movea.l	dri_Pens(A1),A0		; Pointer to pen-array
	move.w	5*2(A0),D0		; Get fillpen (aktive window's bar background)
	move.l	D0,-(sp)
	movea.l	wd_WScreen(A3),A0	; Window's screen
	jsr	_LVOFreeScreenDrawInfo(A6)
	move.l	(sp)+,D0
	movea.l	_GfxBase(A5),A6		; Restore Base
	bra.s	.SavePen
.Read
	movea.l	A2,A1
	moveq	#28,D0			; X
	moveq	#1,D1			; Y (room of first vertical pixel)
	movea.l	_GfxBase(A5),A6
	jsr	_LVOReadPixel(A6)	; Get title bar's background colour
.SavePen
	move.w	D0,_BgPen(A5)		; Save colour
*
** Now we have to set the font for the title bar, it's the same like the screen's
** default font!
*
	movea.l	wd_WScreen(A3),A0	; The window our screen appears on
	lea	sc_RastPort(A0),A0	; Screen's rastport
	movea.l	rp_Font(A0),A0		; Default font
	movea.l	A2,A1			; Window's title bar rastport
	jsr	_LVOSetFont(A6)		; Set font (there isn't one - til now!)
	movem.l	(sp)+,D0/A2-A3

	tst.l	_UserFontPtr(A5)	; Font opened?
	beq.s	6$
	move.l	D0,-(sp)
	movea.l	_WindowPtr(A5),A1
	movea.l	wd_RPort(A1),A1		; RastPort
	move.l	rp_Font(A1),_OldFontPtr(A5)	; Save old font for later
	movea.l	_UserFontPtr(A5),A0
	jsr	_LVOSetFont(A6)		; Set font the user want

	move.l	(sp)+,D0
6$
	movea.l	_WindowPtr(A5),A1
	movea.l	wd_RPort(A1),A1		; RastPort
	cmpi.b	#1,rp_Mask(A1)		; Only one bitplane?
	beq.s	.okBP			; Yes...
	move.b	#%11,rp_Mask(A1)	; Max. 2 bitplanes for Gfx-output!
* At the moment (ks 3.0) it's not supported, may be ks 3.1 will support it.
* If this cause trouble with your 3rd party graphic board, remove the lines.

.okBP
	rts

7$
	tst.l	_UserFontPtr(A5)
	beq.s	8$
	movea.l	_UserFontPtr(A5),A1
	movea.l	_GfxBase(A5),A6
	jsr	_LVOCloseFont(A6)
8$
	moveq	#0,D0
	lea	_WindowRecord(A5),A0
	move.w	nw_Height(A0),D0
	move.l	D0,-(sp)
	move.w	nw_Width(A0),D0
	move.l	D0,-(sp)
	move.w	nw_TopEdge(A0),D0
	move.l	D0,-(sp)
	move.w	(A0),D0			; LeftEdge
	move.l	D0,-(sp)
	pea	_ErrorOpenWindowTxt(pc)
	bsr.w	_FmtDisplay
	lea	20(sp),sp		; Restore stack
	moveq	#0,D0
	rts

*******************************************
*
* Close the main window.
* If a font was opened for this window,
* the system-default font is first set
* to the window (restored), then the opened
* font is closed and after that, the window
* is closed.
*
* Inputs: None
* Results: None
*

_CloseWindow
	tst.l	_UserFontPtr(A5)
	beq.s	1$
	movea.l	_GfxBase(A5),A6

	movea.l	_WindowPtr(A5),A1
	move.l	wd_RPort(A1),A1
	movea.l	_OldFontPtr(A5),A0
	jsr	_LVOSetFont(A6)

	movea.l	_UserFontPtr(A5),A1
	jsr	_LVOCloseFont(A6)

1$
	movea.l	_IntuitionBase(A5),A6
	movea.l	_WindowPtr(A5),A0
	jmp	_LVOCloseWindow(A6)

*************************************
*
* Short subroutine to set window's name
* pc-relative.
*
* Inputs: None
* Results: None
*

_SetPrefs
	lea	_WindowRecord(A5),A0
	lea	_WindowName(pc),A1
	move.l	A1,nw_Title(A0)
	rts

*****************************************
*
* Main routine calls this one.
* This one will jump to the routine which
* belongs to the key.
*
* Inputs: A0 - "_ConBuffer"
*              Key in "_ConBuffer"
* Results: None
* Notes: Never call it via "bsr" or "jsr"!
*

_ConsoleEvent
	cmpi.w	#L_Key,(A0)
	beq.w	_LoadNew
	cmpi.w	#E_Key,(A0)
	beq.w	_EnlargeWindow
	cmpi.w	#H_Key,(A0)
	beq.w	_DisplayHelp
	cmpi.w	#I_Key,(A0)
	beq.w	_Info
	cmpi.w	#A_Key,(A0)
	beq.w	_About
	tst.l	_TextPtr(A5)
	beq.w	_Loop
	move.w	(A0),D0
	cmpi.b	#CRSR_UP,D0
	beq.w	_PageUp
	cmpi.b	#CRSR_DN,D0
	beq.w	_PageDown
	cmpi.b	#CRSR_FD,D0
	beq.w	_OneLineUp
	cmpi.b	#CRSR_BK,D0
	beq.w	_OneLineDown
	cmpi.b	#T_Key,D0
	beq.w	_Top
	cmpi.b	#B_Key,D0
	beq.w	_Bottom
	cmpi.b	#RETURN,D0
	beq.w	_OneLineDown
	cmpi.b	#ENTER,D0
	beq.w	_OneLineDown
	cmpi.b	#HOME,D0
	beq.w	_Top
	cmpi.b	#END,D0
	beq.w	_Bottom
	cmpi.b	#PG_UP,D0
	beq.w	_PageUp_01
	cmpi.b	#PG_DN,D0
	beq.w	_PageDown_01
	cmpi.b	#R_SHIFT,D0
	beq.w	_OneLineUp
	cmpi.b	#W_Key,D0
	beq.w	_WindowContentsPrt
	cmpi.b	#PrtSc,D0
	beq.w	_WindowContentsPrt
	cmpi.b	#C_Key,D0
	beq.w	_WindowContensFile
	cmpi.b	#P_Key,D0
	beq.w	_Print2Prt
	cmpi.b	#F_Key,D0
	beq.s	_Print2File
	cmpi.b	#R_Key,D0
	beq.w	_RestorePage
	cmpi.w	#S_Key,D0
	beq.w	_SearchSequence
	cmpi.w	#N_Key,D0
	beq.w	_ContinueSearch
	cmpi.b	#HELP_Key,D0
	bsr.s	_DisplayTitle
	bra.w	_Loop

**************************************************
*
* Allow counting lines and create new window-title.
*
* Inputs: none
* Results: none
*

_DisplayTitle
	clr.b	_NoLineFlag(A5)		; Allow to count lines
	bsr.w	_ComLine		; Create (modify) window-title
	rts

**************************************
*
* Set prefs to display the ascii-text,
* set up registers.
*
* Inputs: none
* Results: A3 - textstart, A2 - textend
*

_SetViewerPrefs
	movea.l	_TextPtr(A5),A4		; Current text-position
	addq.l	#2,A4			; Overread #$200A
	movea.l	A4,A3			; Textstart A3
	movea.l	A4,A2			;     ^	    A2
	move.l	_FileSize(A5),D0	; Length file
	add.l	D0,A2			; = textend
	addq.l	#3,A2			; + #$0200A + 1 byte behind source
	move.b	#10,(A2)		; = textend
	move.l	A3,D5
	move.l	A3,D6
	rts

*************************************
*
* Print that ascii-text-file to file.
*
* Inputs: none
* Reslts: none
*

_Print2File
	clr.b	_LoadFlag(A5)		; Set save-flag
	tst.b	_ReqFlag(A5)
	bne.s	1$			; Requester already opened?
	bsr.w	OpenReq			; No...
1$
	bsr.w	_GetFile		; Get filename
	cmpi.l	#-1,D0			; Hard error?
	beq.w	_CantPrint		; If so...
	tst.l	D0			; No file?
	bne.s	_PrintFileTO		; If so...
	bra.w	_Loop			; ...and back

*
** Ok, do further...
*
_PrintFileTO
	lea	_PrintFileTxt(pc),A0
	bsr.w	_DisplayError
	tst.l	D0			; User cancelled?
	beq.s	_DoNotPrint		; ..then do not write down the file

	lea	_FileName(A5),A0
	movea.l	A3,A1			; Textstart
	move.l	_FileSize(A5),D0	; Length file
	bsr.w	_PrintFile		; Write down the file
	bra.w	_Loop			; ...and end

***************************************
*
* Write down window contents to a file.
*
* Inputs: none
* Reslts: none
*

_WindowContensFile
	clr.b	_LoadFlag(A5)		; Indicate loading
	tst.b	_ReqFlag(A5)
	bne.s	1$			; Requester already opened?
	bsr.w	OpenReq			; No...
1$
	bsr.w	_GetFile		; Get filename
	cmpi.l	#-1,D0			; Hard error?
	beq.s	_CantPrint		; If so...
	tst.l	D0			; No file?
	bne.s	_PrintFileTO_01		; If so...
	bra.w	_Loop

*
** Further....
*
_PrintFileTO_01
	lea	_PrintContentsTxt(pc),A0
	bsr.w	_DisplayError
	tst.l	D0			; Right mosebutton?
	beq.s	_DoNotPrint		; Then do not write
	movea.l	D6,A1			; Current address (current line D6)
	movea.l	A1,A0
	move.w	_PageSize(A5),D1	; Number of lines of one page
	addq.w	#2,D1			; plus one line and one for linefeed
	moveq	#0,D0			; Counter
1$
	cmpa.l	A2,A0			; Textend == current textposition?
	bge.s	2$			; If so, error
	addq.w	#1,D0
	cmpi.b	#10,(A0)+		; Search for linefeed
	bne.s	1$
	dbf	D1,1$			; Lines of one page
2$
	lea	_FileName(A5),A0	; The filename
	bsr.w	_PrintFile		; Write down file
	bra.w	_Loop			; back to main

*******************************
*
* Print window contents to PRT:
*
* Inputs: none
* Reslts: none
*

_WindowContentsPrt
	lea	_FileName(A5),A0
	move.l	#'PRT:',(A0)+
	clr.b	(A0)
	bsr.s	_CheckPrinter		; Check if printer is turned off or so...
	bra.s	_PrintFileTO_01

*
** Error handling....
*
_DoNotPrint
	lea	_PrintCancelTxt(pc),A0
	bsr.w	_DisplayError
	bra.w	_Loop
_CantPrint
	bra.w	_End	

**************************
*
* Print whole file to PRT:
*
* Inputs: none
* Reslts: none
*

_Print2Prt
	lea	_FileName(A5),A0
	move.l	#'PRT:',(A0)+
	clr.b	(A0)
	bsr.s	_CheckPrinter
	bra.w	_PrintFileTO	

****************************************
*
* Check printer: uses direct CIA-access.
* Works only 100% correctly with Epson-
* printers.
*
* Inputs: none
* Reslts: none
* Notes: Checking can be disabled
*

_CheckPrinter
	tst.b	_NoCheckPrtFlag(A5)	; Allowed to check?
	bne.s	1$
	move.b	$BFD000,D0		; CIA PRA
	cmpi.b	#255,D0
	beq.s	.PrinterOFF
	cmpi.b	#253,D0
	beq.s	.NotOneLine
	cmpi.b	#255,D0
	bne.s	.PrinterOFF
1$
	rts
.PrinterOFF
	lea	_PrinterOFFTxt(pc),A0
	bsr.w	_DisplayError
	addq.l	#4,sp
	bra.w	_Loop
.NotOneLine
	lea	_NotOnelineTxt(pc),A0
	bsr.w	_DisplayError
	addq.l	#4,sp
	bra.w	_Loop

*********************
*
* How to explain....?
*

_PageUp
	move.w	_PageSize(A5),D7	; ditto
	bra.w	_LinesUp
_PageUp_01
	move.w	_StdPageSize(A5),D7	; Set scrollwidth
	addq.w	#1,D7			; We can display one line more
	bra.w	_OnePageUp
_PageDown
	move.w	_PageSize(A5),D7	; see above
	bra.w	_LinesDown
_PageDown_01
	move.w	_StdPageSize(A5),D7	; see above
	addq.w	#1,D7			; We can display one line more
	bra.w	_OnePageDown
_OneLineUp
	moveq	#0,D7			; 1 line!
	bra.w	_LinesUp
_OneLineDown
	moveq	#0,D7			; ditto
	bra.w	_LinesDown
_RestorePage
	bsr.w	_SetPageWidthAndLen
_RestorePage_1
	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

****************************************************
*
* Load from Shell overgiven file and set scrollwidth.
*
* Inputs: none
* Reslts: none
*

_CLILoad
	tst.l	arg_2(A5)		; 2. argument empty?
	beq.s	1$			; If so...
	movea.l	arg_2(A5),A0

*
** Convert chars of second argument to uppercase.
** 2. argument should look like this: 1> viewer <textfile> scrollwidth=11
**							   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
2$
	tst.b	(A0)
	beq.s	4$
	cmpi.b	#'@',(A0)
	bls.s	3$
	cmpi.b	#'z',(A0)
	bhi.s	3$
	bclr	#5,(A0)
3$
	addq.l	#1,A0
	bra.s	2$
4$
	lea	arg_2(A5),A0
	clr.l	4(A0)			; Clear next argument
	bsr.w	_SetScrollWidth_01	; Get scrollwidth
1$
	movea.l	arg_1(A5),A0		; Address 1. argument (filename)
	lea	_FileName(A5),A1	; Address buffer for filename
_StoreArgName
	move.b	(A0)+,(A1)+		; Copy argument
	tst.b	-1(A0)
	bne.s	_StoreArgName	
	bra.s	_ReadIn

*******************************************
*
* Startup to load workbench overgiven file.
*
* Inputs: none
* Results: none
*

_WBLoad
	tst.l	lock_1(A5)		; Lock to dir?
	beq.s	1$			; No...
	move.l	lock_1(A5),D1
	movea.l	_DOSBase(A5),A6
	jsr	_LVOCurrentDir(A6)	; else set as current directory
1$
	tst.l	file_1(A5)
	beq.w	_InitRequester

	movea.l	file_1(A5),A0		; Address name from file
	lea	_FileName(A5),A1
	bra.s	_StoreArgName

*****************************************
*
* Build requester, check file, read file.
*
* Inputs: none
* Results: none
*

_LoadNew
	st.b	_LoadFlag(A5)		; Flag == load
	tst.b	_ReqFlag(A5)
	bne.s	1$			; Requester already opened?
	bsr.w	OpenReq			; No...
1$
	bsr.w	_GetFile		; Get filename
	tst.l	D0
	bmi.w	_End_1			; Hard error?
	tst.l	D0
	beq.w	_Loop			; No file?
_ReadIn
	bsr.w	_FreeAudio

	bsr.w	_ReadFile		; Read file in
	tst.l	D0			; Error?
	beq.w	_Loop			; If so...

	bsr.w	_ClearWindow		; Erase window contents

	bsr.w	_CheckFile		; Check if ASCII, PP-crunched or IFF-screen

	bsr.w	_IgnoreSettings		; ANSI-filter

*	bsr.w	_SetViewerPrefs		; Set up ascii-file to display

	bra.w	_FirstPage		; Display first page

*********************************************
*
* Display first page of ascii-text in window.
*
* Inputs: none
* Results: none
*

_Top
	bra.w	_FirstPage		; Display first page

*********************************************
*
* Display last page of ascii-text in window.
*
* Inputs: none
* Results: none
*

_Bottom
	bra.w	_LastPage

**********************************************
*
* Page up - clear window and write down string
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         D7 == Number of lines to scroll (display)
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_OnePageUp
	movea.l	D6,A4
	movea.l	A4,A0
	subq.l	#4,A0			; Any chars to display?
	cmpa.l	A3,A0
	bls.w	_Loop			; If not...

	bsr.w	_ClearWindow

	moveq	#0,D2			; Number of chars!
0$
	cmpa.l	A3,A4			; A3 == lowest address, A4 == current address, does it fit?
	bls.s	6$			; If not...

1$
	moveq	#0,D0			; Counter for number of chars
2$
	addq.w	#1,D0			; Else counter for number of chars plus 1
	subq.l	#1,A4
	cmpi.b	#10,(A4)		; Next line?
	bne.s	2$
	add.w	D0,D2
3$	
	tst.b	_NoLineFlag(A5)		; Counting lines allowed?
	bne.s	4$			; No...
	subq.l	#1,_Line(A5)
4$
	move.l	A4,D6			; Remember startaddress of string in D6 as next pointer
*					  for LinesUp-routine
	movea.l	D5,A0			; Address last char in window
5$
	cmpi.b	#10,-(A0)		; Find LineFeed
	bne.s	5$
	move.l	A0,D5			; New address last char in window

	dbf	D7,0$

	move.l	D2,-(sp)
	lea	_ConBuffer(A5),A0	; Address buffer
	move.w	#$9B48,(A0)		; Cursor Home
	moveq	#2,D0			; 2 chars for output
	bsr.w	_ConOut_Rel		; Output
	move.l	(sp)+,D0

	movea.l	A4,A0
	addq.l	#1,A0
	subq.w	#1,D0
	bsr.w	_ConOut_Reloc		; Print down those lines

	bra.w	_Loop

6$
	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

***********************************************
*
* Number of lines to scroll up....
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         D7 == Number of lines to scroll (display)
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_LinesUp
	movea.l	D6,A4			; Last address from LinesDown as current address for us
0$
	cmpa.l	A3,A4			; A3 == lowest address, A4 == current address, does it fit?
	bls.w	_Loop			; If not...

	lea	_ConBuffer(A5),A0	; Address buffer
	move.w	#$9B48,(A0)+		; Cursor Home
	move.l	#$9B314100,(A0)		; Scroll 1 line up
	moveq	#5,D0			; 5 chars for output
	bsr.w	_ConOut_Rel		; Output
1$
	moveq	#0,D0			; Counter for number of chars
2$
	addq.w	#1,D0			; Else counter for number of chars plus 1
	subq.l	#1,A4
	cmpi.b	#10,(A4)
	bne.s	2$
3$	
	tst.b	_NoLineFlag(A5)		; Counting lines allowed?
	bne.s	4$			; No...
	subq.l	#1,_Line(A5)
4$
	movea.l	A4,A0
	addq.l	#1,A0
	subq.w	#1,D0
	bsr.w	_ConOut_Reloc		; Print down the line

	move.l	A4,D6			; Remember startaddress of string in D6 as next pointer
*					  for LinesUp-routine
	movea.l	D5,A0			; Address last char in window
5$
	cmpi.b	#10,-(A0)		; Find LineFeed
	bne.s	5$
	move.l	A0,D5			; New address last char in window

	dbf	D7,0$

	bra.w	_Loop

*******************************************************************
*
* Scroll down one complete page an write to freed room the strings.
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         D7 == Number of lines to scroll (display)
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_OnePageDown
	movea.l	D5,A4			; Last address char in window
	movea.l	A4,A0
	addq.l	#2,A0			; At least a few bytes to display?
	cmpa.l	A2,A0			; Does it fit?
	bge.w	_Loop

	bsr.w	_ClearWindow
	addq.l	#1,A4			; Ignore introducing LineFeed

	lea	_ConBuffer(A5),A0
	move.w	#$9B48,(A0)
	moveq	#2,D0
	bsr.w	_ConOut_Rel

	bra.s	_Lines_Down

**************************************************************
*
* Scroll down and print contents, number of lines: ScrollWidth.
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         D7 == Number of lines to scroll (display)
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_LinesDown
	movea.l	D5,A4			; Last address char in window
	cmpa.l	A2,A4			; Does it fit?
	bge.w	_Loop

	lea	_ConBuffer(A5),A0
	move.l	#$9B393939,(A0)+	; Cursor End of Display
	move.b	#$48,(A0)		; <CSI>999H
	moveq	#5,D0
	bsr.w	_ConOut_Rel

_Lines_Down
	movea.l	A4,A0
	moveq	#0,D0			; Counter for number of chars
1$
	cmpa.l	A2,A4			; A2 == highest address, A4 == current
	bge.w	_Loop

	addq.w	#1,D0			; Counter for chars plus 1
	addq.l	#1,A4
	cmpi.b	#10,(A4)		; LineFeed?
	bne.s	1$			; If not, do it further
	bsr.w	_ConOut_Reloc		; Print down one line

	move.l	A4,D5			; Last char address in window
	movea.l	D6,A0			; First char in window
2$
	addq.l	#1,A0
	cmpi.b	#10,(A0)		; LineFeed (next line)?
	bne.s	2$
	move.l	A0,D6			; New address (first char in window)

	tst.b	_NoLineFlag(A5)		; Allowed to count lines?
	bne.s	3$			; No...
	addq.l	#1,_Line(A5)
3$
	dbf	D7,_Lines_Down		; Number of lines

	bra.w	_Loop	

*********************************
*
* Restore current window contents
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_RestoreCurrentPage
	tst.l	_BufferSize(A5)		; Any datas to display out there?
	beq.s	2$			; If not...

	move.l	D6,D5			; Last address == current
	addq.l	#1,D5			; Ignore introducing linefeed

	move.w	_StdPageSize(A5),D7
	addq.w	#1,D7

	movea.l	D5,A4			; Last address char in window
	cmpa.l	A2,A4			; Does it fit?
	bge.s	2$

	lea	_ConBuffer(A5),A0	; Address buffer
	move.l	#$1B5B306D,(A0)+	; Reset display
	move.l	#$9B639B48,(A0)+	; Reset console and Cursor Home
	move.l	#$9B4A9B48,(A0)		; Erase to end of display Cursor Home
	moveq	#12,D0			; 12 chars for output
	bsr.w	_ConOut_Rel		; Output

0$
	movea.l	A4,A0
	moveq	#0,D0			; Counter for number of chars
1$
	cmpa.l	A2,A4			; A2 == highest address, A4 == current
	bge.s	2$

	addq.w	#1,D0			; Counter for chars plus 1
	addq.l	#1,A4
	cmpi.b	#10,(A4)		; LineFeed?
	bne.s	1$			; If not, do it further
	bsr.w	_ConOut_Reloc		; Print down one line

	move.l	A4,D5			; Last char address in window
	dbf	D7,0$			; Number of lines
2$
	rts

***************************************
*
* Display first page of ascii-text-file
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_FirstPage
	bsr.w	_SetViewerPrefs		; Prefs == as on start!

	moveq	#0,D7
	move.w	_StdPageSize(A5),D7
	addq.w	#1,D7
	move.l	D7,_Line(A5)		; == number of lines that "are" displayed"!?"

	movea.l	D5,A4			; Last address char in window
	cmpa.l	A2,A4			; Does it fit?
	bge.w	_Loop

	lea	_ConBuffer(A5),A0	; Address buffer
	move.l	#$1B5B306D,(A0)+	; Reset display
	move.l	#$9B639B48,(A0)+	; Reset and Cursor Home
	move.l	#$9B4A9B48,(A0)		; Erase to end of display + Cursor Home
	moveq	#12,D0			; 12 chars for output
	bsr.w	_ConOut_Rel		; Output
0$
	movea.l	A4,A0
	moveq	#0,D0			; Counter for number of chars
1$
	cmpa.l	A2,A4			; A2 == highest address, A4 == current
	bge.w	_Loop

	addq.w	#1,D0			; Counter for chars plus 1
	addq.l	#1,A4
	cmpi.b	#10,(A4)		; LineFeed?
	bne.s	1$			; If not, do it further
	bsr.w	_ConOut_Reloc		; Print down one line

	move.l	A4,D5			; Last char's address in window
	dbf	D7,0$			; Number of lines

	bra.w	_Loop	

**************************************
*
* Display last page of ascii-text-file
*
* Inputs: D5 == Address of last char in window (or NULL)
*         D6 == Address of 1. char in window
*         A2 == Address last char of text
*         A3 == Address first char of text
*         A4 == used
* Results:
*	  D5 == Address of last char in window
*         D6 == Address of 1. char in window
*

_LastPage
	move.l	A2,D5			; Highest address as current for LinesDown
	move.l	D5,D6			; Highest address as current for us!

	lea	_ConBuffer(A5),A0	; Address buffer
	move.l	#$1B5B306D,(A0)+	; Reset display
	move.l	#$9B639B48,(A0)+	; Reset console and Cursor Home
	move.w	#$9B4A,(A0)		; Erase to end of display + Cursor Home
	moveq	#10,D0			; 10 chars for output
	bsr.w	_ConOut_Rel		; Output

	move.w	_StdPageSize(A5),D7	; Number of scrolls
	addq.w	#1,D7			; Plus 1

	movea.l	D6,A4
0$
	cmpa.l	A3,A4			; A3 == lowest address, A4 == current address, does it fit?
	bls.w	_Loop			; If not...

	lea	_ConBuffer(A5),A0	; Address buffer
	move.w	#$9B48,(A0)+		; Cursor Home
	move.l	#$9B314100,(A0)		; Scroll 1 line up
	moveq	#5,D0			; 5 chars for output
	bsr.w	_ConOut_Rel		; Output
1$
	moveq	#0,D0			; Counter for number of chars
2$
	addq.w	#1,D0			; Counter for number of chars plus 1
	subq.l	#1,A4			; Next char
	cmpi.b	#10,(A4)		; Next line?
	bne.s	2$

	movea.l	A4,A0
	addq.l	#1,A0
	subq.w	#1,D0
	bsr.w	_ConOut_Reloc		; Print down the line

	move.l	A4,D6			; Remember startaddress of string in D6 as next pointer
*					  for LinesUp-routine
	dbf	D7,0$

	move.l	_LinesInFile(A5),D0	; How many lines in file?
	addq.l	#1,D0
	move.l	D0,_Line(A5)		; = lines

	bra.w	_Loop

************************
*
* Make cursor invisible.
*
* Inputs: none
* Results: none
*

_CursorOff
	clr.l	-(sp)
	movea.l	sp,A0
	move.b	#$9B,(A0)
	move.b	#'0',1(A0)
	move.b	#' ',2(A0)
	move.b	#'p',3(A0)
	moveq	#4,D0
	bsr.w	_ConOut_Reloc		; Output
	addq.l	#4,sp
	rts

_CursorOn
	clr.l	-(sp)
	movea.l	sp,A0
	move.b	#$9B,(A0)
	move.b	#' ',1(A0)
	move.b	#'p',2(A0)
	moveq	#3,D0
	bsr.w	_ConOut_Reloc		; Output
	addq.l	#4,sp
	rts

****************************************************************
*
* Twist pointer for system-requester so that system-requesters
* which mean us, will appear on our window; must be done because
* any other screen as the Workbench's one can be used by Viewer.
*
* Inputs: none
* Results: none
*

_SetPtr4Req
	movea.l	_OwnTask(A5),A0
	move.l	pr_WindowPtr(A0),_StdprWindowPtr(A5)	; Save default pointer
	move.l	_WindowPtr(A5),pr_WindowPtr(A0)		; Twist
	rts

***********************************************
*
* Find in tooltypes a string which tells us to make a
* word warp when the contents of one line do not fit
* in one line (window limits)
*
* Inputs: none
* Results: none
*

_CheckWrap
	lea	WB_arg_1(A5),A0
1$
	tst.l	(A0)			; Any argument?
	beq.s	4$

	movea.l	(A0)+,A1
	lea	_WrapDef(pc),A2		; String to compare
	moveq	#7,D0
2$
	cmpm.b	(A1)+,(A2)+
	bne.s	1$
	dbf	D0,2$
	st.b	_WrapFlag(A5)		; Set flag
4$
	rts

*************************************************
*
* Get window limits out of tooltypes,
* (EXTENTWINDOW=<width>,<height>)
*
* Inputs: (GetNextArg() - pointer to string in A0
* Results: none
*

_SetWindow				; Only if WB-start!!!
	lea	WB_arg_1(A5),A0
_GetNextArg				; this one for the Shell
1$
	tst.l	(A0)			; Argument there?
	beq.s	.EndSetWindow		; No
	movea.l	(A0)+,A1		; Address overgiven string
	lea	_WindowDef(pc),A2	; Address string to compare
	moveq	#12,D0			; 13 chars to compare
3$
	cmpm.b	(A1)+,(A2)+		; Compare strings
	bne.s	1$			; "EXTENTWINDOW="
	dbf	D0,3$

	moveq	#0,D0			; Fill up (no mask)
	movea.l	A1,A0			; A0 string (contains value)
	bsr.w	_StrToLong
	tst.l	D1			; Error?
	bmi.s	.EndSetWindow

.SetWidth
	lea	_WindowRecord(A5),A3	; Address window-record
	move.w	D0,nw_Width(A3)		; Set width

	moveq	#0,D0			; No mask
* String to convert already in A0
	bsr.w	_StrToLong
	tst.l	D1
	bmi.s	.EndSetWindow

.SetHeight
	lea	_WindowRecord(A5),A3	; Window-record
	move.w	D0,nw_Height(A3)	; Set height

.EndSetWindow
	rts

*********************************************************
*
* Set scrollwidth, user has to specify it on his own,
* tooltyes or Shell.
*
* Inputs: (SetScrollWidth_01() - only Shell: A0 - string)
* Results: none
*

_SetScrollWidth				; Only available from Workbench
	lea	WB_arg_1(A5),A0		; Address constant of 1. argument
_SetScrollWidth_01			; Jumpmark for Shell use
	tst.l	(A0)			; Address 1. argument there?
	beq.s	1$

	movea.l	(A0)+,A1		; Out of it address 1. argument
	lea	_PageDef(pc),A2
	moveq	#11,D0			; 12 loops
2$
	cmpm.b	(A1)+,(A2)+		; Compare char for char
	bne.s	_SetScrollWidth_01	; "SCROLLWIDTH="
	dbf	D0,2$

	moveq	#0,D0			; No mask
	movea.l	A1,A0			; Text into A0	
	bsr.w	_StrToLong		; Get value
	cmpi.l	#-1,D1			; On error
	beq.s	1$
	subq.w	#1,D0			; Because scrolling can be done once more!
	move.w	D0,_PageSize(A5)	; Set length to scroll
	st.b	_PageSizeFlag(A5)	; Set flag
1$
	rts

****************************************************
*
* Get from and only! from Workbench overgiven file,
* may be specified in the defaulttool of the project-
* icon of a file.
*
* Inputs: none
* Results: none
*

_SetDirection
	tst.l	_argc(A5)		; Any argument?
	beq.s	2$			; If not...

	move.l	lock_1(A5),D1		; Get the lock to the file
	beq.s	3$
	movea.l	_DOSBase(A5),A6
	jsr	_LVOCurrentDir(A6)	; Change current directory to project's one
3$
	tst.l	file_1(A5)		; No file?
	beq.s	2$

	movea.l	file_1(A5),A0		; Name of file
	tst.l	_IconBase(A5)
	beq.s	2$
	movea.l	_IconBase(A5),A6
	jsr	_LVOGetDiskObject(A6)	; Load ".info"-file
	move.l	D0,_UserProject(A5)	; Save its handle
	movea.l	D0,A0			; Pointer to entries A0
	tst.l	D0
	beq.s	2$			; Upon error

	movea.l	do_ToolTypes(A0),A0	; Get those tooltype-pointer
	move.l	A0,_ToolTypesArray(A5)

	moveq	#14,D0			; Allow 15 entries to be stored
	lea	WB_arg_1(A5),A1		; Address for 1. argument
1$
	move.l	(A0)+,(A1)+		; Save these pointers
	beq.s	2$			; Last pointer?
	dbf	D0,1$			; No...
2$
	rts

*************************************************
*
* Get page width and length in lines. Do it via a
* console status report.
*
* Maximums for now:
* 999 lines and 999 columns.
* The console will report if we set the limits to
* 999 the maximum which is displayable, e.g.
* <CSI>20;78R - mean 20 lines and 78 columns.
*
* Inputs: none
* Results: none
*

_SetPageWidthAndLen
	movem.l	D0-D7/A0-A6,-(sp)
.GetConReport
	lea	_ConBuffer(A5),A0
	move.l	#$9B39393B,(A0)+	; Move Cursor <CSI>99; [ NOTEZ-BIEN: We cannot use 999
*					  here - due to the below menitioned bug! ]
	move.l	#$39393948,(A0)+	; 999H - here it works...
	moveq	#8,D0
	bsr.w	_ConOut_Rel

	lea	_ConBuffer(A5),A0
	move.l	#$9B393939,(A0)+	; Because of a bug in the con-routines
	move.b	#'B',(A0)		; we have to set the cursor as single CSI
	moveq	#5,D0			; to end of the display (<CSI>999B
	bsr.w	_ConOut_Rel

	lea	_ConBuffer(A5),A0
	move.l	#$9B366E00,(A0)+	; Console Device Status Report
*					  <CSI>6n
	moveq	#3,D0			; 3 chars
	bsr.w	_ConOut_Rel		; Output
	lea	_ConBuffer(A5),A0
	moveq	#20,D0
.ClearIt
	clr.b	(A0)+
	dbf	D0,.ClearIt
1$
	bsr.w	_GetConMsg		; Get the message from the console-device
	tst.l	D0			; Message?
	beq.s	1$
	movea.l	D0,A1
	jsr	_LVOReplyMsg(A6)

	lea	_ConBuffer(A5),A0
	addq.l	#1,A0
	move.l	A0,D2
	move.l	_stdout(A5),D1
	beq.s	8$
	moveq	#7,D3
	movea.l	_DOSBase(A5),A6		; Print message to Shell-window
	jsr	_LVOWrite(A6)
8$

	lea	_ConBuffer(A5),A0
	addq.l	#1,A0			; Overread CSI

	moveq	#0,D0			; No mask
	bsr.w	_StrToLong		; Get value
	cmpi.l	#-1,D1			; Error ?
	bne.s	2$
	cmpi.b	#';',-1(A0)		; Last char the semicolon?
	beq.s	2$			; If so, it is ok
	bra.w	.GetConReport		; Upon error
2$
	subq.w	#2,D0			; Minus 2 = scrollwidth
	move.w	D0,_StdPageSize(A5)	; Standard scrollwidth
	tst.b	_PageSizeFlag(A5)	; Already defined (ToolTypes)?
	bne.s	3$			; If so...
	move.w	D0,_PageSize(A5)	; Else save it
3$
*
** Get count which stays after the semicolon
** (returned by the status-report)
*
	moveq	#0,D0			; No mask
	bsr.w	_StrToLong		; Get value
	cmpi.l	#-1,D1			; Error ?
	bne.s	4$
	cmpi.b	#'R',-1(A0)		; Last char the 'R'?
	beq.s	4$			; If so, it is ok
	bra.w	.GetConReport		; Else get new
4$
	subq.w	#1,D0
	move.l	D0,_PageWidth(A5)	; Set max. length

	lea	_IOInlineBuf(A5),A0
	move.b	#10,(A0)+
	move.l	_PageWidth(A5),D0	
	bsr.w	_comdec
	move.b	#10,(A0)+
	clr.b	(A0)
	lea	_IOInlineBuf(A5),A0
	move.l	_stdout(A5),D1
	beq.s	6$
	move.l	A0,D2
	moveq	#-1,D3
7$
	tst.b	(A0)+
	dbeq	D3,7$
	not.l	D3
	movea.l	_DOSBase(A5),A6
	jsr	_LVOWrite(A6)		; Print down settings to Shell-window
6$
	movem.l	(sp)+,D0-D7/A0-A6
5$
	rts

********************************************************************
*
* Open and init a filerequester, only Arp and ReqTools supported yet.
*
*
* Inputs: none
* Results: Gloabal Flag ("_ReqFlag), indicates which requester is used,
*                  1 ReqTools
*                  2 Arp
*                 -1 failed to open (hard error)
*

OpenReq
	tst.l	_ReqPtr(A5)
	bne.s	1$
	movea.l	_SysBase(A5),A6
	moveq	#37,D0
	lea	_ReqToolsName(pc),A1
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_ReqToolsBase(A5)
	beq.s	_ArpReq			; If it failed...
	movea.l	_ReqToolsBase(A5),A6	; else
	moveq	#0,D0			; Must be NULL for the moment
	suba.l	A0,A0			; (Tags) ditto
	jsr	_LVOrtAllocRequestA(A6)	; Allocate structure
	move.l	D0,_ReqPtr(A5)
	beq.s	.noReqToolsReq		; Upon error
1$
	move.b	#1,_ReqFlag(A5)		; Say: ok reqtools
	rts
.noReqToolsReq
	movea.l	A6,A1
	movea.l	_SysBase(A5),A6
	jsr	_LVOCloseLibrary(A6)
	clr.l	_ReqToolsBase(A5)	; Important!!!

_ArpReq
	tst.l	_ArpBase(A5)
	bne.s	2$
	movea.l	_SysBase(A5),A6
	moveq	#39,D0
	lea	_ArpName(pc),A1
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_ArpBase(A5)
	beq.s	.NoArp			; Hard error, failed to open any requester!
	bsr.s	_InitReq		; Init Arp-structure
2$
	move.b	#2,_ReqFlag(A5)		; Flag for Ok Arp
	rts

.NoArp
	move.b	#-1,_ReqFlag(A5)	; Say: damned, failed to open
	rts

**********************************
*
* Display ReqTools file-requester.
*
* Inputs: none
* Results: none
*

_ReqLoad
	movem.l	A2-A3,-(sp)
	suba.l	A0,A0			; TAG-list
	movea.l	_ReqPtr(A5),A1		; ReqTools-structure
	lea	_File(A5),A2		; Buffer for filename
	tst.b	_LoadFlag(A5)		; Shall we load?
	bne.s	3$			; No, save!
	lea	_SaveTitle(pc),A3	; Save-string (title-text)
	bra.s	2$
3$
	lea	_AWTitle(pc),A3		; Window-title == load
2$
	movea.l	_ReqToolsBase(A5),A6
	jsr	_LVOrtFileRequestA(A6)
	tst.l	D0
	beq.s	4$			; No file was chosen!
	lea	_Drive(A5),A1		; Address buffer for directory
	movea.l	_ReqPtr(A5),A0		; Address Requester-structure
	movea.l	16(A0),A0		; rtfi_Dir(A0),A0! - pointer to directory
1$
	move.b	(A0)+,(A1)+		; Copy drive-name
	tst.b	-1(A0)			; Copy also NULL-byte
	bne.s	1$
	moveq	#1,D0			; Signal ok
4$
	movem.l	(sp)+,A2-A3
	rts

************************************
*
* Initialize Arp-requester structure.
*
* Inputs: none
* Results: none
*

_InitReq
	lea	_ArpReqStruc(A5),A0	; Address structure
	lea	_AWTitle(pc),A1		; Address title for requester
	move.l	A1,(A0)
	lea	_File(A5),A1		; Address buffer for name
	move.l	A1,4(A0)
	lea	_Drive(A5),A1		; Address buffer for directory
	move.l	A1,8(A0)
	move.b	#':',_Drive(A5)		; Say current directory
	rts

*****************************
*
* Display Arp-file-requester.
*
* Inputs: none
* Results: none
*

_ArpLoad
	movem.l	D2-D7/A2-A6,-(sp)	; <-I don't trust Arp
	lea	_ArpReqStruc(A5),A0	; Address structure
	tst.b	_LoadFlag(A5)		; Shall we load a file?
	bne.s	1$			; Yes...
	lea	_SaveTitle(pc),A1	; Otherwise set saving-title
	move.l	A1,(A0)
	bra.s	2$
1$
	lea	_AWTitle(pc),A1		; Title (Load)
	move.l	A1,(A0)
2$
	movea.l	_ArpBase(A5),A6
	lea	_ArpReqStruc(A5),A0	; Structure of requester
	jsr	_LVOArpFileRequest(A6)
	movem.l	(sp)+,D2-D7/A2-A6
	rts

***************************************************
*
* Merge volume's/directory's name with file's name.
*
* Inputs: none
* Results: none
*

_GetFileName
	move.l	A2,-(sp)
	lea	_Drive(A5),A0
	lea	_File(A5),A1
	lea	_FileName(A5),A2
1$
	tst.b	(A0)
	beq.s	2$
	move.b	(A0)+,(A2)+
	bra.s	1$
2$
	tst.b	-1(A0)
	beq.s	3$
	cmpi.b	#':',-1(A0)
	beq.s	3$
	cmpi.b	#'/',-1(A0)
	beq.s	3$
	move.b	#'/',(A2)+
3$
	move.b	(A1)+,(A2)+
	tst.b	-1(A1)
	bne.s	3$
	movea.l	(sp)+,A2
	rts

***********************************
*
* Startup to display filerequester.
*
* Inputs: none
* Results: D0 == NULL upon error
*

*------------------------------------------------------
_GetFile
	cmpi.b	#-1,_ReqFlag(A5)	; No requester at all?
	beq.s	.NoReqAtAll
	cmpi.b	#1,_ReqFlag(A5)		; ReqTools-Load-routine?
	bne.s	.ArpMustLoad		; No, Arp
	bsr.w	_ReqLoad		; else ReqTools-file-requester
	tst.l	D0			; Ok?
	beq.s	.NoFileGet		; No, no file selected!
	bsr.s	_GetFileName		; Combinate filename in dos-convention
	moveq	#$11,D0			; Return ok
	rts

.ArpMustLoad
	bsr.w	_ArpLoad		; Arp-file-requester
	tst.l	D0			; No file?
	beq.s	.NoFileGet
	bsr.s	_GetFileName		; Combinate filename in dos-convention
	moveq	#$11,D0			; Return ok.
	rts
.NoReqAtAll
	moveq	#-1,D0			; Damned, no requester at all!
	rts
.NoFileGet				; No file was selected
	rts

***************************************************************
*
* Complex routine which loads a file, sets up needed parameters.
*
* Inputs: none
* Results: D0 - NULL upon error
*

_ReadFile
	movea.l	_SysBase(A5),A6
	movea.l	_TextPtr(A5),A1
	move.l	_BufferSize(A5),D0
	beq.s	1$
	jsr	_LVOFreeMem(A6)		; Free last pointed text
	clr.l	_BufferSize(A5)
	clr.l	_TextPtr(A5)
	clr.l	_Line(A5)
	clr.l	_SearchStrPtr(A5)	; Don't access what isn't valid....
	clr.l	_SearchStrLen(A5)
1$
	movea.l	_DOSBase(A5),A6
	lea	_FileName(A5),A0
	move.l	A0,D1
	moveq	#ACCESS_READ,D2		; Mode: READ
	jsr	_LVOLock(A6)
	move.l	D0,_LockSave(A5)	; Save lock of file
	beq.w	.LockErr
	move.l	_LockSave(A5),D1	; The key to the file
	lea	_FIB(A5),A0		; Address FileInfoBlock
	move.l	A0,D2			; into D2
	jsr	_LVOExamine(A6)		; Get file's status
	lea	_FIB(A5),A0		; Address FileInfoBlock
	tst.l	(A0)			; Was function Examine successful?
	beq.w	.ExamineErr		; No, oh boy
	move.l	_LockSave(A5),D1	; Key to D1
	jsr	_LVOUnLock(A6)		; Free key
	lea	_FIB(A5),A0		; Address FileInfoBlock
	tst.l	4(A0)			; Dir or file?
	bpl.w	.ItsADir		; Too bad, it's a dir
	move.l	124(A0),_FileSize(A5)	; Get size in bytes of file
	move.l	124(A0),D0		; also into D0
	beq.w	.FileEmpty		; If the file is empty
	addq.l	#8,D0			; else filelength plus 8 bytes
	bsr.w	_MakeCountEven		; Align count

	move.l	D0,_BufferSize(A5)	; Save extended count

	movea.l	_SysBase(A5),A6
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	jsr	_LVOAllocMem(A6)	; Mem demand
	move.l	D0,_TextPtr(A5)		; Save address allocated memory
	beq.w	.AllocError		; Upon error...

	movea.l	_DOSBase(A5),A6
	lea	_FileName(A5),A0	; Address string (file's name)
	move.l	A0,D1			; into D1
	move.l	#MODE_OLDFILE,D2	; Mode = OLD
	jsr	_LVOOpen(A6)		; Open file
	move.l	D0,_FileHandle(A5)	; Save handle
	beq.s	.FileOpenErr		; Upon error
	move.l	_FileHandle(A5),D1
	movea.l	_TextPtr(A5),A0		; Address buffer for file to read in
	move.w	#$200A,(A0)+		; Write first a Blank and a LineFeed
	move.l	A0,D2			; Current address into D2
	move.l	_FileSize(A5),D3	; Length file		
	jsr	_LVORead(A6)		; Read file into buffer
	tst.l	D0
	bmi.s	.ReadError		; Upon error
	bsr.s	.CloseFile		; Close file
	movea.l	_TextPtr(A5),A0
	move.l	_FileSize(A5),D0
	cmpi.b	#10,1(A0,D0.l)
	beq.s	.ok
	move.b	#10,2(A0,D0.l)		; LineFeed (end)
.ok
	moveq	#$11,D0			; Say ok
	rts				; and back

.ReadError
	movea.l	_DOSBase(A5),A6		; - Because of bug in DOS v39
*					  we have to restore DOSBase....
	jsr	_LVOIoErr(A6)		; Get the error
	bsr.w	_SetError		; Set the error
	bsr.s	.CloseFile		; Close file
	bsr.w	_FreeFile		; Free allocated memory
	lea	_ReadErrTxt(pc),A0	; Errorstring
	bsr.w	_DisplayError		; Tell user...
	moveq	#0,D0
	rts

.CloseFile
	move.l	A6,-(sp)
	movea.l	_DOSBase(A5),A6
	move.l	_FileHandle(A5),D1
	jsr	_LVOClose(A6)
	movea.l	(sp)+,A6
	rts

.FileOpenErr
	jsr	_LVOIoErr(A6)		; Get the error
	bsr.w	_SetError		; and set it
	bsr.w	_FreeFile		; Free memory
	lea	_OpenFileErrTxt(pc),A0	; Errorstring
	bsr.w	_DisplayError		; Tell user...
	moveq	#0,D0
	rts

.AllocError
	movea.l	_DOSBase(A5),A6		; Get errorcode (103)
	jsr	_LVOIoErr(A6)
	bsr.w	_SetError		; Set the errorcode
	lea	_AllocErrTxt(pc),A0	; Errorstring
	bsr.w	_DisplayError		; Tell user...
	moveq	#0,D0
	rts

.FileEmpty
	lea	_EmptyTxt(pc),A0	; Errorstring
	bsr.w	_DisplayError		; Tell user...
	moveq	#0,D0
	rts

.ItsADir
	lea	_DirTxt(pc),A0		; Errorstring
	bsr.w	_DisplayError		; Tell user...
	tst.l	D0
	beq.s	3$			; If user said abort...

	bsr.w	OpenReq			; Initialize requester (Arp or Reqtools)
	cmpi.b	#-1,_ReqFlag(A5)	; No requester at all?
	beq.s	3$			; If so...

	lea	_FileName(A5),A0	; Name of directory
	move.l	A0,D1
	moveq	#ACCESS_READ,D2		; Mode: Read
	movea.l	_DOSBase(A5),A6
	jsr	_LVOLock(A6)		; Lock Directory
	move.l	D0,D2			; Lock into D2
	beq.s	3$			; If we can't get lock

*	move.l	D0,D0			; Lock
	lea	_Drive(A5),A0		; Buffer for name from Lock
	lea	_FIB(A5),A1		; FileInfoBlock
	bsr.w	_GetNameFromLock	; Get complete name of Lock, e.g. "DF0:pics/brushes/"

	move.l	D2,D1			; Lock
	movea.l	_DOSBase(A5),A6
	jsr	_LVOUnLock(A6)		; Free Lock

	cmpi.b	#1,_ReqFlag(A5)		; Reqtools-requester?
	bne.s	2$			; If not, it must be arp (for now)
	clr.l	-(sp)			; Local TagItems....
	clr.l	-(sp)			;   TAG_DONE
	clr.l	-(sp)			;   ti_DATA (pointer to directory string)
	clr.l	-(sp)			;   ti_TAG (RTFI_Dir)
	movea.l	sp,A0			; As TagList...
	move.l	#$80000000+50,(A0)	; Tell: change directory (RTFI_Dir)
	lea	_Drive(A5),A1		; Address new directory string
	move.l	A1,4(A0)		;  as pointer for ReqTools
	movea.l	_ReqPtr(A5),A1		; Reqtools-Requester-Record
	movea.l	_ReqToolsBase(A5),A6
	jsr	_LVOrtChangeReqAttrA(A6) ; Change directory to overgiven one
	lea	16(sp),sp		; Correct stack
2$
	st.b	_LoadFlag(A5)		; Tell: we're going to "load" a file
	bsr.w	_GetFile		; Get filename (display requester)
	tst.l	D0			; Nothing picked?
	beq.s	3$			; Hard error not possible, only "no file chosen"
	bra.w	_ReadFile		; Again, try to load the file...
3$
	moveq	#0,D0			; Tell, didn't fit to read file
	rts

.ExamineErr				; Should never occur
	jsr	_LVOIoErr(A6)
	bsr.w	_SetError
	move.l	_LockSave(A5),D1	; Key
	jsr	_LVOUnLock(A6)		; We allow other people to modify that file...
	lea	_ExamineErrTxt(pc),A0
	bsr.w	_DisplayError
	moveq	#0,D0
	rts

.LockErr
	jsr	_LVOIoErr(A6)
	bsr.w	_SetError
	lea	_LockErrTxt(pc),A0
	bsr.w	_DisplayError
*
** Now we do something smart....
*
** When the user calls us directly from CLI/Shell with the path and file and
** the file he/she wants to displayed can't be locked because he/she entered
** an invalid path or filename, we search as long as the path is valid, example:
*
**   1> viewer hd2:dtp/pictures/btush/aga/lamp.bsh   <- incorrect
** was chosen by the user, but the valid name is:
**   1> viewer hd2:dtp/pictures/brush/aga/lamp.bsh   <- correct
*
** The only thing we now have to do is to search backward if the string is valid, i.e.
** if the directory can be locked:
*
** (--------) "hd2:dtp/pictures/btush/aga/lamp.bsh" - caused the lock-error
** (1st loop) "hd2:dtp/pictures/btush/aga/"	    - isn't still valid
** (2nd loop) "hd2:dtp/pictures/btush/"		    - isn't still valid
** (3rd loop) "hd2:dtp/pictures/"		    - valid!!!
*
** Now we copy this valid string into the buffer for the "_Drive" and depending
** of the requester-modules (ReqTools/Arp) we setup the necessary things.
** That's all!
*

* Let's say the the volume isn't available (e.g. "DF7:"), then it makes no sense
* to execute the following routine (if we can't access the disk, we can't access
* the directories...).
	move.l	_errno(A5),D0		; Get current IoErr-errornumber
	cmpi.l	#ERROR_DEVICE_NOT_MOUNTED,D0
	beq.w	.NotFound
	cmpi.l	#ERROR_NOT_A_DOS_DISK,D0
	beq.w	.NotFound
	cmpi.l	#ERROR_NO_DISK,D0
	beq.w	.NotFound
	cmpi.l	#ERROR_OBJECT_IN_USE,D0 ; Does somebody format the drive?
	beq.w	.NotFound

.FindValidDir
	lea	_FileName(A5),A0	; Address string of filename
	movea.l	A0,A1			; Startaddress of string also in A1
	moveq	#-1,D0			; Dummy-counter
.FindStrEnd
	tst.b	(A0)+			; Find string end
	dbeq	D0,.FindStrEnd
	subq.l	#1,A0			; Pointer to NULL-byte (terminator) of string

.Find
	cmpa.l	A0,A1			; Original same as decreased address?, i.e.
	beq.w	.NotFound		; stringstart found - then no trailing was found
	cmpi.b	#':',(A0)		; Else...
	beq.s	.Found
	cmpi.b	#'/',(A0)
	beq.s	.Found
	subq.l	#1,A0
	dbf	D0,.Find		; So long not found...

.Found
	move.b	(A0),D1			; Remember last valid char
	clr.b	(A0)			; Last valid char is the ":" or the "/", so
*					  terminate string (_FileName), i.e. replace ":"
*					  or "/" through NULL-byte - otherwise at next loop
*					  we found the same char (never ending loop)
*					  "Viewer Hang Up"
	move.l	A2,-(sp)
	lea	_Drive(A5),A2		; Stringbuffer for volume/directory
.Cpy
	cmpa.l	A1,A0			; Copy all chars until we reach the right address
	beq.s	.Done
	move.b	(A1)+,(A2)+
	dbf	D0,.Cpy

.Done
	move.b	D1,(A2)+		; Copy also remembered trailing
	clr.b	(A2)			; Terminate new string
	movea.l	(sp)+,A2

	lea	_Drive(A5),A0
	move.l	A0,D1
	moveq	#ACCESS_READ,D2
	movea.l	_DOSBase(A5),A6
	jsr	_LVOLock(A6)		; Can we lock the directory (or volume)
	move.l	D0,D1
	beq.s	.FindValidDir		; If not, try again...
	jsr	_LVOUnLock(A6)		; Else give back not more needed lock

	bsr.w	OpenReq			; Initialize requester (Arp or Reqtools)
	cmpi.b	#-1,_ReqFlag(A5)	; No requester at all?
	beq.s	.NotFound		; If so...

	cmpi.b	#1,_ReqFlag(A5)		; Reqtools-requester?
	bne.s	.NotFound		; If not, it must be arp (for now)
	clr.l	-(sp)			; Local TagItems....
	clr.l	-(sp)			;   TAG_DONE
	clr.l	-(sp)			;   ti_DATA (pointer to directory string)
	clr.l	-(sp)			;   ti_TAG (RTFI_Dir)
	movea.l	sp,A0			; As TagList...
	move.l	#$80000000+50,(A0)	; Tell: change directory (RTFI_Dir)
	lea	_Drive(A5),A1		; Address new directory string
	move.l	A1,4(A0)		;  as pointer for ReqTools
	movea.l	_ReqPtr(A5),A1		; Reqtools-Requester-Record
	movea.l	_ReqToolsBase(A5),A6
	jsr	_LVOrtChangeReqAttrA(A6) ; Change directory to overgiven one
	lea	16(sp),sp		; Correct stack

.NotFound
	moveq	#0,D0			; Indicates no file was loaded...
	rts

***************************************************************
*
*
* Inputs: D0 - Lock of directory
*	  A0 - buffer for name of merged volume/directory name
*	  A1 - buffer for FileInfoBlock (272 byte here)
*

_GetNameFromLock
	movem.l	D2/D6-D7/A3-A4,-(sp)

	movea.l	_DOSBase(A5),A6

	move.l	D0,D6			; Lock
	beq.s	.ErrorEnd

	move.l	A0,A3			; Buffer
	move.l	A1,A4			; FIB

	moveq	#1,D7			; Counter
	move.l	D6,-(sp)		; Lock onto stack

.Parent
	move.l	D6,D1			; Lock
	jsr	_LVOParentDir(A6)
	tst.l	D0			; Previous dir
	beq.s	.Volume			; Home-directory e.g. DF0
	move.l	D0,-(sp)		; Lock passed onto stack
	addq.l	#1,D7			; 1 more Lock
	move.l	D0,D6			; Save this Lock
	bra.s	.Parent			; So long home-directory not found...
.Volume
	move.l	(sp)+,D1		; Lock
	bsr.s	.ExamineDir		; Get those infos
	bsr.s	.CopyName		; Copy volume's name
	move.b	#':',-1(A3)		; Set colon
	subq.l	#1,D7			; 1 less argument
	beq.s	.FoundThem		; If all...
.Drawer
	move.l	(sp)+,D1		; Lock
	bsr.s	.ExamineDir		; Get the infos
	bsr.s	.CopyName		; Copy drawer's name
	move.b	#'/',-1(A3)		; Set trailing
	subq.l	#1,D7			; 1 less argument
	beq.s	.FoundThem
	bra.s	.Drawer

.FoundThem
	clr.b	(A3)
	moveq	#0,D0			; Indicates no error
.end
	movem.l	(sp)+,D2/D6-D7/A3-A4
	rts

.ErrorEnd
	moveq	#-1,D0
	bra.s	.end


.ExamineDir
	move.l	A4,D2		; FIB
	jmp	_LVOExamine(A6)

.CopyName
	move.l	A4,A0		; FIB
	addq.l	#8,A0		; Lock
.CopyIt
	move.b	(A0)+,(A3)+
	bne.s	.CopyIt
	rts

************************
*
* Free allocated data...
*
* Inputs: none
* Results: none

_FreeFile
	move.l	A6,-(sp)
	movea.l	_SysBase(A5),A6
	movea.l	_TextPtr(A5),A1
	move.l	_BufferSize(A5),D0
	jsr	_LVOFreeMem(A6)
	clr.l	_BufferSize(A5)		; Important!!!
	clr.l	_TextPtr(A5)		; Important!!!
	clr.l	_SearchStrPtr(A5)
	clr.l	_SearchStrLen(A5)
	movea.l	(sp)+,A6
	rts

******************************************
*
* File is an object module or a binary file.
* Called out of "CheckFile()
*
* Inputs: none
* Results: none
*

*------------------------------------------------------
_WrongFileType
	tst.b	_NoWarnFlag(A5)
	bne.s	1$
	bsr.w	_GetConvertedSize
	move.l	D0,-(sp)
	pea	_ObjectFileTxt(pc)	; Display the error
	bsr.w	_FmtDisplay
	addq.l	#8,sp
	tst.l	D0			; Right mouse button?
	beq.s	0$			; Yes
1$
	bra.w	_ConvertBinary
0$
	addq.l	#4,sp			; Remove "bsr"
	bsr.s	_FreeFile
	bra.w	_Loop

_BinaryFile
	tst.b	_NoWarnFlag(A5)
	bne.s	1$
	bsr.w	_GetConvertedSize
	move.l	D0,-(sp)
	pea	_BinaryFileTxt(pc)
	bsr.w	_FmtDisplay
	addq.l	#8,sp
	tst.l	D0			; Right mouse button?
	beq.s	0$			; Yes
1$
	bra.w	_ConvertBinary
0$
	addq.l	#4,sp			; Remove "bsr"
	bsr.s	_FreeFile
	bra.w	_Loop

**********************************************
*
* Check if the file is an ascii-text file,
*  a powerpacker.library packed ascii-textfile,
*  a picture,
*  a powerpacker.library packed picture or -what is
* not truely displayable
*  an object file,
*  a binary file (like ANIMs).
*
* Inputs: none
* Results: none
*

_CheckFile
	movea.l	_TextPtr(A5),A0		; Source in memory
	addq.l	#2,A0			; Overread #$200A
	cmpi.l	#'PP20',(A0)		; PowerPacker.library packed?
	beq.w	_Decrunch
	cmpi.l	#$000003F3,(A0)		; Hunk header?
	beq.s	_WrongFileType		; If so ...
	cmpi.l	#'CAT ',(A0)
	beq.w	_LoadFCFile
	cmpi.l	#'LIST',(A0)
	beq.w	_LoadFCFile
	cmpi.l	#'FORM',(A0)		; IFF-file?
	bne.s	_CheckFile_1		; If not...
	cmpi.l	#'ILBM',8(A0)		; Picture?
	beq.w	_LoadScreen		; If so...
	cmpi.l	#'ACBM',8(A0)		; Picture?
	beq.w	_LoadScreen		; If so...
	cmpi.l	#'SWRT',8(A0)		; FinalCopy document?
	beq.w	_LoadFCFile
	cmpi.l	#'FTXT',8(A0)		; IFF-text document?
	beq.w	_LoadFCFile
	cmpi.l	#'WOWO',8(A0)		; WordWoorth text document?
	beq.w	_LoadFCFile
	cmpi.l	#'8SVX',8(A0)		; Audio file?
	beq.w	_LoadAudio

*
** Test if file contains binary datas...
*
_CheckFile_1
	move.l	#255,D0			; Counter
	move.l	_FileSize(A5),D1	; Old filelength
	cmp.l	D0,D1			; Compare
	ble.s	SetLittleFileSize	; Smaller than 256!
	bra.s	Test_If_Binary		; Else test 256 bytes
SetLittleFileSize:
	move.b	D1,D0			; As much bytes file is large (smaller than 256)
	subq.b	#1,D0			; Minus 1 - because of DBF

Test_If_Binary
	move.b	(A0),D1
	cmpi.b	#$9B,D1
	beq.s	.Ok
	cmpi.b	#127,D1
	bls.s	.Ok1
	cmpi.b	#159,D1
	bls.w	_BinaryFile
	bra.s	.Ok
.Ok1
	cmpi.b	#31,D1
	bhi.s	.Ok
	cmpi.b	#6,D1
	bls.w	_BinaryFile
.Ok2
	cmpi.b	#15,D1
	beq.w	.Ok
	cmpi.b	#16,D1
	beq.w	.Ok
	cmpi.b	#27,D1
	beq.s	.Ok
	bhi.w	_BinaryFile
	cmpi.b	#15,D1
	bhi.w	_BinaryFile
.Ok
	addq.l	#1,A0			; One char further
	dbf	D0,Test_If_Binary	; All bytes tested?
	rts

*******************************************
*
* Decrunch startup for PP20 crunched files.
*
* Inputs: none
* Results: none
*

_Decrunch
	movea.l	_TextPtr(A5),A0		; Source
	addq.l	#2,A0			; Overread #$200A
	move.l	_FileSize(A5),D0	; Length file
	lea	-4(A0,D0.l),A0		; Pointer to last longword of crunched file

	move.l	(A0),D0			; Only upper 24 bits are intresting
	lsr.l	#8,D0			; Skip crunch-info
	move.l	D0,_UPFSize(A5)		; UnPackedFileSize
	addi.l	#12,D0			; Plus 8 bytes :-) Nico François
*					  plus 4 :-) Jörg van de Loo
	bsr.w	_MakeCountEven		; Align size
	move.l	D0,_IncSize(A5)		; Increased file size

	tst.b	_NoWarnFlag(A5)		; Allowed to display warning?
	bne.s	1$
	move.l	_UPFSize(A5),D0		; Length file
	move.l	D0,-(sp)
	pea	_PPCrunchTxt(pc)	; Tell user
	bsr.w	_FmtDisplay
	addq.l	#8,sp
	tst.l	D0			; Right mousebtton?
	beq.w	_BinaryFile		; If so...
1$
	move.l	_IncSize(A5),D0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,_DecrunchAddr(A5)	; Buffer for decrunched datas
	beq.s	.DecrunchError

	movea.l	_TextPtr(A5),A0		; = Decrunch address
	addq.l	#2,A0			; Overread #$200A
	move.l	_FileSize(A5),D0	; Length crunched file
	movea.l	_DecrunchAddr(A5),A1	; Address for uncrunched file
	move.w	#$200A,(A1)+		; (but write down Blank and LineFeed as first
*					  entries, important for the ascii-text-viewer).

	bsr.s	_PPDecrunch		; Decrunch datas

	movea.l	_DecrunchAddr(A5),A0
	move.l	_UPFSize(A5),D0
	cmpi.b	#10,1(A0,D0.l)
	beq.s	.CrunchOk
	move.b	#10,2(A0,D0.l)		; Write LineFeed at end of uncrunched file
.CrunchOk
	bsr.w	_FreeFile		; Free not needed thing

	move.l	_DecrunchAddr(A5),_TextPtr(A5)	; Copy pointer
	move.l	_IncSize(A5),_BufferSize(A5)	; Copy size
	move.l	_UPFSize(A5),_FileSize(A5)	; Copy size

	bra.w	_CheckFile		; Check unpacked file

.DecrunchError
	lea	_DecrunchErrTxt(pc),A0
	bsr.w	_DisplayError
	bsr.w	_FreeFile		; see above
	addq.l	#4,sp			; Remove "bsr" CheckFile
	bra.w	_Loop


***********************************
*
* Copyright Nico François
*

_PPDecrunch
	movem.l	D1-D3/D5-D7/A2-A3,-(sp)
	bsr.s	.PowerPackerDecruncher
	movem.l	(sp)+,D1-D3/D5-D7/A2-A3
	rts
.PowerPackerDecruncher
	lea	4(A0),A3
	lea	0(A0,D0.l),A0
	movea.l	A1,A2
	moveq	#3,D6
	moveq	#7,D7
	moveq	#1,D5
	movea.l	A2,A1
	move.l	-(A0),D1
	tst.b	D1
	beq.s	1$
	bsr.s	5$
	subq.b	#1,D1
	lsr.l	D1,D5
1$
	lsr.l	#8,D1
	add.l	D1,A2
2$

	bsr.s	5$
	bcs.s	12$
	moveq	#0,D2
3$
	moveq	#1,D0
	bsr.s	8$
	add.w	D1,D2
	cmp.w	D6,D1
	beq.s	3$
4$
	moveq	#7,D0
	bsr.s	8$
	move.b	D1,-(A2)
	dbf	D2,4$
	cmp.l	A2,A1
	bcs.s	12$
	rts
5$
	lsr.l	#1,D5
	beq.s	6$
	rts
6$
	move.l	-(A0),D5
	roxr.l	#1,D5
	rts
7$
	subq.w	#1,D0
8$
	moveq	#0,D1
9$
	lsr.l	#1,D5
	beq.s	11$
10$
	roxl.l	#1,D1
	dbf	D0,9$
	rts
11$
	move.l	-(A0),D5
	roxr.l	#1,D5
	bra.s	10$
12$
	moveq	#1,D0
	bsr.s	8$
	moveq	#0,D0
	move.b	0(A3,D1.w),D0
	move.w	D1,D2
	cmp.w	D6,D2
	bne.s	15$
	bsr.s	5$
	bcs.s	13$
	moveq	#7,D0
13$
	bsr.s	7$
	move.w	D1,D3
14$
	moveq	#2,D0
	bsr.s	8$
	add.w	D1,D2
	cmp.w	D7,D1
	beq.s	14$
	bra.s	16$
15$
	bsr.s	7$
	move.w	D1,D3
16$
	addq.w	#1,D2
17$
	move.b	0(A2,D3.w),-(A2)
	dbf	D2,17$
	cmpa.l	A2,A1
	bcs.s	2$
	rts

***********************************************
*
* Attempt to find a display ID which does match
* with the settings of the computed image.
*
* Needed for the Picasso96 software package.
*
* Should also works with other by me unknown
* 3rd party software packages.
*

_GetMode
	movem.l	D2-D3/D5-D7/A2,-(sp)

	moveq	#0,D5
	move.b	D0,D5

	cmpi.w	#1360,_Width(A5)	; Maximum widtn for a 24 bit display (CV3D)
	bls.s	1$
	cmpi.b	#16,D5			; If not 24 bitplanes deep
	bls.s	1$
	moveq	#16,D5			; Else, force screen from 24 to 16 bitplanes
1$
	moveq	#0,D7			; Error code or Monitor ID

	movea.l	_SysBase(A5),A6
	move.l	#128,D0			; Buffer for DimensionInfo (di)
	move.l	#MEMF_CLEAR,D1
	jsr	_LVOAllocMem(A6)
	tst.l	D0
	beq.w	.end
	movea.l	D0,A2			; DimensionInfo

	movea.l	_GfxBase(A5),A6
	moveq	#INVALID_ID,D6		; Get really first ID!

	cmpi.b	#7,D5
	bhi.s	.loop
	moveq	#8,D5			; Less than 8 bitplanes -> now 8 bitplanes!

.loop
	move.l	D6,D0			; Last monitor ID
	jsr	_LVONextDisplayInfo(A6)
	cmpi.l	#INVALID_ID,D0		; End of monitor ID list?
	beq.s	.notfound

	move.l	D0,D6			; Monitor ID
	andi.l	#$FFF00000,D0		; Only non native AMIGA modes allowed!
	beq.s	.loop
	cmpi.l	#$FFF00000,D0		; Test monitor? - ignore!
	beq.s	.loop

	suba.l	A0,A0			; handle = 0
	movea.l	A2,A1			; di
	move.l	#128,D0			; size of buffer
	move.l	#DTAG_DIMS,D1		; TAG
	move.l	D6,D2			; Monitor ID
	jsr	_LVOGetDisplayInfoData(A6)
	tst.l	D0
	beq.s	.loop			; If it failed...

*	cmpi.w	#15,dim_MaxDepth(A2)	; Ignore 15bit modes!
*	beq.s	.loop

	cmp.w	#16,D5			; More than 16 bitplanes?
	bls.s	.normalDepthCheck	; If not, a normal depth check

	cmp.w	#23,dim_MaxDepth(A2)	; Can we display 24 bitplanes at a time with this monitor?
	bls.s	.loop			; No...

	bra.s	.dimCheck		; Yes...

.normalDepthCheck
	cmp.w	dim_MaxDepth(A2),D5	; Right depth?
	bne.s	.loop			; If not...

.dimCheck
	lea	dim_Nominal(A2),A0	; Get dimension of monitor
	move.w	ra_MaxX(A0),D0		; Last X-position of monitor (e.g. 639)
	move.w	ra_MaxY(A0),D1		; Last Y-position of monitor (e.g. 479)
	addq.w	#1,D0			; e.g. == 640
	addq.w	#1,D1			; e.g. == 480

	move.w	_PlaneWidth(A5),D2	; e.g. 640
	move.w	_PlaneHeight(A5),D3	; e.g. 480

	cmp.w	D0,D2
	bne.s	.loop
	cmp.w	D1,D3
	bne.s	.loop

	move.l	D6,D7			; Found ID!

* Now figure out if this monitor supports changes of RasInfo,
* set ViewPortShare by default to no (#-1)!

* Completey removed because Picasso96 1.4x supports now changing of View^dx/dy
	moveq	#0,D0			; Must be set to minus 1 if the check should work!!!
	move.l	D0,_ViewPortShare(A5)

*	suba.l	A0,A0			; handle = 0
*	movea.l	A2,A1			; Now MonitorInfo!!!
*	move.l	#128,D0			; size of buffer
*	move.l	#DTAG_MNTR,D1		; TAG
*	move.l	D6,D2			; Monitor ID
*	jsr	_LVOGetDisplayInfoData(A6)
*	tst.l	D0
*	beq.s	.freeDI

*	move.l	mtr_Compatibility(A2),_ViewPortShare(A5)
*	bra.s	.freeDI

.notfound
*	moveq	#0,D7			; No ID!
*	move.l	D7,_ViewPortShare(A5)	; Reset

.freeDI
	movea.l	_SysBase(A5),A6
	movea.l	A2,A1
	move.l	#128,D0
	jsr	_LVOFreeMem(A6)
.end
	move.l	D7,D0
	movem.l	(sp)+,D2-D3/D5-D7/A2
	rts				; Return ID in D0 or zero for not found
*					  (only foreign modes will be returned)

************************************************
*
* Display picture or image...
*
* Inputs: none
* Results: none
*

_LoadScreen
	tst.b	_NoWarnFlag(A5)
	bne.s	0$

	cmpi.l	#'ACBM',8(A0)		; ACBM-file?
	bne.s	.IFF_ILBM		; if not, must be ILBM-file

	lea	_ACBMTxt(pc),A0
	bsr.w	_DisplayError
	tst.l	D0			; User cancelled?
	beq.w	_BinaryFile		; If so, don't display
	bra.s	0$

.IFF_ILBM
	lea	_ILBMTxt(pc),A0
	bsr.w	_DisplayError
	tst.l	D0			; User cancelled?
	beq.w	_BinaryFile		; If so, don't display
0$
	movea.l	_TextPtr(A5),A0		; Source in memory
	addq.l	#2,A0			; Overread #$200A

	move.l	A0,_SourceFilePtr(A5)	; Copy pointer and size
	move.l	_FileSize(A5),_SourceFileSize(A5)

	bsr.w	_Convert		; Decrunch image
	move.l	D0,-(sp)		; Save returncode

	movea.l	_SysBase(A5),A6
	movea.l	_TextPtr(A5),A1
	move.l	_BufferSize(A5),D0	; Free old datas
	jsr	_LVOFreeMem(A6)
	clr.l	_TextPtr(A5)		; Important!!!
	clr.l	_BufferSize(A5)
	clr.l	_SearchStrPtr(A5)
	clr.l	_SearchStrLen(A5)

	move.l	(sp)+,D0		; Get return code
	cmpi.l	#1,D0			; 1 means all ok.
	bne.w	2$


	moveq	#0,D0
	move.b	_Depth(A5),D0
	move.l	_ViewPortMod(A5),D1
	andi.l	#HAM_KEY,D1		; HAM6 or HAM8?
	beq.s	.noham			; If not...

.ham
	moveq	#0,D1
	move.b	_Depth(A5),D1
	move.l	D1,_HAMSet(A5)
	move.b	#24,_Depth(A5)		; Always use a 24 bit depth screen for HAM modes

	moveq	#1,D1			; Initial val
	subq.b	#2,D0			; 8 to 6 or 6 to 4
	lsl.w	D0,D1			; HAM8: 1 << 6 = 64 or HAM6: 1 << 4 = 16
	lsl.l	D0,D1			; Perform 64 * 64 * 64 or
	lsl.l	D0,D1			; 16 * 16 * 16
	bra.s	.giveMsg		; Done for HAM

.noham
	clr.l	_HAMSet(A5)
	moveq	#1,D1
	lsl.l	D0,D1			; 1 << x = number of colours used

.giveMsg
	tst.b	_NoWarnFlag(A5)
	bne.s	.DontWrite

	move.l	_AllPlaneSize(A5),D0	; Allocated size (in bytes)
	move.l	D0,-(sp)
	move.l	D1,-(sp)		; Number of colours
	move.w	_Height(A5),D0		; Height of image
	move.l	D0,-(sp)
	move.l	_RealIWidth(A5),D0	; Width of image (no boundary)
	move.l	D0,-(sp)
	move.w	_Height(A5),D0		; Number of rows used by bitmap
	move.l	D0,-(sp)
	move.w	_Width(A5),D0		; Width in pixels of bitmap
	move.l	D0,-(sp)
	move.w	_PlaneHeight(A5),D0	; Original screen's height
	move.l	D0,-(sp)
	move.w	_PlaneWidth(A5),D0	; Original screen's width
	move.l	D0,-(sp)
	pea	_ImageInfoTxt(pc)
	bsr.w	_FmtDisplay
	lea	9*4(sp),sp
	tst.l	D0
	beq.w	2$

.DontWrite
	clr.b	_BlitFlag(A5)		; Reset flags, important!!!
	clr.b	_SuperBitMap(A5)
	moveq	#0,D0
	move.l	D0,_ViewPortShare(A5)

*
** If we're in OS3(+) we ask the system for the proberty ViewPort ModeID!
*
	movea.l	_GfxBase(A5),A6
	cmpi.w	#38,LIB_VERSION(A6)
	bls.w	.stdcheck

	tst.l	_TypeOfMem(A5)		; TypeOfMem set up by routine _Convert(), if it is zero
*					  the bitplanes for the image where forces to public (FAST)
*					  memory, since an alien gfx board software created the window's bitmap
	bne.w	.stdcheck

	bsr.w	_CheckEHB

	clr.l	-(sp)			; Assumption: 3rd party GFX device
	clr.l	-(sp)
	clr.l	-(sp)
	clr.l	-(sp)
	clr.l	-(sp)
	clr.l	-(sp)
	clr.l	-(sp)
	movea.l	sp,A0

	moveq	#0,D1
	move.l	D1,D2
	move.w	_PlaneHeight(A5),D1	; Screen's dimension (not bitmap !!!)
	move.w	_PlaneWidth(A5),D2

*
** Make a 4 to 3 aspect ratio so that any 3rd party device can handle it...
*	
	lsl.l	#2,D1			; * 4
	divu.w	#3,D1			; / 3

	cmp.w	D1,D2			; Range check...
	bhi.s	.align0

	andi.l	#$FFFF,D1 
	move.w	D1,D2			; New Width

.align0
	cmpi.w	#360,D2			; Following are resolutions which can be used
	bhi.s	.align1			; for 8 bitplane images, the other do only
	move.w	#320,D2			; support 15/16 and 24/32 bit resolutions...
	move.w	#240,D1
	bra.s	.dimset
.align1
	cmpi.w	#768,D2
	bhi.s	.align2
	move.w	#640,D2
	move.w	#480,D1
	bra.s	.dimset
.align2
	cmpi.w	#896,D2
	bhi.s	.align3
	move.w	#800,D2
	move.w	#600,D1
	bra.s	.dimset
.align3
	move.w	#1024,D2		; Default...
	move.w	#768,D1
.dimset
	move.w	D2,_PlaneWidth(A5)
	move.w	D1,_PlaneHeight(A5)

	moveq	#0,D0
	move.b	_Depth(A5),D0
	cmpi.b	#14,D0			; Force a 9-14 bitplane display to 15 bit
	bhi.s	.depthok
	cmpi.b	#8,D0
	bls.s	.depthok
	moveq	#15,D0
	bra.s	.startscan

.depthok
	cmpi.b	#16,D0
	bls.s	.startscan

	cmpi.w	#1360,_Width(A5)
	bls.s	.startscan
	moveq	#16,D0

.startscan
	movem.l	D0-D2,-(sp)

	move.l	#BIDTAG_NominalWidth,(A0)
	move.w	D2,4(A0)
	move.l	#BIDTAG_NominalHeight,6(A0)
	move.w	D1,10(A0)
	move.l	#BIDTAG_Depth,12(A0)
	move.b	D0,14(A0)
	clr.l	16(A0)			; TAG_Done
	movea.l	_GfxBase(A5),A6
	jsr	_LVOBestModeIDA(A6)
	move.l	D0,_ViewPortMod(A5)	; Save 3rd party GFX device View Mode ID (only CyberGraphX)

	andi.l	#$FFF00000,D0		; Only foreign modes!
	beq.s	.getModeID
	cmpi.l	#$FFF00000,D0		; Do not use a test monitor!
	bne.s	.modeok

.getModeID
	move.l	(sp),D0			; Depth
	bsr.w	_GetMode		; Find monitor id that suits...
	move.l	D0,_ViewPortMod(A5)
	bne.s	.modeok			; If found
	movem.l	(sp)+,D0-D2
	cmpi.b	#15,D0			; 15 bit?
	bne.s	.wrongMode		; No
	moveq	#16,D0			; Try 16 bit instead of 15
	bra.s	.startscan

.wrongMode
	lea	_ErrorInvalidIDTxt(pc),A0
	bsr.w	_DisplayError
	lea	7*4(sp),sp
	bra.w	2$

.modeok
	movem.l	(sp)+,D0-D2
	lea	7*4(sp),sp
	bsr.w	_BrightenColours	; Adjust the colours, e.g.: native AA = 8 bits per pen, 3rd party e.g. only 6
	bra.s	.ViewModeSet

.stdcheck
	move.l	_ViewPortMod(A5),D0	; ViewModes
	movea.l	_SysBase(A5),A6
	cmpi.w	#35,LIB_VERSION(A6)
	bls.s	.StdChipSet
	movea.l	_GfxBase(A5),A6
	jsr	_LVOModeNotAvailable(A6)
	tst.l	D0
	beq.s	.ViewModeSet

	move.l	_ViewPortMod(A5),D0	; Take as std-chip-set because Monitor isn't installed

.StdChipSet
	andi.l	#$FFFF,D0		; Clear upper 16 bits because
	move.l	D0,_ViewPortMod(A5)	; OS 1.x doesn't cares about Monitors!
	bsr.w	_DefaultMonitor		; Choose screen-mode depending on video system...

.ViewModeSet
	lea	_NewScreen(A5),A0	; Init screen-record
	clr.l	(A0)+
	move.w	_PlaneWidth(A5),(A0)+
	move.w	_PlaneHeight(A5),(A0)+
	moveq	#0,D0
	move.b	_Depth(A5),D0
	tst.l	_TypeOfMem(A5)
	bne.s	.storeDepth
	cmpi.b	#16,D0
	bls.s	.storeDepth
	cmp.w	#1360,_Width(A5)
	bls.s	.storeDepth
	moveq	#16,D0			; Reduce 24 bit to 16
.storeDepth
	move.w	D0,(A0)+
	move.b	#-1,(A0)+
	move.b	#-1,(A0)+
	move.l	_ViewPortMod(A5),D0
	move.w	D0,(A0)+
	move.w	#NS_EXTENDED|CUSTOMSCREEN|CUSTOMBITMAP|SCREENQUIET,D1
	move.w	D1,(A0)+
	clr.l	(A0)+			; Font
	lea	_ScreenName(pc),A1
	move.l	A1,(A0)+
	clr.l	(A0)+			; Gadgets
	lea	_BitmapStruc(A5),A1	; Set bitmap as screen's bitmap
	move.l	A1,(A0)+
	lea	_StdTags(A5),A1		; Init tag-list for screen
	move.l	A1,(A0)+
	move.l	#SA_DisplayID,(A1)+

	move.l	_ViewPortMod(A5),D0
	tst.l	_TypeOfMem(A5)		; Check if bitplanes forced to FAST-RAM - then
*					  the monitor ID isn't (shouldn't be) a normal AMIGA view mode
	beq.s	.Set

	btst.l	#12,D0			; An ECS or AA monitor?
	bne.s	.ECS_AA			; if so...

	andi.l	#$FFFF,D0		; else mask out unused bytes
	bra.s	.Set

.ECS_AA
	cmpi.l	#$5FFFF,D0		; Highest possible OS1 and! OS2 monitor ID
	bhi.s	.NewAAMode		; We do have an AA display mode - so
*					  check if we have the "AA-chip-set"
	bra.s	.Set			; We have only to open a standard or ECS display

*
** AA monitor used for displaying, do we have the right chip-set?
** NOTE: I check here the hardware but for the sakeness of completeness the info-data-
** base of the monitor itselfs must be examined.
*
.NewAAMode
	movea.l	_SysBase(A5),A6
	cmpi.w	#38,LIB_VERSION(A6)	; OS3.x or greater?
	bls.s	.MustEraseDbl		; If not...
	movea.l	_GfxBase(A5),A6
	move.b	gb_ChipRevBits0(A6),D1	; AA custom chip-set enabled?
	andi.b	#GFXF_AA_ALICE|GFXF_AA_LISA,D1
	bne.s	.Set			; If enabled...

.MustEraseDbl
	andi.l	#$FFFF,D0		; else take as default monitor

.Set
	tst.l	D0
	bne.s	.gotMID
	bsr.w	_DefaultMonitor
.gotMID
	move.l	D0,(A1)+		; Set DisplayID
	clr.l	(A1)

	clr.b	_BlitFlag(A5)		; Erase flag

	move.w	_Height(A5),D0
	move.w	_PlaneHeight(A5),D1
	cmp.w	D0,D1
	slt.b	_SuperBitMap(A5)	; Bitmap taller than screen? - see there
	shi.b	_BlitFlag(A5)		; Displaying a brush?

	move.w	_Width(A5),D0
	move.w	_PlaneWidth(A5),D1
	tst.l	_TypeOfMem(A5)		; Foreign display HW used to display image?
	beq.s	.widthSetOk		; If so,

	addi.w	#63,D1			;  otherwise care about the BURST-Fetch-mode
	andi.w	#-64,D1			;  so we have to correct this value
.widthSetOk
	tst.b	_SuperBitMap(A5)	; Already dimension for a superbitmap?
	bne.s	1$			; If so, skip next

	cmp.w	D0,D1			; Check for superbitmap
	slt.b	_SuperBitMap(A5)	; Set flag when encountered

1$
	tst.b	_BlitFlag(A5)		; Already a brush encountered?
	bne.s	.MustSet		; If so...

	cmp.w	D0,D1
	shi.b	_BlitFlag(A5)		; Encountered now

	tst.b	_BlitFlag(A5)		; Do we display a brush?
	bne.s	.MustSet		; If so...

	bra.s	.CheckDevice		; Normal fullscreen image either with a superbitmap or without

.MustSet
	lea	_NewScreen(A5),A0
	move.w	#NS_EXTENDED|CUSTOMSCREEN|SCREENQUIET,ns_Type(A0) ; No custom bitmap used when displaying brushes!

.CheckDevice
	tst.l	_TypeOfMem(A5)		; If the bitplanes have been forced to public memory
*					  I assume that a 3rd party GFX software driver is installed,
*					  this means we cannot use the system function to set the view
*					  since AMIGA 3rd party GFX boards are originally from the PC 
*					  and PCs don't support overscan!!!
	beq.s	.3rdParty
	bsr.w	_SetView		; See there... (only for real AMIGA monitors/screens)
	bra.s	.ScreenSet

.3rdParty
	lea	_NewScreen(A5),A0
	move.w	#NS_EXTENDED|CUSTOMSCREEN|SCREENQUIET,ns_Type(A0) ; No custom bitmap!
	clr.l	ns_CustomBitMap(A0)

	tst.b	_SuperBitMap(A5)	; Do we have a super bitmap?
	beq.s	.ScreenSet

	lea	_StdTags(A5),A0		; Taglist for screen, SA_DisplayID already set
	move.l	#SA_AutoScroll,8(A0)
	move.l	#0,12(A0)		; FALSE
	move.l	#SA_Type,16(A0)
	move.l	#CUSTOMSCREEN,20(A0)
	move.l	#SA_Width,24(A0)
	move.l	_ImageWidth(A5),28(A0)	; How tall must be the screen's bitmap (without alignments)
	move.l	#SA_Height,32(A0)
	clr.w	36(A0)			; Clear upper word of longword
	move.w	_Height(A5),38(A0)
	clr.l	40(A0)			; TAG_DONE

.ScreenSet
	lea	_NewScreen(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOOpenScreen(A6)
	tst.l	D0
	bne.s	.OkScreen		; Screen is open...

	lea	_ErrorOpeningScreen(pc),A0
	bsr.w	_DisplayError
	bra.w	2$

.OkScreen
	move.l	D0,D2			; ScreenPtr
	movea.l	D0,A0
	lea	sc_ViewPort(A0),A0	; Get screen's viewport
	lea	_Colourmap(A5),A1	; Get screen's colourmap
	move.l	_CMapNumEntries(A5),D0	; Number of colours (max 256)
	movea.l	_GfxBase(A5),A6
	cmpi.w	#38,LIB_VERSION(A6)
	bhi.s	.set32Bit		; Running an AGA machine!
	jsr	_LVOLoadRGB4(A6)	; Else use old colour-set function
	bra.s	.ColoursSet

.set32Bit
	tst.l	_TypeOfMem(A5)
	bne.s	.modifyCM32

*
** Following only for displays with more than 8 bitplanes
*
	cmpi.b	#8,_Depth(A5)
	bls.s	.modifyCM32

	move.l	D2,-(sp)
	movea.l	D2,A2

	lea	sc_ViewPort(A2),A0
	moveq	#0,D0
	move.l	D0,D1
	move.l	D0,D2
	move.l	D0,D3
	jsr	_LVOSetRGB32(A6)	; Colour zero of ViewPort to black

	lea	sc_RastPort(A2),A1
	moveq	#0,D0
	jsr	_LVOSetAPen(A6)		; Use Rastport's pen zero

	lea	sc_RastPort(A2),A1
	moveq	#0,D0
	moveq	#0,D1
	move.w	sc_Width(A2),D2
	subq.w	#1,D2
	move.w	sc_Height(A2),D3
	subq.w	#1,D3
	jsr	_LVORectFill(A6)	; Flood Screen with pen zero (black background)

	move.l	(sp)+,D2
	bra.s	.ColoursSet

.modifyCM32
	lea	_RGB32Colours(A5),A1	; RGB32 Colourtable
	jsr	_LVOLoadRGB32(A6)	; Load them

.ColoursSet
	tst.l	_TypeOfMem(A5)		; Since the most 3rd party GFX board drivers don't support
	beq.s	.blit			; custom BitMaps we have to copy the bitplanes manually...

	tst.b	_BlitFlag(A5)		; Do we have to blit an image to the screen?
	beq.w	.noneedblit		; No...

.blit
	movem.l	D2-D7/A2,-(sp)

.loop
	movea.l	_IntuitionBase(A5),A6
	move.l	ib_FirstScreen(A6),D0
	cmp.l	D2,D0
	beq.s	.startblit

	movea.l	_DOSBase(A5),A6
	moveq	#1,D1
	jsr	_LVODelay(A6)
	bra.s	.loop

.startblit
	tst.l	_HAMSet(A5)
	bne.s	.convertHAM

	lea	_BitmapStruc(A5),A0	; Image's bitmap
	cmpi.b	#24,bm_Depth(A0)
	bne.s	.check16bit
	movea.l	D2,A1			; Screen A1
	lea	sc_RastPort(A1),A1
	bsr.w	_PlanarBMtoRGB24
	tst.l	D0
	bne.w	.none
	bra.s	.realstartblit

.convertHAM
	tst.l	_TypeOfMem(A5)		; HAM and no gfx-board?
	bne.s	.realstartblit

	lea	_BitmapStruc(A5),A0	; Image's bitmap
	movea.l	D2,A1			; Screen A1
	lea	sc_RastPort(A1),A1
	bsr.w	_HAMtoRGB24
	tst.l	D0
	bne.w	.none

.check16bit
	cmpi.b	#8,bm_Depth(A0)
	bls.s	.realstartblit
	cmpi.b	#16,bm_Depth(A0)
	bhi.s	.realstartblit
	movea.l	D2,A1			; Screen A1
	lea	sc_RastPort(A1),A1
	bsr.w	_CLUTtoRGB16
	tst.l	D0
	bne.w	.none
	
.realstartblit
	lea	_BitmapStruc(A5),A0	; Image's bitmap
	movea.l	D2,A1			; Screen A1
	movea.l	A1,A2
	lea	sc_RastPort(A1),A1	; Screen's RastPort
	movea.l	rp_BitMap(A1),A1
	moveq	#0,D0
	move.l	D0,D1
	moveq	#0,D2
	move.w	sc_Width(A2),D2		; Screen's dimensions
	lsr.w	#1,D2			; Half
	moveq	#0,D7
	move.l	_RealIWidth(A5),D7	; Image's width
	lsr.w	#1,D7			; Half
	sub.w	D7,D2			; == X-Offset for image

	move.w	sc_Height(A2),D3
	lsr.w	#1,D3			; Half
	move.w	_Height(A5),D7
	lsr.w	#1,D7			; Half
	sub.w	D7,D3			; Y-Offset for image

	move.l	_RealIWidth(A5),D4	; Image's width
	move.w	_Height(A5),D5		; Image's height

*
** Because a blit must be friendly, we now check the bounds
*
	tst.w	D2
	bpl.s	.XOk
	moveq	#0,D2
.XOk
	tst.w	D3
	bpl.s	.YOk
	moveq	#0,D3
.YOk
	move.w	D4,D7
	add.w	D2,D7
	cmp.w	sc_Width(A2),D7
	bls.s	.WOk
	move.w	sc_Width(A2),D7
	addq.w	#1,D7

	move.w	D4,D6
	add.w	D2,D6
	sub.w	D7,D6

	sub.w	D6,D4
.WOk
	move.w	D5,D7
	add.w	D3,D7
	cmp.w	sc_Height(A2),D7
	bls.s	.doblit
	move.w	sc_Height(A2),D7
	addq.w	#1,D7

	move.w	D5,D6			; e.g. 832
	add.w	D3,D6			; e.g. 0
	sub.w	D7,D6			; 800 from 832 = 32

	sub.w	D6,D5			; 832 - 32 = 800

.doblit
	move.b	#$C0,D6			; Minterm == blit all
	move.l	#$FF,D7			; Only byte treated...
	suba.l	A2,A2

	movem.l	D0-D1/A0-A1,-(sp)
	movea.l	_GfxBase(A5),A6
	jsr	_LVOWaitBlit(A6)
	movem.l	(sp)+,D0-D1/A0-A1
	jsr	_LVOBltBitMap(A6)	 ; Blit the image to the display (only first 8 bitplanes... shit...)

.none
	movem.l	(sp)+,D2-D7/A2

.noneedblit
	movem.l	D2-D7/A2-A4,-(sp)
	movea.l	D2,A4			; Screen
	lea	sc_ViewPort(A4),A3	; Screen's ViewPort
	movea.l	vp_RasInfo(A3),A3	; Screen's RasInfo
	move.w	_PlaneWidth(A5),D2	; Visible size (screen)
	move.w	_PlaneHeight(A5),D3	; Visible size (screen)
	move.l	_RealIWidth(A5),D4	; Whole size (bitmap)
	move.w	_Height(A5),D5		; Whole size (bitmap)
	move.w	D2,D6			; Current Width
	move.w	D3,D7			; Current Height

.Wait
	clr.b	_RIChanged(A5)		; Important

	tst.b	_SuperBitMap(A5)	; Do we have a superbitmap?
	beq.w	.PureWait		; No, wait only

	move.w	sc_MouseX(A4),D0	; Mouse-x-position on screen
	move.w	sc_MouseY(A4),D1	; Mouse-y-position on screen
	move.w	$DFF016.l,_RMB(A5)	; Right mouse button state
	addq.w	#1,D0			; Important!
	addq.w	#1,D1			; Important!

*
** When the mouse hits the limits of the screen, we scroll the bitmap
** to the direction where the mouse hits the screen limits, so we display
** the normally invisible parts.
*
.ScrollRight
	cmp.w	D0,D2			; MouseX + 1 same as screenwidth (not bitmap!)
	bhi.s	.ScrollDown		; If not, mouse not at border...

	cmp.w	D4,D6			; Right border reached ? (max == current ?)
	bge.s	.ScrollDown		; - then not at the border of the bitmap...

	st.b	_RIChanged(A5)		; Else indicate: Must "Rethink Display" after this action

	btst	#2,_RMB(A5)		; Right mouse button?
	beq.s	.SR16			; - then move faster...
.SR1
	addq.w	#1,D6			; One more pixel (right side) + 1 to display
	addq.w	#1,ri_RxOffset(A3)	; Change offset so the hidden pixel can be displayed
	bra.s	.ScrollDown		; Check for down scrolling
.SR16	
	move.w	D6,_Max(A5)		; RMB - maximum visible  (_Max(A5) is only a dummy -
*					  haven't got enought registers....
	addi.w	#16,_Max(A5)		; plus 16 pixels
	cmp.w	_Max(A5),D4		; In range? - does it fit?
	blt.s	.SR1			; If not...
	addi.w	#16,D6			; Else 16 pixels more to display
	addi.w	#16,ri_RxOffset(A3)	; Change offset (X) so those hidden 16 pixels can
*					; be displayed	
.ScrollDown
	cmp.w	D1,D3			; MouseY + 1 same as bottom of screen (not bitmap!)
	bhi.s	.ScrollLeft		; If not, screen border not touched...

	cmp.w	D5,D7			; max == current ?
	bge.s	.ScrollLeft

	st.b	_RIChanged(A5)

	btst	#2,_RMB(A5)
	beq.s	.SD16
.SD1
	addq.w	#1,D7
	addq.w	#1,ri_RyOffset(A3)
	bra.s	.ScrollLeft
.SD16
	move.w	D7,_Max(A5)
	addi.w	#16,_Max(A5)
	cmp.w	_Max(A5),D5
	blt.s	.SD1

	addi.w	#16,D7
	addi.w	#16,ri_RyOffset(A3)

.ScrollLeft
	tst.w	sc_MouseX(A4)		; Top of screen touched with mouse?
	bne.s	.ScrollUp

	cmp.w	D2,D6			; std == current ?
	bls.s	.ScrollUp

	st.b	_RIChanged(A5)

	btst	#2,_RMB(A5)
	beq.s	.SL16
.SL1
	subq.w	#1,D6
	subq.w	#1,ri_RxOffset(A3)
	bra.s	.ScrollUp
.SL16
	move.w	D6,_Max(A5)
	subi.w	#16,_Max(A5)
	cmp.w	_Max(A5),D2
	bhi.s	.SL1

	subi.w	#16,D6
	subi.w	#16,ri_RxOffset(A3)

.ScrollUp
	tst.w	sc_MouseY(A4)		; Left border touched with mouse?
	bne.s	.Check

	cmp.w	D3,D7			; std == current ?
	bls.s	.Check

	st.b	_RIChanged(A5)

	btst	#2,_RMB(A5)
	beq.s	.SU16
.SU1
	subq.w	#1,D7
	subq.w	#1,ri_RyOffset(A3)
	bra.s	.Check
.SU16
	move.w	D7,_Max(A5)
	subi.w	#16,_Max(A5)
	cmp.w	_Max(A5),D3
	bhi.s	.SU1

	subi.w	#16,D7
	subi.w	#16,ri_RyOffset(A3)

.Check
	tst.b	_RIChanged(A5)		; RasInfo changed?
	beq.s	.PureWait		; No, wait only

	tst.l	_ViewPortShare(A5)	; Assumption: If we can share the ViewPort we
	bmi.s	.mustblit		; can also change the RasInfo-offsets!

* Called under OS1.x, 2.x and OS3.x when a native Amiga monitor is available.
* CyberGraphX will also end here...
	movea.l	_IntuitionBase(A5),A6
	movea.l	A4,A0			; Screen
	jsr	_LVOMakeScreen(A6)	; Move screen contents
	jsr	_LVORethinkDisplay(A6)	; and make them visible
	bra.s	.CheckLMB

.mustblit	; This is only for alien gfx-board software packages... (Picasso96)
	movem.l	D2-D7/A2,-(sp)		; » We have to blit the non visible part
*					    into the display

	lea	_BitmapStruc(A5),A0	; Image's bitmap
	lea	sc_RastPort(A4),A1	; Screen's RastPort
	movea.l	rp_BitMap(A1),A1	; Screen's BitMap
	suba.l	A2,A2			; No Temp
	move.w	D6,D0			; Last displayable pixel X
	move.w	D7,D1			; Last displayable pixel Y
	moveq	#0,D2			; DestX
	moveq	#0,D3			; DestY
	move.w	_PlaneWidth(A5),D4	; Width
	move.w	_PlaneHeight(A5),D5	; Height
	sub.w	D4,D0			; = SrcX
	sub.w	D5,D1			; = SrcY
	move.b	#$C0,D6			; Cooky cut
	move.b	#$FF,D7			; All planes

	movem.l	D0-D1/A0-A1,-(sp)
	movea.l	_GfxBase(A5),A6
	jsr	_LVOWaitBlit(A6)
	movem.l	(sp)+,D0-D1/A0-A1

	jsr	_LVOBltBitMap(A6)
	jsr	_LVOWaitBlit(A6)

	movem.l	(sp)+,D2-D7/A2
	bra.s	.CheckLMB

.PureWait
	moveq	#4,D1			; Wait 4/50 or 4/60 seconds
	movea.l	_DOSBase(A5),A6
	jsr	_LVODelay(A6)

.CheckLMB
	btst	#6,$BFE001		; Left mouse button?
	bne.w	.Wait

	movem.l	(sp)+,D2-D7/A2-A4

	movea.l	D2,A0			; Screen
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOCloseScreen(A6)
	bsr.w	_RestoreView		; See there
2$
	tst.l	_Bitplane(A5)		; Bitplane allocated?
	beq.s	3$
	movea.l	_Bitplane(A5),A1
	move.l	_AllPlaneSize(A5),D0
	clr.l	_AllPlaneSize(A5)
	clr.l	_Bitplane(A5)
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)		; Free bitplanes
3$
	movea.l	_IntuitionBase(A5),A6
	movea.l	_WindowPtr(A5),A0
	jsr	_LVOActivateWindow(A6)	; Activate our window

	addq.l	#4,sp
	bra.w	_LoadNew		; Display requester

************************************************************************
*
** Subroutines to set correct view for overscan pictures of ks lower v36.
*

_SetView
	movem.l	D0-D1/A0-A1/A6,-(sp)
	movea.l	_IntuitionBase(A5),A6
	cmpi.w	#35,LIB_VERSION(A6)	; Lower V36?
	bhi.s	.OSOScanSet

	jsr	_LVOViewAddress(A6)	; Get view
	movea.l	D0,A0
	move.w	v_DyOffset(A0),_OldY(A5) ; Save old offset
	move.w	v_DxOffset(A0),_OldX(A5)

	cmpi.w	#320,_PlaneWidth(A5)	; Lower than 320?
	bls.s	1$			; No overscan!
	cmpi.w	#352,_PlaneWidth(A5)	; If it fits, we have
	bls.s	2$			; an overscan-screen

	cmpi.w	#640,_PlaneWidth(A5)	; Lower than 640?
	bls.s	1$			; No overscan!

	bra.s	2$			; Else we have an overscan-screen

1$
	cmpi.w	#256,_PlaneHeight(A5)	; Lower than 256?
	bls.s	.NoOScan		; No overscan!
	cmpi.w	#290,_PlaneHeight(A5)	; If it fits, we have
	bls.s	2$			; an overscan-screen

	cmpi.w	#512,_PlaneHeight(A5)	; Lower than 512?
	bls.s	.NoOScan		; No overscan!

2$	; We have an overscan screen!
	move.w	#30,v_DyOffset(A0)	; Change dyOffset
	move.w	#112,v_DxOffset(A0)	; Change dxOffset
	jsr	_LVORethinkDisplay(A6)	; Make display

.NoOScan
	movem.l	(sp)+,D0-D1/A0-A1/A6
	rts

* Let the system do the work (up from OS2.0)...
.OSOScanSet
	lea	_StdTags(A5),A0
	movea.l	4(A0),A0		; MonitorID
	clr.l	-(sp)			; Make room for rectangle - see gfx.i
	clr.l	-(sp)
	movea.l	sp,A1			; Rectangle
	moveq	#OSCAN_STANDARD,D0	; The simply - may improve on your own...
	jsr	_LVOQueryOverscan(A6)	; Give me informations...
	tst.l	D0			; Failed?
	beq.s	.NoOScan
	movea.l	sp,A0			; Rectangle
	lea	_NewScreen(A5),A1
	move.w	(A0),(A1)		; ( ra_MinX(A0),ns_LeftEdge(A1) )
	move.w	ra_MinY(A0),ns_TopEdge(A1)
	addq.l	#8,sp
	bra.s	.NoOScan		; Set...

_RestoreView
	movem.l	D0-D1/A0-A1/A6,-(sp)
	movea.l	_IntuitionBase(A5),A6
	cmpi.w	#35,LIB_VERSION(A6)	; Ks 1.3 including Headly-Monitor?
	bhi.s	.NotNeeded		; At least Kickstart 2.0 ßeta...

	jsr	_LVOViewAddress(A6)	; Get old offsets
	movea.l	D0,A0
	move.w	_OldY(A5),v_DyOffset(A0); Restore them
	move.w	_OldX(A5),v_DxOffset(A0)
	jsr	_LVORethinkDisplay(A6)
.NotNeeded
	movem.l	(sp)+,D0-D1/A0-A1/A6
	rts

************************************************************************
*
** Running OS 1.x or the required mode is not available (up from OS 2.x)
*
* Video Overscan taken as limit to check against...
*

_DefaultMonitor
	moveq	#0,D0
	cmpi.w	#362,_PlaneWidth(A5)	; Los-Res maximum?
	bhi.s	.MinMedRes		; If taller, at least Med-Res
	bra.s	.CheckILace
.MinMedRes
	ori.w	#V_HIRES,D0		; Set Hires key

.CheckILace
	cmpi.w	#283,_PlaneHeight(A5)	; Maximum for PAL non-interlace
	bhi.s	.ItsInterlace		; else we have to set interlace-bit
	bra.s	.CheckNTSC
.ItsInterlace
	ori.w	#V_LACE,D0		; Set LACE-key

.CheckNTSC
	movea.l	_GfxBase(A5),A6
	move.w	gb_DisplayFlags(A6),D1
	btst	#2,D1			; PAL or NTSC ($4 means PAL)?
	bne.s	.VMSet			; was PAL

	btst	#2,D0			; else NTSC - check for interlace ($4 means V_LACE)
	bne.s	.VMSet			; Since already set

	cmpi.w	#241,_PlaneHeight(A5)	; Maximum for NTSC non-lace
	bls.s	.VMSet
	ori.w	#V_LACE,D0

.VMSet
	move.l	_ViewPortMod(A5),D1
	btst	#11,D1			; HAM-Key? (HAM or HAM8?)
	beq.s	.SetDim			; No HAM, else
	ori.w	#V_HAM,D0		; set HAM-Key

.SetDim
	move.l	D0,_ViewPortMod(A5)	; Save new ViewModes

	move.w	gb_DisplayFlags(A6),D1
	andi.w	#V_HIRES,D0
	bne.s	.Hires

	cmpi.w	#362,_PlaneWidth(A5)	; We have a Lores display
	bls.s	.checkDimHeight
	move.w	#362,_PlaneWidth(A5)
	bra.s	.checkDimHeight

.Hires
	cmpi.w	#724,_PlaneWidth(A5)	; We have a Medres or Hires display
	bls.s	.checkDimHeight
	move.w	#724,_PlaneWidth(A5)

.checkDimHeight
	move.l	_ViewPortMod(A5),D0
	andi.w	#V_LACE,D0		; Check for interlace
	bne.s	.Interlace

	btst	#2,D1			; Check display against NTSC / PAL
	bne.s	.noILacePAL

	cmpi.w	#241,_PlaneHeight(A5)	; Non interlace NTSC display
	bls.s	.done
	move.w	#241,_PlaneHeight(A5)
	bra.s	.done

.noILacePAL
	cmpi.w	#283,_PlaneHeight(A5)	; Non interlace PAL display
	bls.s	.done
	move.w	#283,_PlaneHeight(A5)
	bra.s	.done

.Interlace
	btst	#2,D1			; Check Display against NTSC / PAL
	bne.s	.ILacePAL

	cmpi.w	#482,_PlaneHeight(A5)	; Interlace NTSC display
	bls.s	.done
	move.w	#482,_PlaneHeight(A5)
	bra.s	.done

.ILacePAL
	cmpi.w	#566,_PlaneHeight(A5)	; Interlace PAL display
	bls.s	.done
	move.w	#566,_PlaneHeight(A5)
.done
	rts

*************************************************************************
*
** Convert a AMIGA BitMap-Structure with 24 bitplanes to the RGB values a
** 3rd party gfx-board support.
** This routines needs a 68020 CPU.
** This routine has been designed as a hack (late after midnight) and so
** it looks really dirty. Sorry for that.
*

	OPT	P=68020

_PlanarBMtoRGB24
*	A0 - bitmap, A1 Rastport

	movem.l	D2-D7/A2-A6,-(sp)

	movea.l	A0,A3			; Bitmap
	movea.l	A1,A2			; RastPort

	tst.l	_CyberGfxBase(A5)
	bne.s	.start
	movea.l	_SysBase(A5),A6
	lea	_CyberGfxName(pc),A1
	moveq	#40,D0
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_CyberGfxBase(A5)
	beq.w	.endall
.start
	OPT	OW-
	move.w	bm_BytesPerRow(A3),D0
	mulu.w	#24,D0
	move.l	D0,D3
	move.l	D0,_RGB24Size(A5)
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,_RGB24Ptr(A5)
	beq.w	.endall
	OPT	OW+

	move.l	_CyberGfxBase(A5),D1
	move.l	_ImageWidth(A5),D2

	move.l	A5,-(sp)
	lea	-48(sp),sp		; Mixed buffer
	movea.l	sp,A5

	move.l	D0,24(A5)		; Data buffer
	move.l	D1,28(A5)		; CyberGfxBase
	move.l	D2,32(A5)		; ImageWidth
	move.l	A2,36(A5)		; RastPort
	move.l	D3,44(A5)		; Size of one 24 bit RGB row
	
	movea.l	D0,A4			; RGB24

	OPT	OW-
	moveq	#0,D3			; Line
	moveq	#0,D4			; Bytes per row
	move.w	bm_BytesPerRow(A3),D4	; As it tells
	moveq	#0,D7			; Offset (X) in planar bitmap
	moveq	#0,D6			; Pixel per line
	OPT	OW+

.nextpixel				; Read eight pixel (one byte) of each bitplane
*	moveq	#23,D0			; For 24 bit-planes
*	lea	8(A3),A0		; 1st plane ptr
*	movea.l	A5,A2			; Mixed buffer

*.getB
*	movea.l	(A0)+,A1
*	move.b	0(A1,D7.l),(A2)+	; Read eight pixel (one byte) of each bitplane
*	subq.w	#1,D0
*	bcc.s	.getB			; For 24 bitplanes

*	movem.l	D3-D4/D6-D7/A3-A5,-(sp)

*	movea.l	A5,A0
*	movem.l	(A0)+,D1-D6

*
** Replaces above, consider yourself what's faster. Read eight pixel (one byte) of each bitplane
*
	movem.l	D3-D4/D6-D7/A3-A5,-(sp)	; Replacement start
	OPT	OW-

	lea	bm_Planes(A3),A0	; 1st plane ptr
	moveq	#8,D0

	move.b	([0,A0],D7.l),D1	; Read 8 pixel of bit-plane 0
	lsl.w	D0,D1
	move.b	([4,A0],D7.l),D1	; Read 8 pixel of bit-plane 1
	lsl.l	D0,D1
	move.b	([8,A0],D7.l),D1	; Read 8 pixel of bit-plane 2
	lsl.l	D0,D1
	move.b	([12,A0],D7.l),D1	; Read 8 pixel of bit-plane 3

	move.b	([16,A0],D7.l),D2	; Read 8 pixel of bit-plane 4
	lsl.w	D0,D2
	move.b	([20,A0],D7.l),D2	; Read 8 pixel of bit-plane 5
	lsl.l	D0,D2
	move.b	([24,A0],D7.l),D2	; Read 8 pixel of bit-plane 6
	lsl.l	D0,D2
	move.b	([28,A0],D7.l),D2	; Read 8 pixel of bit-plane 7

	move.b	([32,A0],D7.l),D3	; Read 8 pixel of bit-plane 8
	lsl.w	D0,D3
	move.b	([36,A0],D7.l),D3	; Read 8 pixel of bit-plane 9
	lsl.l	D0,D3
	move.b	([40,A0],D7.l),D3	; Read 8 pixel of bit-plane 10
	lsl.l	D0,D3
	move.b	([44,A0],D7.l),D3	; Read 8 pixel of bit-plane 11

	move.b	([48,A0],D7.l),D4	; Read 8 pixel of bit-plane 12
	lsl.w	D0,D4
	move.b	([52,A0],D7.l),D4	; Read 8 pixel of bit-plane 13
	lsl.l	D0,D4
	move.b	([56,A0],D7.l),D4	; Read 8 pixel of bit-plane 14
	lsl.l	D0,D4
	move.b	([60,A0],D7.l),D4	; Read 8 pixel of bit-plane 15

 	move.b	([64,A0],D7.l),D5	; Read 8 pixel of bit-plane 16
	lsl.w	D0,D5
	move.b	([68,A0],D7.l),D5	; Read 8 pixel of bit-plane 17
	lsl.l	D0,D5
	move.b	([72,A0],D7.l),D5	; Read 8 pixel of bit-plane 18
	lsl.l	D0,D5
	move.b	([76,A0],D7.l),D5	; Read 8 pixel of bit-plane 19

	move.b	([80,A0],D7.l),D6	; Read 8 pixel of bit-plane 20
	lsl.w	D0,D6
	move.b	([84,A0],D7.l),D6	; Read 8 pixel of bit-plane 21
	lsl.l	D0,D6
	move.b	([88,A0],D7.l),D6	; Read 8 pixel of bit-plane 22
	lsl.l	D0,D6
	move.b	([92,A0],D7.l),D6	; Read 8 pixel of bit-plane 23

	OPT	OW+			; Replacement end

*
** Registers (D1-D6) filled with 24 bytes each holding 8 pixel
*
.getColour
	movea.l	A4,A0			; RGB24 buffer

	move.l	D1,A1
	move.l	D2,A2
	move.l	D3,A3
	move.l	D4,A4
	move.l	D5,A5
	move.l	D6,A6

	move.l	#$80808080,D0
	and.l	D0,D1			; bit 0 of plane 0,1,2,3
	and.l	D0,D2			; bit 0 of plane 4,5,6,7
	and.l	D0,D3			; bit 0 of plane 8,9,10,11
	and.l	D0,D4			; bit 0 of plane 12,13,14,15
	and.l	D0,D5			; bit 0 of plane 16,17,18,19
	and.l	D0,D6			; bit 0 of plane 20,21,22,23

	moveq	#-34,D0			; See 'Counting ...' below for explain
	move.l	D0,-(sp)

.GetPixelColour

* Get the red bits (8 per gun) (24 bit)

* Original R0 pixel 0 bit 31 , R1 pixel 0 bit 23 , R2 pixel 0 bit 15, R3 pixel 0 bit 0 in D1.L

	move.b	D1,D0			; R3 pixel 0 in D0.b
	lsr.w	#8,D1			; Get R2 pixel 0 on byte position in D1.b
	lsr.b	#4,D0			; R3 pixel 0 on position 3
	lsr.b	#5,D1			; R2 pixel 0 on position 2
	or.b	D0,D1
	move.b	D1,D7			; Half lower nibble in D7 (bits 3 and 2)	

	swap.w	D1			; Original R0 pixel 0, R1 pixel 0, R2 pixel 0, R3 pixel 0 in D1.L
*					  R0 pixel 0 and R1 pixel 0 in D1.w

	move.b	D1,D0			; R1 pixel 0 in D0
	lsr.w	#8,D1			; Get R0 pixel 0 on byte position
	lsr.b	#6,D0			; R1 pixel 0 on position 1
	lsr.b	#7,D1			; R0 pixel 0 on position 0
	or.b	D0,D1
	or.b	D1,D7			; R3 R2 R1 R0

* --------------------

* Original R4 pixel 0 bit 31 , R5 pixel 0 bit 23 , R6 pixel 0 bit 15, R7 pixel 0 bit 0 in D2.L

	move.b	D2,D0			; R7 pixel 0 in D0
	lsr.w	#8,D2			; Get R6 pixel 0 on byte position
*	lsr.b	#0,D0			; R7 pixel 0 on position 7
	lsr.b	#1,D2			; R6 pixel 0 on position 6
	or.b	D0,D2
	or.b	D2,D7			; R7 R6 nn nn R3, R2, R1, R0

	swap.w	D2			; Original R4 pixel 0, R5 pixel 0 in D2.L
*					  R4 pixel 0, R5 pixel 0 in D2.w

	move.b	D2,D0			; R5 pixel 0 in D0
	lsr.w	#8,D2			; Get R4 pixel 0 on byte position
	lsr.b	#2,D0			; R5 pixel 0 on position 5
	lsr.b	#3,D2			; R4 pixel 0 on position 4
	or.b	D0,D2
	or.b	D2,D7			; R0, R1, R2, R3, R4, R1 nn nn

	move.b	D7,(A0)+		; Store red value

* -------------------------------------------------------------------

* Get the green bits (8 ber gun) (24 bit)

	move.b	D3,D0			; G3 pixel 0 in D0
	lsr.w	#8,D3			; Get G2 pixel 0 on byte position
	lsr.b	#4,D0			; G3 pixel 0 on position 3
	lsr.b	#5,D3			; G2 pixel 0 on position 2
	or.b	D0,D3
	move.b	D3,D7			; nn nn nn nn G3 G2 nn nn	

	swap.w	D3			; Original G0 pixel 0, G1 pixel 0, G2 pixel 0, G3 pixel 0
*					  now G0 pixel 0, G1 pixel 0 in D3.w

	move.b	D3,D0			; G1 pixel 0 in D0
	lsr.w	#8,D3			; Get G0 pixel 0 on byte position
	lsr.b	#6,D0			; G1 pixel 0 on position 1
	lsr.b	#7,D3			; G0 pixel 0 on position 0
	or.b	D0,D3
	or.b	D3,D7			; nn nn nn nn G3 G2 G1 G0

* -------------------

	move.b	D4,D0			; G7 pixel 0 in D0
	lsr.w	#8,D4			; Get G6 pixel 0 on byte position
*	lsr.b	#0,D0			; G7 pixel 0 on position 7
	lsr.b	#1,D4			; G6 pixel 0 on position 6
	or.b	D0,D4
	or.b	D4,D7			; G7 G6 nn nn G3 G2 G1 G0	

	swap.w	D4			; Original G4 pixel 0, G5 pixel 0, G6 pixel 0, G7 pixel 0
*					  now G4 pixel 0, G5 pixel 0 in D4.w

	move.b	D4,D0			; G5 pixel 0 in D0
	lsr.w	#8,D4			; Get G4 pixel 0 on byte position
	lsr.b	#2,D0			; G5 pixel 0 on position 5
	lsr.b	#3,D4			; G4 pixel 0 on position 4
	or.b	D0,D4
	or.b	D4,D7			; G7 G6 G5 G4 G3 G2 G1 G0

	move.b	D7,(A0)+		; Store green value
* -------------------------------------------------------------------

* Get the blue bits (8 ber gun) (24 bit)

	move.b	D5,D0			; B3 pixel 0 in D0
	lsr.w	#8,D5			; Get B2 pixel 0 on byte position
	lsr.b	#4,D0			; B3 pixel 0 on position 3
	lsr.b	#5,D5			; B2 pixel 0 on position 2
	or.b	D0,D5
	move.b	D5,D7			; nn nn nn nn B3 B2 nn nn	

	swap.w	D5			; Original B0 pixel 0, B1 pixel 0, B2 pixel 0, B3 pixel 0
*					  now B0 pixel 0, B1 pixel 0 in D5.w

	move.b	D5,D0			; B1 pixel 0 in D0
	lsr.w	#8,D5			; Get B0 pixel 0 on byte position
	lsr.b	#6,D0			; B1 pixel 0 on position 1
	lsr.b	#7,D5			; B0 pixel 0 on position 0
	or.b	D0,D5
	or.b	D5,D7			; nn nn nn nn B3 B2 B1 B0

* -------------------

	move.b	D6,D0			; B7 pixel 0 in D0
	lsr.w	#8,D6			; Get B6 pixel 0 on byte position
*	lsr.b	#0,D0			; B7 pixel 0 on position 7
	lsr.b	#1,D6			; B6 pixel 0 on position 6
	or.b	D0,D6
	or.b	D6,D7			; B7 B6 nn nn B3 B2 B1 B0	

	swap.w	D6			; Original B4 pixel 0, B5 pixel 0, B6 pixel 0, B7 pixel 0
*					  now B4 pixel 0, B5 pixel 0 in D6.w

	move.b	D6,D0			; B5 pixel 0 in D0
	lsr.w	#8,D6			; Get B4 pixel 0 on byte position
	lsr.b	#2,D0			; B5 pixel 0 on position 5
	lsr.b	#3,D6			; B4 pixel 0 on position 4
	or.b	D0,D6
	or.b	D6,D7			; B7 B6 B5 B4 B3 B2 B1 B0

	move.b	D7,(A0)+		; Store blue value
* -------------------------------------------------------------------

* Repeat GetPixelColour until a complete byte (8 pixel) is worked out...

	move.l	(sp)+,D0

	move.l	A1,D1
	move.l	A2,D2
	move.l	A3,D3
	move.l	A4,D4
	move.l	A5,D5
	move.l	A6,D6

.thejump
	addi.l	#36,D0
	move.l	D0,-(sp)

	jmp	(pc,D0.w)		; An opcode for 32 bit CPUs only

.mask1					; Counting 2 :: (-34) = (+2 - +36 = -34) -> 1st offset to PC to reach this (.mask1)
	move.l	#$40404040,D0		; -- Each mask has got 15 instruction surrounded by 36 bytes code
	and.l	D0,D1			; bit 1 of plane 0,1,2,3
	and.l	D0,D2			; bit 1 of plane 4,5,6,7
	and.l	D0,D3			; bit 1 of plane 8,9,10,11
	and.l	D0,D4			; bit 1 of plane 12,13,14,15
	and.l	D0,D5			; bit 1 of plane 16,17,18,19
	and.l	D0,D6			; bit 1 of plane 20,21,22,23
	moveq	#1,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask2
	move.l	#$20202020,D0
	and.l	D0,D1			; bit 2 of plane 0,1,2,3
	and.l	D0,D2			; bit 2 of plane 4,5,6,7
	and.l	D0,D3			; bit 2 of plane 8,9,10,11
	and.l	D0,D4			; bit 2 of plane 12,13,14,15
	and.l	D0,D5			; bit 2 of plane 16,17,18,19
	and.l	D0,D6			; bit 2 of plane 20,21,22,23
	moveq	#2,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask3
	move.l	#$10101010,D0
	and.l	D0,D1			; bit 3 of plane 0,1,2,3
	and.l	D0,D2			; bit 3 of plane 4,5,6,7
	and.l	D0,D3			; bit 3 of plane 8,9,10,11
	and.l	D0,D4			; bit 3 of plane 12,13,14,15
	and.l	D0,D5			; bit 3 of plane 16,17,18,19
	and.l	D0,D6			; bit 3 of plane 20,21,22,23
	moveq	#3,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask4
	move.l	#$08080808,D0
	and.l	D0,D1			; bit 4 of plane 0,1,2,3
	and.l	D0,D2			; bit 4 of plane 4,5,6,7
	and.l	D0,D3			; bit 4 of plane 8,9,10,11
	and.l	D0,D4			; bit 4 of plane 12,13,14,15
	and.l	D0,D5			; bit 4 of plane 16,17,18,19
	and.l	D0,D6			; bit 4 of plane 20,21,22,23
	moveq	#4,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask5
	move.l	#$04040404,D0
	and.l	D0,D1			; bit 5 of plane 0,1,2,3
	and.l	D0,D2			; bit 5 of plane 4,5,6,7
	and.l	D0,D3			; bit 5 of plane 8,9,10,11
	and.l	D0,D4			; bit 5 of plane 12,13,14,15
	and.l	D0,D5			; bit 5 of plane 16,17,18,19
	and.l	D0,D6			; bit 5 of plane 20,21,22,23
	moveq	#5,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask6
	move.l	#$02020202,D0
	and.l	D0,D1			; bit 6 of plane 0,1,2,3
	and.l	D0,D2			; bit 6 of plane 4,5,6,7
	and.l	D0,D3			; bit 6 of plane 8,9,10,11
	and.l	D0,D4			; bit 6 of plane 12,13,14,15
	and.l	D0,D5			; bit 6 of plane 16,17,18,19
	and.l	D0,D6			; bit 6 of plane 20,21,22,23
	moveq	#6,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask7
	move.l	#$01010101,D0
	and.l	D0,D1			; bit 7 of plane 0,1,2,3
	and.l	D0,D2			; bit 7 of plane 4,5,6,7
	and.l	D0,D3			; bit 7 of plane 8,9,10,11
	and.l	D0,D4			; bit 7 of plane 12,13,14,15
	and.l	D0,D5			; bit 7 of plane 16,17,18,19
	and.l	D0,D6			; bit 7 of plane 20,21,22,23
	moveq	#7,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	lsl.l	D0,D5
	lsl.l	D0,D6
	bra.w	.GetPixelColour

.mask8					; Does not exist!!!
	move.l	(sp)+,D0		; - so, continue...

	movem.l	(sp)+,D3-D4/D6-D7/A3-A5

	addq.l	#1,D7			; Worked out 8 pixel
	lea	24(A4),A4		; Increase RGB24 buffer

	addq.w	#1,D6			; New byte (8 pixel)
	cmp.w	D6,D4			; End of line?
	bne.w	.nextpixel		; If no new line

	movem.l	D3-D4/D7,-(sp)

* WritePixelArray( SrcRect [pointer to src datas A0]
*		   SrcX	X position D0
*		   SrcY	Y position D1
*		   SrcMod bytes per row in source rectangle D2
*		   RastPort A1
*		   DestX  D3
*		   DestY  D4
*		   SizeX  D5
*		   SizeY  D6
*		   SrcFmt RECTFMT_RGB )

	OPT	OW-
	movea.l	24(A5),A0		; Datas
	moveq	#0,D0
	moveq	#0,D1
	moveq	#0,D2
	move.l	44(A5),D2
	movea.l	36(A5),A1		; RastPort
	move.l	D3,D4			; DestY
	moveq	#0,D3			; DestX
	move.l	32(A5),D5		; Width
	move.w	#1,D6			; Height
	moveq	#RECTFMT_RGB,D7
	movea.l	28(A5),A6
	jsr	_LVOWritePixelArray(A6)
	OPT	OW+

	movem.l	(sp)+,D3-D4/D7

	move.l	24(A5),A4		; RGB24 buffer

	moveq	#0,D6			; New X position (starting at zero)
	addq.w	#1,D3			; Increase line number

	cmp.w	bm_Rows(A3),D3		; Already done for all lines?
	bne.w	.nextpixel

	lea	48(sp),sp
	movea.l	(sp)+,A5

	move.l	_RGB24Ptr(A5),A1
	move.l	_RGB24Size(A5),D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)

	moveq	#-1,D0
.endall
	movem.l	(sp)+,D2-D7/A2-A6
	rts

_PlanarBMtoRGB24end
	OPT	P=68000

*****************************************************
*
** Same as above only for 6/8 bitplanes (HAM encoded)
*

	OPT	P=68020

_HAMtoRGB24
*	A0 - bitmap, A1 Rastport

	movem.l	D2-D7/A2-A6,-(sp)

	movea.l	A0,A3			; Bitmap
	movea.l	A1,A2			; RastPort

	tst.l	_CyberGfxBase(A5)
	bne.s	.start
	movea.l	_SysBase(A5),A6
	lea	_CyberGfxName(pc),A1
	moveq	#40,D0
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_CyberGfxBase(A5)
	beq.w	.endall
.start
	OPT	OW-
	move.w	bm_BytesPerRow(A3),D0
	mulu.w	#24,D0
	move.l	D0,D3
	addq.l	#8,D0			; For one black RGB pixel (mem-allocation boundary = 8 - thus use 8 instead of 3) at left of image
	move.l	D0,_RGB24Size(A5)
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,_RGB24Ptr(A5)	; Buffer for RGB24 format
	beq.w	.endall
	OPT	OW+

	move.l	_CyberGfxBase(A5),D1
	move.l	_ImageWidth(A5),D2
	lea	_RGB32Colours(A5),A0
	move.l	A0,D4
	addq.l	#4,D4			; Pointer to colours (RGB) for index 0

	move.l	_HAMSet(A5),D5

	move.l	A5,-(sp)
	lea	-56(sp),sp		; Mixed buffer
	movea.l	sp,A5

	addq.l	#8,D0			; Ignore the black pixel
	move.l	D0,24(A5)		; Data buffer
	move.l	D1,28(A5)		; CyberGfxBase
	move.l	D2,32(A5)		; ImageWidth
	move.l	A2,36(A5)		; RastPort
	move.l	D3,44(A5)		; Size of one 24 bit RGB row
	move.l	D4,48(A5)		; RGB32Colours
	move.l	D5,52(A5)		; HAM indicator (HAM6/HAM8)
	
	movea.l	D0,A4			; Data

	OPT	OW-
	moveq	#0,D3			; Line
	moveq	#0,D4			; Bytes per row
	move.w	bm_BytesPerRow(A3),D4	; As it tells
	moveq	#0,D5			; Offset (X) in planar bitmap
	moveq	#0,D6			; Pixel per line
	OPT	OW+

.nextpixel
	move.l	52(A5),D0		; For `n´ bit-planes
	subq.w	#1,D0
	lea	8(A3),A0		; 1st plane ptr
	movea.l	A5,A2			; Mixed buffer

.getB
	movea.l	(A0)+,A1
	move.b	0(A1,D5.l),(A2)+	; Read eight pixel (one byte) of each bitplane
	subq.w	#1,D0
	bcc.s	.getB			; For `n´ bitplanes

	cmpi.l	#7,52(A5)		; HAM6 ?
	bhi.s	.doconvert

	clr.b	(A2)+			; HAM6 has got 2 bits less than HAM8
	clr.b	(A2)+

.doconvert
	movem.l	D3-D6/A3-A5,-(sp)
	bsr.s	.getC
	movem.l	(sp)+,D3-D6/A3-A5

	addq.l	#1,D5			; Worked out 8 pixel
	lea	24(A4),A4		; Increase RGB24 buffer

	addq.w	#1,D6			; New byte (8 pixel)
	cmp.w	D6,D4			; End of line?
	bne.s	.nextpixel		; If no new line

	movem.l	D3-D5,-(sp)

* WritePixelArray( SrcRect [pointer to src datas A0]
*		   SrcX	X position D0
*		   SrcY	Y position D1
*		   SrcMod bytes per row in source rectangle D2
*		   RastPort A1
*		   DestX  D3
*		   DestY  D4
*		   SizeX  D5
*		   SizeY  D6
*		   SrcFmt RECTFMT_RGB )

	OPT	OW-
	movea.l	24(A5),A0		; Datas
	moveq	#0,D0
	moveq	#0,D1
	moveq	#0,D2
	move.l	44(A5),D2
	movea.l	36(A5),A1		; RastPort
	move.l	D3,D4			; DestY
	moveq	#0,D3			; DestX
	move.l	32(A5),D5		; Width
	move.w	#1,D6			; Height
	moveq	#RECTFMT_RGB,D7
	movea.l	28(A5),A6
	jsr	_LVOWritePixelArray(A6)
	OPT	OW+

	movem.l	(sp)+,D3-D5

	move.l	24(A5),A4		; RGB24 buffer

	moveq	#0,D6			; New X position (starting at zero)
	addq.w	#1,D3			; Increase line number

	cmp.w	bm_Rows(A3),D3		; Already done for all lines?
	bne.s	.nextpixel

	lea	56(sp),sp
	movea.l	(sp)+,A5

	move.l	_RGB24Ptr(A5),A1
	move.l	_RGB24Size(A5),D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)

	moveq	#-1,D0
.endall
	movem.l	(sp)+,D2-D7/A2-A6
	rts

*
** Buffer filled with 24 bytes which hold 8 pixel
*
.getC
	movea.l	A5,A0			; Mixed buffer

	move.l	(A0)+,D1		; 4 bytes (plane0 pixel 0-7, plane1 pixel 0-7 and so on
	move.l	(A0)+,D2
	moveq	#0,D3

	movea.l	A4,A0			; RGB24 buffer
	movea.l	48(A5),A3		; Index colour table
	move.l	D1,A1
	move.l	D2,A2

	move.l	#$80808080,D0
	and.l	D0,D1			; bit 0 of plane 0,1,2,3
	and.l	D0,D2			; bit 0 of plane 4,5,6,7

	moveq	#-14,D0			; See 'Counting ...' below for explantion
	move.l	D0,-(sp)

.GetPixelColour

* Original D1 pixel-0 bit 0 , P1 pixel-0 0 bit 1, P2 pixel-0 bit 2, P3 pixel-0 bit 4

	move.b	D1,D0			; P3 pixel 0 in D0.b
	lsr.w	#8,D1			; Get P2 pixel 0 on byte position in D1.b
	lsr.b	#4,D0			; P3 pixel 0 on position 3
	lsr.b	#5,D1			; P2 pixel 0 on position 2
	or.b	D0,D1
	move.b	D1,D7			; Half lower nibble in D7 (bits 3 and 2)	

	swap.w	D1			; Original P2 pixel 0, P3 pixel 0, P0 pixel 0, P1 pixel 0
*					  P0 pixel 0 and P1 pixel 0 in D1.w

	move.b	D1,D0			; P1 pixel 0 in D0
	lsr.w	#8,D1			; Get P1 pixel 0 on byte position
	lsr.b	#6,D0			; P1 pixel 0 on position 1
	lsr.b	#7,D1			; P0 pixel 0 on position 0
	or.b	D0,D1
	or.b	D1,D7			; P3 P2 P1 P0

* --------------------

* Original P4 pixel 0 bit 4, P5 pixel 0 bit 5 , P6 pixel 0 bit 6, P7 pixel 0 bit 7

	move.b	D2,D0			; P7 pixel 0 in D0
	lsr.w	#8,D2			; Get P6 pixel 0 on byte position
*	lsr.b	#0,D0			; P7 pixel 0 on position 7
	lsr.b	#1,D2			; P6 pixel 0 on position 6
	or.b	D0,D2
	or.b	D2,D7			; P7 P6 nn nn P3, P2, P1, P0

	swap.w	D2			; Original P6 pixel 0, P7 pixel 0
*					  P6 pixel 0, P7 pixel 0 in D2.w

	move.b	D2,D0			; P4 pixel 0 in D0
	lsr.w	#8,D2			; Get P5 pixel 0 on byte position
	lsr.b	#2,D0			; P4 pixel 0 on position 5
	lsr.b	#3,D2			; P5 pixel 0 on position 4
	or.b	D0,D2
	or.b	D2,D7			; P7, P6, P5, P4, P3, P2 P1 P0

	cmpi.l	#7,52(A5)		; HAMSet equal to HAM8?
	bhi.s	.checkham8

	cmpi.b	#15,D7			; Index = 15? (HAM6 used)
	bls.s	.storeHAM6		; If index lower or equal 15 store unmodified index
	bra.s	.modifyHAM6		; Else compute modified index

.checkham8
	cmpi.b	#63,D7			; Index = 63? (HAM8 used)
	bls.s	.store			; If index lower or equal 63 store unmodified index

.modify					; Modifiy new pixel by last stored
	move.b	-3(A0),(A0)+		; Get red and take over
	move.b	-3(A0),(A0)+		; Get green and take over
	move.b	-3(A0),(A0)+		; Get blue and take over

	move.w	D7,D6			; Index

	andi.w	#63,D7			; Without H(old)A(nd)M(odified) bits
	lsl.b	#2,D7			; 6-bit value to an 8 bit one

	andi.w	#192,D6			; Only H(old)A(nd)M(odified) bits
	lsr.w	#6,D6			; into lowest bit positions
	jmp	(pc,D6.w*2)		; Calls one of the three `bra.s´ below

	bra.s	.modifyblue
	bra.s	.modifyred
	bra.s	.modifygreen

.modifyblue
	move.b	D7,-1(A0)
	bra.s	.repeat
.modifygreen
	move.b	D7,-2(A0)
	bra.s	.repeat
.modifyred
	move.b	D7,-3(A0)
	bra.s	.repeat

.modifyHAM6
	move.b	-3(A0),(A0)+		; Get red
	move.b	-3(A0),(A0)+		; Get green
	move.b	-3(A0),(A0)+		; Get blue

	move.w	D7,D6

	andi.w	#15,D7			; Without H(old)A(nd)M(odified) bits
	move.b	D7,D5			; Save result
	lsl.b	#4,D5			; Low nibble to high nibble
	or.b	D5,D7			; Make new value

	andi.w	#48,D6			; Only H(old)A(nd)M(odified) bits
	lsr.w	#4,D6			; into lowest bit positions
	jmp	(pc,D6.w*2)

	bra.s	.modifyblue
	bra.s	.modifyred
	bra.s	.modifygreen

.storeHAM6
	andi.w	#15,D7
	move.w	D7,D3			; INDEX to colour value
	lsl.w	#3,D3			; INDEX * 8
	move.w	D7,D4
	lsl.w	#2,D4			; INDEX * 4
	add.w	D4,D3			; == mulu 12 D3 (12 bytes per RGB gun used by OS3 structure)
	lea	0(A3,D3.w),A4		; Colour values (longwords)
	move.b	(A4),(A0)+		; Get only most significant byte
	move.b	4(A4),(A0)+		; the same...
	move.b	8(A4),(A0)+		; and again
	bra.s	.repeat

.store
	andi.w	#63,D7
	move.w	D7,D3			; INDEX to colour value
	lsl.w	#3,D3			; INDEX * 8
	move.w	D7,D4
	lsl.w	#2,D4			; INDEX * 4
	add.w	D4,D3			; == mulu 12 D3
	lea	0(A3,D3.w),A4		; Colour values (longwords)
	move.b	(A4),(A0)+		; See above
	move.b	4(A4),(A0)+
	move.b	8(A4),(A0)+

* Repeat GetPixelColour until a complete byte (8 pixel) is worked out...
.repeat
	move.l	(sp)+,D0

	move.l	A1,D1
	move.l	A2,D2

.thejump
	addi.l	#20,D0
	move.l	D0,-(sp)

	jmp	(pc,D0.w)		; Call one of the masks below depending on value in D0

.end
	move.l	(sp)+,D0		; Counting 2
	rts				; Counting 4

.mask1					; Counting 6 :: (-14) = (+6 - +20 = -14) -> 1st offset to PC to reach this (.mask1)
	move.l	#$40404040,D0		; -- Each mask has got 15 instruction surrounded by 20 bytes code
	and.l	D0,D1			; bit 1 of plane 0,1,2,3
	and.l	D0,D2			; bit 1 of plane 4,5,6,7
	moveq	#1,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask2					; 26
	move.l	#$20202020,D0
	and.l	D0,D1			; bit 2 of plane 0,1,2,3
	and.l	D0,D2			; bit 2 of plane 4,5,6,7
	moveq	#2,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask3					; 46
	move.l	#$10101010,D0
	and.l	D0,D1			; bit 3 of plane 0,1,2,3
	and.l	D0,D2			; bit 3 of plane 4,5,6,7
	moveq	#3,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask4					; 66
	move.l	#$08080808,D0
	and.l	D0,D1			; bit 4 of plane 0,1,2,3
	and.l	D0,D2			; bit 4 of plane 4,5,6,7
	moveq	#4,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask5					; 86
	move.l	#$04040404,D0
	and.l	D0,D1			; bit 5 of plane 0,1,2,3
	and.l	D0,D2			; bit 5 of plane 4,5,6,7
	moveq	#5,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask6
	move.l	#$02020202,D0
	and.l	D0,D1			; bit 6 of plane 0,1,2,3
	and.l	D0,D2			; bit 6 of plane 4,5,6,7
	moveq	#6,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask7
	move.l	#$01010101,D0
	and.l	D0,D1			; bit 7 of plane 0,1,2,3
	and.l	D0,D2			; bit 7 of plane 4,5,6,7
	moveq	#7,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	bra.w	.GetPixelColour

.mask8					; Does not exists!!!
	bra.w	.end

_HAMtoRGB24end
	OPT	P=68000

*****************************************************
*
** Same as above only for more than 9 and less than 17 bitplanes (not HAM) encoded
*

	OPT	P=68020

_CLUTtoRGB16
*	A0 - bitmap, A1 Rastport

	movem.l	D2-D7/A2-A6,-(sp)

	movea.l	A0,A3			; Bitmap
	movea.l	A1,A2			; RastPort

	tst.l	_CyberGfxBase(A5)
	bne.s	.start
	movea.l	_SysBase(A5),A6
	lea	_CyberGfxName(pc),A1
	moveq	#40,D0
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_CyberGfxBase(A5)
	beq.w	.endall
.start
	OPT	OW-
	move.w	bm_BytesPerRow(A3),D0	; CLUT (9-16 bits) become to a RGB (24 bit) gun, which is written to a 16 bit display
	mulu.w	#24,D0
	move.l	D0,D3
	move.l	D0,_RGB24Size(A5)
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,_RGB24Ptr(A5)	; Buffer for RGB24 format
	beq.w	.endall
	OPT	OW+

	move.l	_CyberGfxBase(A5),D1
	move.l	_ImageWidth(A5),D2
	move.l	_RGB32Values(A5),D4

	move.l	A5,-(sp)
	lea	-56(sp),sp		; Mixed buffer
	movea.l	sp,A5

*	move.l	D0,24(A5)		; Data buffer
*	move.l	D1,28(A5)		; CyberGfxBase
*	move.l	D2,32(A5)		; ImageWidth
*	move.l	A2,36(A5)		; RastPort
*	move.l	D3,44(A5)		; Size of one 24 bit RGB row
*	move.l	D4,48(A5)		; RGB32Values

	move.l	D0,32(A5)		; Data buffer
	move.l	D1,36(A5)		; CyberGfxBase
	move.l	D2,40(A5)		; ImageWidth
	move.l	A2,44(A5)		; RastPort
	move.l	D3,48(A5)		; Size of one 24 bit RGB row
	move.l	D4,52(A5)		; RGB32Values
	
	movea.l	D0,A4			; Data

	OPT	OW-
	moveq	#0,D3			; Line
	moveq	#0,D4			; Bytes per row
	move.w	bm_BytesPerRow(A3),D4	; As it tells
	moveq	#0,D5			; Offset (X) in planar bitmap
	moveq	#0,D6			; Pixel per line
	OPT	OW+

.nextpixel
	moveq	#15,D0			; For 16 bit-planes
	lea	8(A3),A0		; 1st plane ptr
	movea.l	A5,A2			; Mixed buffer

.getB
	move.l	(A0)+,D1
	bne.s	.exists
	move.b	D1,(A2)+		; No data (e.g. 13 bitplanes and bitplane 14/15/16 encountered)
	bra.s	.further
.exists
	movea.l	D1,A1
	move.b	0(A1,D5.l),(A2)+	; Read eight pixel (one byte) of each bitplane
.further
	subq.w	#1,D0
	bcc.s	.getB			; For `n´ bitplanes

.doconvert
	movem.l	D3-D6/A3-A5,-(sp)
	bsr.s	.getC
	movem.l	(sp)+,D3-D6/A3-A5

	addq.l	#1,D5			; Worked out 8 pixel
	lea	24(A4),A4		; Increase RGB24 buffer

	addq.w	#1,D6			; New byte (8 pixel)
	cmp.w	D6,D4			; End of line?
	bne.s	.nextpixel		; If no new line

	movem.l	D3-D5,-(sp)

* WritePixelArray( SrcRect [pointer to src datas A0]
*		   SrcX	X position D0
*		   SrcY	Y position D1
*		   SrcMod bytes per row in source rectangle D2
*		   RastPort A1

*		   DestX  D3
*		   DestY  D4
*		   SizeX  D5
*		   SizeY  D6
*		   SrcFmt RECTFMT_RGB )

	OPT	OW-
	movea.l	32(A5),A0		; Datas
	moveq	#0,D0
	moveq	#0,D1
	moveq	#0,D2
	move.l	48(A5),D2
	movea.l	44(A5),A1		; RastPort
	move.l	D3,D4			; DestY
	moveq	#0,D3			; DestX
	move.l	40(A5),D5		; Width
	move.w	#1,D6			; Height
	moveq	#RECTFMT_RGB,D7
	movea.l	36(A5),A6
	jsr	_LVOWritePixelArray(A6)
	OPT	OW+

	movem.l	(sp)+,D3-D5

	move.l	32(A5),A4		; RGB24 buffer

	moveq	#0,D6			; New X position (starting at zero)
	addq.w	#1,D3			; Increase line number

	cmp.w	bm_Rows(A3),D3		; Already done for all lines?
	bne.s	.nextpixel

	lea	56(sp),sp
	movea.l	(sp)+,A5

	move.l	_RGB24Ptr(A5),A1
	move.l	_RGB24Size(A5),D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)

	moveq	#-1,D0
.endall
	movem.l	(sp)+,D2-D7/A2-A6
	rts

*
** Buffer filled with 24 bytes which hold 8 pixel
*
.getC
	movea.l	A5,A0			; Mixed buffer
	move.l	52(A5),A5		; RGB32Values
	movem.l	(A0)+,D1-D4		; 8 bytes (plane0 pixel 0-15, plane1 pixel 0-15 and so on
	movea.l	A4,A0			; RGB24 buffer

	move.l	D1,A1
	move.l	D2,A2
	move.l	D3,A3
	move.l	D4,A4

	move.l	#$80808080,D0
	and.l	D0,D1			; bit 0 of plane 0,1,2,3
	and.l	D0,D2			; bit 0 of plane 4,5,6,7
	and.l	D0,D3			; bit 0 of plane 8,9,10,11
	and.l	D0,D4			; bit 0 of plane 12,13,14,15

	moveq	#-22,D0			; See 'Counting ...' below for explantion
	move.l	D0,-(sp)

.GetPixelColour
	moveq	#0,D7
	move.l	D7,D5

* Original D1 pixel-0 bit 0 , P1 pixel-0 bit 1, P2 pixel-0 bit 2, P3 pixel-0 bit 4

	move.b	D1,D0			; P3 pixel 0 in D0.b
	lsr.w	#8,D1			; Get P2 pixel 0 on byte position in D1.b
	lsr.b	#4,D0			; P3 pixel 0 on position 3
	lsr.b	#5,D1			; P2 pixel 0 on position 2
	or.b	D0,D1
	move.b	D1,D7			; Half lower nibble in D7 (bits 3 and 2)	

	swap.w	D1			; Original P2 pixel 0, P3 pixel 0, P0 pixel 0, P1 pixel 0
*					  P0 pixel 0 and P1 pixel 0 in D1.w

	move.b	D1,D0			; P1 pixel 0 in D0
	lsr.w	#8,D1			; Get P1 pixel 0 on byte position
	lsr.b	#6,D0			; P1 pixel 0 on position 1
	lsr.b	#7,D1			; P0 pixel 0 on position 0
	or.b	D0,D1
	or.b	D1,D7			; P3 P2 P1 P0

* --------------------

* Original P4 pixel 0 bit 4, P5 pixel 0 bit 5 , P6 pixel 0 bit 6, P7 pixel 0 bit 7

	move.b	D2,D0			; P7 pixel 0 in D0
	lsr.w	#8,D2			; Get P6 pixel 0 on byte position
*	lsr.b	#0,D0			; P7 pixel 0 on position 7
	lsr.b	#1,D2			; P6 pixel 0 on position 6
	or.b	D0,D2
	or.b	D2,D7			; P7 P6 nn nn P3, P2, P1, P0

	swap.w	D2			; Original P6 pixel 0, P7 pixel 0
*					  P6 pixel 0, P7 pixel 0 in D2.w

	move.b	D2,D0			; P4 pixel 0 in D0
	lsr.w	#8,D2			; Get P5 pixel 0 on byte position
	lsr.b	#2,D0			; P4 pixel 0 on position 5
	lsr.b	#3,D2			; P5 pixel 0 on position 4
	or.b	D0,D2
	or.b	D2,D7			; P7, P6, P5, P4, P3, P2 P1 P0

* --------------------

	move.b	D3,D0			; P3 pixel 0 in D0.b
	lsr.w	#8,D3			; Get P2 pixel 0 on byte position in D1.b
	lsr.b	#4,D0			; P3 pixel 0 on position 3
	lsr.b	#5,D3			; P2 pixel 0 on position 2
	or.b	D0,D3
	move.b	D3,D5			; Half lower nibble in D7 (bits 3 and 2)	

	swap.w	D3			; Original P2 pixel 0, P3 pixel 0, P0 pixel 0, P1 pixel 0
*					  P0 pixel 0 and P1 pixel 0 in D1.w

	move.b	D3,D0			; P1 pixel 0 in D0
	lsr.w	#8,D3			; Get P1 pixel 0 on byte position
	lsr.b	#6,D0			; P1 pixel 0 on position 1
	lsr.b	#7,D3			; P0 pixel 0 on position 0
	or.b	D0,D3
	or.b	D3,D5			; P3 P2 P1 P0

* --------------------

* Original P4 pixel 0 bit 4, P5 pixel 0 bit 5 , P6 pixel 0 bit 6, P7 pixel 0 bit 7

	move.b	D4,D0			; P7 pixel 0 in D0
	lsr.w	#8,D4			; Get P6 pixel 0 on byte position
*	lsr.b	#0,D0			; P7 pixel 0 on position 7
	lsr.b	#1,D4			; P6 pixel 0 on position 6
	or.b	D0,D4
	or.b	D4,D5			; P7 P6 nn nn P3, P2, P1, P0

	swap.w	D4			; Original P6 pixel 0, P7 pixel 0
*					  P6 pixel 0, P7 pixel 0 in D2.w

	move.b	D4,D0			; P4 pixel 0 in D0
	lsr.w	#8,D4			; Get P5 pixel 0 on byte position
	lsr.b	#2,D0			; P4 pixel 0 on position 5
	lsr.b	#3,D4			; P5 pixel 0 on position 4
	or.b	D0,D4
	or.b	D4,D5			; P7, P6, P5, P4, P3, P2 P1 P0

	lsl.w	#8,D5
	or.w	D5,D7

.store
	move.w	D7,D5			; INDEX
	add.l	D5,D5			; Index * 2
	add.l	D5,D7			; = Index * 3
	
	move.b	0(A5,D7.l),(A0)+	; Colour value R
	move.b	1(A5,D7.l),(A0)+	; Colour value G
	move.b	2(A5,D7.l),(A0)+	; Colour value B


* Repeat GetPixelColour until a complete byte (8 pixel) is worked out...
.repeat
	move.l	(sp)+,D0

	move.l	A1,D1
	move.l	A2,D2
	move.l	A3,D3
	move.l	A4,D4

.thejump
	addi.l	#28,D0
	move.l	D0,-(sp)

	jmp	(pc,D0.w)		; Call one of the masks below depending on value in D0

.end
	move.l	(sp)+,D0		; Counting 2
	rts				; Counting 4

.mask1					; Counting 6 :: (-22) = (+6 - +28 = -22) -> 1st offset to PC to reach this (.mask1)
	move.l	#$40404040,D0		; -- Each mask has got 19 instruction surrounded by 28 bytes code
	and.l	D0,D1			; bit 1 of plane 0,1,2,3
	and.l	D0,D2			; bit 1 of plane 4,5,6,7
	and.l	D0,D3
	and.l	D0,D4
	moveq	#1,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask2					; 26
	move.l	#$20202020,D0
	and.l	D0,D1			; bit 2 of plane 0,1,2,3
	and.l	D0,D2			; bit 2 of plane 4,5,6,7
	and.l	D0,D3			; bit 2 of plane 4,5,6,7
	and.l	D0,D4			; bit 2 of plane 4,5,6,7
	moveq	#2,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask3					; 46
	move.l	#$10101010,D0
	and.l	D0,D1			; bit 3 of plane 0,1,2,3
	and.l	D0,D2			; bit 3 of plane 4,5,6,7
	and.l	D0,D3			; bit 3 of plane 4,5,6,7
	and.l	D0,D4			; bit 3 of plane 4,5,6,7
	moveq	#3,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask4					; 66
	move.l	#$08080808,D0
	and.l	D0,D1			; bit 4 of plane 0,1,2,3
	and.l	D0,D2			; bit 4 of plane 4,5,6,7
	and.l	D0,D3			; bit 4 of plane 4,5,6,7
	and.l	D0,D4			; bit 4 of plane 4,5,6,7
	moveq	#4,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask5					; 86
	move.l	#$04040404,D0
	and.l	D0,D1			; bit 5 of plane 0,1,2,3
	and.l	D0,D2			; bit 5 of plane 4,5,6,7
	and.l	D0,D3			; bit 5 of plane 4,5,6,7
	and.l	D0,D4			; bit 5 of plane 4,5,6,7
	moveq	#5,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask6
	move.l	#$02020202,D0
	and.l	D0,D1			; bit 6 of plane 0,1,2,3
	and.l	D0,D2			; bit 6 of plane 4,5,6,7
	and.l	D0,D3			; bit 6 of plane 4,5,6,7
	and.l	D0,D4			; bit 6 of plane 4,5,6,7
	moveq	#6,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask7
	move.l	#$01010101,D0
	and.l	D0,D1			; bit 7 of plane 0,1,2,3
	and.l	D0,D2			; bit 7 of plane 4,5,6,7
	and.l	D0,D3			; bit 7 of plane 4,5,6,7
	and.l	D0,D4			; bit 7 of plane 4,5,6,7
	moveq	#7,D0
	lsl.l	D0,D1
	lsl.l	D0,D2
	lsl.l	D0,D3
	lsl.l	D0,D4
	bra.w	.GetPixelColour

.mask8					; Does not exists!!!
	bra.w	.end

_CLUT16oRGB16end
	OPT	P=68000

***********************************
* ONIX 02.10.'91
*
* MakeCounteven
*
* Inputs: D0 - value
* Results: D0 - value
*

_MakeCountEven
	addq.l	#7,D0
	andi.l	#-8,D0
	rts

********************************
*
* Filter ANSI-escape code.
*
* Inputs: none
* Results: none
*

_IgnoreSettings
	movea.l	_TextPtr(A5),A0		; Address file in memory
	addq.l	#2,A0			; Overread #$200A
	move.l	_FileSize(A5),D0	; Length of this file
	moveq	#0,D1			; Amount lines

1$
	subq.l	#1,D0			; Length -1
	bmi.s	.done

	cmpi.b	#10,(A0)+		; LineFeed?
	beq.s	6$			; If so...

	cmpi.b	#12,-1(A0)		; ANSI-sequence?
	beq.s	5$			; If so...

	cmpi.b	#13,-1(A0)		; LineFeed?
	beq.s	5$			; If not...

2$
	cmpi.b	#31,-1(A0)
	bhi.s	1$

	cmpi.b	#27,-1(A0)
	beq.s	1$

	cmpi.b	#8,-1(A0)
	bls.s	3$	

	bra.s	1$

3$
	move.b	#' ',-1(A0)
	bra.s	1$

.done
	move.l	D1,_LinesInFile(A5)	; Lines in file
	bra.s	_SetTitle

5$
	move.b	#10,-1(A0)		; LineFeed instead of ANSI!
6$
	addq.l	#1,D1
	bra.s	1$
************************************
*
* Make title for main-window
*
* Inputs: none
* Results: none
*

_SetTitle
	move.l	A2,-(sp)
	lea	_WindowTitle(A5),A2	; Address buffer
	lea	_FIB(A5),A0		; Address FileInfoBlock
	addq.l	#8,A0			; Get the name of the file
1$
	move.b	(A0)+,(A2)+		; Copy the file's name
	tst.b	(A0)
	bne.s	1$
	move.b	#' ',(A2)+		; Write Blank
	move.b	#'(',(A2)+
	movea.l	A2,A0			; Address buffer
	move.l	_LinesInFile(A5),D0	; Number of lines in file
	bsr.w	_comdec			; Convert count into ascii
	move.b	#' ',(A0)+		; Write String ' Lines)  Current line: '
	move.b	#'L',(A0)+
	move.b	#'i',(A0)+
	move.b	#'n',(A0)+
	move.b	#'e',(A0)+
	move.b	#'s',(A0)+
	move.b	#')',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#'C',(A0)+
	move.b	#'u',(A0)+
	move.b	#'r',(A0)+
	move.b	#'r',(A0)+
	move.b	#'e',(A0)+
	move.b	#'n',(A0)+
	move.b	#'t',(A0)+
	move.b	#' ',(A0)+
	move.b	#'l',(A0)+
	move.b	#'i',(A0)+
	move.b	#'n',(A0)+
	move.b	#'e',(A0)+
	move.b	#':',(A0)+
	move.b	#' ',(A0)+
	move.l	A0,_PtrToWTitle(A5)	; Remember current buffer address

	movea.l	_IntuitionBase(A5),A6
	movea.l	_WindowPtr(A5),A0
	lea	_WindowTitle(A5),A1	; Address new window title
	lea	_WindowName(pc),A2	; Address new screen title
	jsr	_LVOSetWindowTitles(A6)	; Set window and screen title

	movea.l	(sp)+,A2	
	rts

_ComLine
	tst.l	_TextPtr(A5)		; File in memory?
	beq.w	2$			; No...

	tst.b	_AudGadget(A5)		; We make a sound audible, thus no text and lines!
	bne.w	2$

	move.l	A2,-(sp)

	movea.l	_PtrToWTitle(A5),A0	; Save current buffer address for later
	move.l	_Line(A5),D0		; Current line
	bsr.w	_comdec
	move.b	#' ',(A0)+		; Write blanks...
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	clr.b	(A0)			; End of window-title

	movea.l	_GfxBase(A5),A6
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_BorderRPort(A0),A2	; RastPort


	move.w	_BgPen(A5),D0		; Backgroundcolour of window's titel bar
	movea.l	A2,A1
	jsr	_LVOSetBPen(A6)

	moveq	#1,D0			; Foregroundcolour
	movea.l	A2,A1
	jsr	_LVOSetAPen(A6)

	movea.l	rp_BitMap(A2),A0	; Bitmap for the title
	cmpi.b	#1,bm_Depth(A0)		; Only one bitplane used?
	bne.s	.normal			; No, more.

	moveq	#0,D0			; Because of the inversed title bar
	movea.l	A2,A1
	jsr	_LVOSetAPen(A6)

.normal
	move.b	#RP_JAM2,D0
	movea.l	A2,A1
	jsr	_LVOSetDrMd(A6)

	moveq	#30,D0			; X
	moveq	#1,D1			; Y
	movea.l	A2,A1
	add.w	62(A2),D1		; TxBaseLine
	jsr	_LVOMove(A6)

	lea	_WindowTitle(A5),A0
	moveq	#-1,D0
1$
	tst.b	(A0)+
	dbeq	D0,1$
	not.l	D0
	lea	_WindowTitle(A5),A0
	movea.l	A2,A1
	jsr	_LVOText(A6)
	movea.l	(sp)+,A2
2$
	rts

**********************************************
*
* Size window to maximum "!?!?|?" .
*
* Inputs: none
* Results: none
*

_EnlargeWindow
	movem.l	D0-D3/A0-A2/A6,-(sp)
	movea.l	_IntuitionBase(A5),A6
	movea.l	_WindowPtr(A5),A0
	movea.l	A0,A2
	lea	_WindowRecord(A5),A1
	move.w	wd_LeftEdge(A0),D0
	move.w	wd_TopEdge(A0),D1
	neg.w	D0			; Place it to 0,
	neg.w	D1			; 0
	add.w	(A1),D0			; leftEdge
	add.w	nw_TopEdge(A1),D1	; topEdge
	jsr	_LVOMoveWindow(A6)	; Move window to 0,0 or to user specified X- and Y-position

	bsr.s	1$			; Wait for intuition timer tick
	movea.l	A2,A0			; Intuition-Engage-Window-Record
	move.w	wd_Width(A0),D2		; Current window-width
	move.w	wd_Height(A0),D3	; Current window-height

	lea	_WindowRecord(A5),A1	; Address window-record
	move.w	nw_Width(A1),D0		; User's width
	move.w	nw_Height(A1),D1	; Users's height
	sub.w	D2,D0			; Substract
	sub.w	D3,D1
	jsr	_LVOSizeWindow(A6)	; Enlarge? window
	movem.l	(sp)+,D0-D3/A0-A2/A6

	bsr.s	1$			; Wait

	bsr.w	_SetPageWidthAndLen
	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

1$
	movem.l	D0-D3/A0-A3/A6,-(sp)
	moveq	#6,D1			; 6/60 seconds = 1/10 second == int. timer tick
	movea.l	_DOSBase(A5),A6
	jsr	_LVODelay(A6)
	movem.l	(sp)+,D0-D3/A0-A3/A6
	rts

*******************************************************************
*
* Format text, display that text in a window, get Gadget-status and
* return.
*
* Inputs: Stack - reverse arguments on stack
* Results: D0 = NULL = FALSE , D0 ~NULL = OK
*

	IFD	__G2
	OPT	OW-			; Devpac: Don't display optimisation warnings
	ENDC

_FmtDisplay

     STRUCTURE	printfBuf,0
	STRUCT	_Cnt,4			; Counter for number of chars
	STRUCT	_Buffer,512		; Room for max. 511 chars
	LABEL	_Args			; Dynamic wide
	LABEL	_pfbso

.printf
	movem.l	D2-D6/A2-A3,-(sp)
	movea.l	32(sp),A0		; Pointer to the string which should be formatted
	moveq	#-1,D1			; Dummy-counter
	moveq	#0,D0			; Counter for arguments
0$
	cmpi.b	#'%',(A0)		; Argument?
	bne.s	.NoArg			; No...
	addq.w	#1,D0			; Argument +1
.NoArg
	tst.b	(A0)+			; End of string?
	dbeq	D1,0$			; If not

	lsl.l	#2,D0			; * 4 == longwords
	addi.l	#_pfbso,D0		; 4 bytes count, plus buffer
	addq.l	#7,D0
	andi.l	#-8,D0			; Align size
	move.l	D0,D5			; Save size
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,D4			; Address table
	beq.s	3$			; Upon error

	movea.l	32(sp),A0		; Pointer to string
	lea	36(sp),A1		; Pointer to 1. argument
	movea.l	D4,A2			; Address table
	lea	_Args(A2),A2		; Address arguments-buffer (up from 516)

	moveq	#-1,D1			; Dummy-counter
	bra.s	1$

* --    #############  -- *
.skip
	addq.l	#2,A0			; Overread both %-chars
	subq.w	#2,D1			; 2 chars less in text
	bmi.s	3$			; Upon error

* --- Here we start! --- *
1$
	cmpi.b	#'%',(A0)		; Argument?
	bne.s	2$			; No
	cmpi.b	#'%',1(A0)		; or only to display %-char?
	beq.s	.skip			; If so, overread both %-chars
	addq.l	#1,A0			; Else only one %-char
	subq.w	#1,D1			; Counter -1
.getType
	cmpi.b	#'b',(A0)		; Argument = BCPL?
	beq.s	.typeFound		; If so
	cmpi.b	#'d',(A0)		; Decimal?
	beq.s	.typeFound.1
	cmpi.b	#'x',(A0)		; Sedicimal?
	beq.s	.typeFound.1
	cmpi.b	#'s',(A0)		; String?
	beq.s	.typeFound
	cmpi.b	#'c',(A0)		; One char?
	beq.s	.typeFound.1
*
** Because an argument can look like this: '%-08ld' we only search for the
** valid description of the argument, here 'd' in a loop.
*
	tst.b	(A0)+			; Search further
	dbeq	D1,.getType

	bra.s	3$			; Upon error, string without end of argument

.typeFound.1
	cmpi.b	#'l',-1(A0)		; Longword?
	beq.s	.typeFound		; then the other routine
	move.l	(A1),D0			; Get argument (ever longword)
	move.w	D0,(A2)+		; write down for Exec only a word
	addq.l	#4,A1			; Pointer to following argument
	bra.s	2$			; and do it normal
.typeFound
	move.l	(A1),(A2)+		; Argument-contents into buffer
	addq.l	#4,A1			; see above
2$
	tst.b	(A0)+			; Search for NULL-byte
	dbeq	D1,1$
	bra.s	.FmtString		; == End of string, now format string
3$
	moveq	#0,D6			; Return error
.printf_end
	tst.l	D4			; Address table?
	beq.s	4$
	movea.l	D4,A1			; Address table
	move.l	D5,D0			; Size table
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)		; Free table
4$
	move.l	D6,D0
	movem.l	(sp)+,D2-D6/A2-A3
	rts


.FmtString
	movea.l	32(sp),A0		; Pointer to unformatted string
	movea.l	D4,A3			; Address table
	lea	_Args(A3),A1		; Address arguments-buffer
	lea	.Hook(pc),A2		; Call-Back-Routine
*	movea.l	A3,A3			; Address table already in A3
	movea.l	_SysBase(A5),A6		; Base Exec
	jsr	_LVORawDoFmt(A6)	; Format the string

	movea.l	D4,A1
	lea	_Buffer(A1),A0		; Address formatted text in buffer
	move.l	_Cnt(A1),D0		; Size of text
	beq.s	.okEnd			; If zero
	bsr.s	_DisplayError		; else print text to window
	move.l	D0,D6
.okEnd
	bra.s	.printf_end


.Hook
* D0 == char, returned by RawDoFmt()
* A3 == Pointer to table, returned by RawDoFmt()
	movem.l	D1/A0,-(sp)
	lea	_Buffer(A3),A0		; Buffer for formatted text
	move.l	_Cnt(A3),D1		; Number of chars that are in buffer
	move.b	D0,0(A0,D1.w)		; Store current
	addq.l	#1,_Cnt(A3)		; Counter plus 1
	cmpi.l	#510,D1			; 511 chars in buffer?
	bls.s	.ok			; If ok.
	subq.l	#1,_Cnt(A3)		; One too far
	clr.b	0(A0,D1.w)		; Clear byte
.ok	
	movem.l	(sp)+,D1/A0
	rts

	IFD	__G2
	OPT	OW+
	ENDC

******************************************************************
*
* Open in the middle of a screen a window where we will display
* a text.
* 
*
* Inputs: A0 - text
* Results: D0 - NULL == ABORT, else OK


_DisplayError
	movem.l	D1-D4/A0-A4,-(sp)

	movea.l	A0,A4			; Save text for later
	lea	_ErrWindowStruc(A5),A0

	tst.l	_ScreenPtr(A5)
	bne.s	.GotScreen

	movea.l	_IntuitionBase(A5),A1
	movea.l	ib_ActiveScreen(A1),A1
.GotScreen
	movea.l	_ScreenPtr(A5),A1
	move.l	A1,nw_Screen(A0) 	; ScreenPtr->WindowRecord

* Center window on screen.
	move.w	sc_Width(A1),D0		; Width of screen
	subi.w	#320,D0			; Width of ErrorWindow
	lsr.w	#1,D0			; Half
	move.w	D0,(A0)			; == leftEdge

	move.w	sc_Height(A1),D0	; Height of screen
	subi.w	#100,D0			; Height of ErrorWindow
	lsr.w	#1,D0			; Half
	move.w	D0,nw_TopEdge(A0)	; == topEdge

* Open the window.
	clr.l	nw_FirstGadget(A0)
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOOpenWindow(A6)
	move.l	D0,_ErrWindowPtr(A5)
	beq.w	.NoErrWindow		; Upon error
	movea.l	D0,A0			; Window
	movea.l	wd_RPort(A0),A3		; ^RastPortPtr

	bsr.w	_InitGadgets		; Init gadgets
	lea	_Gad1(A5),A1		; First gadget
	moveq	#0,D0			; Begin with number zero
	moveq	#-1,D1			; All gadgets
	moveq	#0,D2
	movea.l	D2,A2			; No requester
	jsr	_LVOAddGList(A6)	; Set gadgets to window
	lea	_Gad1(A5),A0		; Gadgets
	movea.l	_ErrWindowPtr(A5),A1	; Window
	moveq	#0,D2
	movea.l	D2,A2			; No requester
	jsr	_LVORefreshGList(A6)	; Draw gadgets

* Set pens.
	moveq	#1,D0			; 1. foregroundcolour
	movea.l	A3,A1			; RastPort
	movea.l	_GfxBase(A5),A6
	jsr	_LVOSetAPen(A6)		; Set text-pen

* Fill background of window with 1. foreground colour.
	movea.l	_ErrWindowPtr(A5),A0
	movea.l	A3,A1			; RastPort
	move.w	#0,D0			; leftEdge
	move.w	#0,D1			; topEdge
	move.w	#319,D2			; width
	move.w	#79,D3			; height

	moveq	#0,D4
	move.b	wd_BorderLeft(A0),D4
	add.w	D4,D0
	addq.w	#1,D0
	move.b	wd_BorderRight(A0),D4
	sub.w	D4,D2
	subq.w	#1,D2
	move.b	wd_BorderTop(A0),D4
	add.w	D4,D1
	addq.w	#1,D1
	move.b	wd_BorderBottom(A0),D4
	sub.w	D4,D3	
	subq.w	#1,D3
	movem.l	D0/D2,-(sp)		; Save coordinates
	jsr	_LVORectFill(A6)	; Draw rectangle

	move.w	#2,D0			; 2. Foregroundcolour
	movea.l	A3,A1			; RastPort
	jsr	_LVOSetAPen(A6)		; Set text-pen

	movea.l	A3,A1			; RastPort
	move.w	#RP_JAM1,D0
	jsr	_LVOSetDrMd(A6)

	movem.l	(sp)+,D0/D2		; Get coordinates

*	D0 contains X-Offset
	moveq	#76,D1			; Y-Offset
	movea.l	A3,A1
	jsr	_LVOMove(A6)
	move.l	D2,D0			; D2 == X-Offset - to D0
	moveq	#76,D1			; Y-Offset
	movea.l	A3,A1
	jsr	_LVODraw(A6)

	moveq	#0,D0			; X-, Y-offsets = 0
	move.l	D0,D1
	move.b	(A4)+,D1		; Y-Offset out of text
	movea.l	A3,A1			; RastPortPtr
	jsr	_LVOMove(A6)		; Set Gfx-cursor

	move.l	A4,-(sp)		; Text
	moveq	#0,D0
	move.w	rp_TxHeight(A3),D0
	addq.w	#2,D0			; Spacing
	sub.w	rp_TxBaseline(A3),D0
	move.l	D0,-(sp)
	move.l	_ErrWindowPtr(A5),-(sp)	; Window
	bsr.w	_CenterPage		; CenterText (struct Window *, ULONG Spacing, char *)
	lea	12(sp),sp		; Restore stack

.Wait
	movea.l	_ErrWindowPtr(A5),A0	; WindowPointer
	movea.l	wd_UserPort(A0),A0	; MsgPort
	movea.l	A0,A3			; save it
	movea.l	_SysBase(A5),A6
	jsr	_LVOWaitPort(A6)	; Sleep

	movea.l	A3,A0			; MsgPort
	jsr	_LVOGetMsg(A6)		; Get the message
	tst.l	D0
	beq.s	.Wait
	movea.l	D0,A1			; into A1
	movea.l	A1,A2
	move.l	im_Class(A2),D2
	move.w	im_Code(A2),D3
	swap	D3
	move.w	im_Qualifier(A2),D3
	jsr	_LVOReplyMsg(A6)

	cmpi.l	#$40,D2			; GadgetUp?
	beq.s	.Gadget

	btst.l	#6,D3			; Left AMIGA (Commodore) key?
	beq.s	.Wait			; If not...

	swap	D3

	cmpi.b	#53,D3
	beq.s	.KeyB

	cmpi.b	#52,D3
	beq.s	.KeyV

	bra.s	.Wait
.KeyB
	moveq	#0,D3
	bra.s	.EndDisplayError
.KeyV
	moveq	#1,D3
	bra.s	.EndDisplayError
.Gadget
	tst.l	im_IAddress(A2)
	beq.s	.Wait			; No gadget?
	movea.l	im_IAddress(A2),A0	; Get gadget's address
	move.w	gg_GadgetID(A0),D3	; Get my ID

.EndDisplayError
	movea.l	_ErrWindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOCloseWindow(A6)
	move.w	D3,D0			; im_Code (gadget's ID)
	cmpi.w	#1,D0			; Left gadget (OK) ?
	beq.s	.NoErrWindow		; If so...
	moveq	#0,D0			; It was the right one
.NoErrWindow
	movem.l	(sp)+,D1-D4/A0-A4
	rts

*
* void CenterPage( struct Window *Window, ULONG Spacing, STRPTR TextPage );
*

_CenterPage
	movem.l	D2-D3/A2-A3,-(sp)

	movea.l	_GfxBase(A5),A6
	movea.l	20(sp),A0		; Window
	movea.l	50(A0),A3		; RastPort
	moveq	#0,D3
	move.l	24(A0),D0		; Window flags
	btst.l	#10,D0			; gimme zero zero ?
	bne.s	0$			; if gzz
	move.w	8(A0),D3		; Window-width
	lsr.w	#1,D3			; == half window width
	bra.s	1$
0$
	move.w	112(A0),D3		; gzzWidth
	lsr.w	#1,D3			; == half window width
1$
	movea.l	28(sp),A2		; Text
2$
	movea.l	A2,A0
	moveq	#-1,D2			; Counter
3$
	tst.b	(A0)			; End?
	beq.s	4$
	cmpi.b	#10,(A0)+		; Search for line-end
	dbeq	D2,3$

	move.l	A0,-(sp)		; Save pointer to next line

	not.l	D2			; Compute length
	move.l	D2,D0			; Length in number of chars
	movea.l	A3,A1			; RastPort
	movea.l	A2,A0			; Text
	jsr	_LVOTextLength(A6)
	move.l	D0,D1			; Length in pixels 
	lsr.w	#1,D1			; == half length
	move.l	D3,D0			; Half window-width
	sub.w	D1,D0			; minus half text-width == X-offset for 1. char
	move.w	38(A3),D1		; Current Y
	add.w	62(A3),D1		; plus rp_TxBaseline
	movea.l	A3,A1			; RastPort
	jsr	_LVOMove(A6)

	movea.l	(sp)+,A0		; Get pointer to next line

	exg.l	A0,A2			; A0 == now old position, A2 new position of text
	move.l	D2,D0			; TextLength in number of chars
	movea.l	A3,A1			; RastPort	
	jsr	_LVOText(A6)

	move.w	38(A3),D1		; Current Y-Offset
	move.l	24(sp),D0		; Spacing (user's Y-offset)
	add.w	D0,D1			; Next line offset (Y)
	move.w	36(A3),D0		; Current X-Offset
	movea.l	A3,A1			; RastPort
	jsr	_LVOMove(A6)

	bra.s	2$
4$
	movem.l	(sp)+,D2-D3/A2-A3
	rts

***************************************
*
* Convert long-value into ascii-string.
*
* Inputs: D0 - value (ulong), A0 - buffer
* Result: none
*

_comdec
	movem.l	D2/A2,-(sp)
	move.l	D0,D2
	lea	_Divutable(pc),A2
	movea.l	A0,A1
	moveq	#9,D0

1$
	moveq	#48,D1
2$
	addq.b	#1,D1
	sub.l	(A2),D2
	bcc.s	2$
	subq.b	#1,D1
	add.l	(A2)+,D2

	cmpi.b	#'0',D1
	bne.s	3$
	cmpi.b	#0,D0
	beq.s	3$
	cmpa.l	A1,A0
	bne.s	3$

	dbf	D0,1$
3$
	move.b	D1,(A0)+
4$
	dbf	D0,1$
	clr.b	(A0)
	movem.l	(sp)+,D2/A2
	rts

*************************************************************
*
* Print file to ???.
*
* Inputs: D0 - length datas, A0 - filename, A1 - startaddress
* Results: none
* Note: The datas are not stored in once to the device (PRT:/DFx:)
* because when a disk-error occurs, we get the chance to terminate
* saving/printing earlier, which in fact will not destroy the whole
* disk as it is possible under OS1.x .

_PrintFile
	movem.l	D2-D5/A2,-(sp)
	move.l	D0,D5			; Save length
	movea.l	A1,A2			; Save address datas
	move.l	A0,D1			; Name
	move.l	#MODE_NEWFILE,D2	; Mode: New
	movea.l	_DOSBase(A5),A6
	jsr	_LVOOpen(A6)
	move.l	D0,D4			; FileHandle
	beq.s	.PrintOpenError
3$
	subi.l	#4096,D5		; Length -4096 bytes
	bcs.s	1$			; If there aren't at least 4096 chars to store
	move.l	#4096,D3		; Number of chars to write: 4096
	bra.s	2$			; Go and write these chars...
1$
	addi.l	#4096,D5		; Add these - now D5 contains again the rest to store
	move.l	D5,D3			; Number of chars to store
	moveq	#0,D5			; Indicates: no chars anymore for next loop
2$
	move.l	D4,D1			; FileHandle
	move.l	A2,D2			; Address
	jsr	_LVOWrite(A6)
	tst.l	D0
	bmi.s	.WriteError
	lea	4096(A2),A2		; Increase address by 4096 bytes
	tst.l	D5			; Rest there?
	bne.s	3$			; If there...
	move.l	D4,D1			; FileHandle
	jsr	_LVOClose(A6)		; Close file/prt: or something like that

.PrintFileEnd
	movem.l	(sp)+,D2-D5/A2
	rts
.PrintOpenError
	jsr	_LVOIoErr(A6)
	bsr.w	_SetError
	lea	_OpenPrintErrTxt(pc),A0
	bsr.w	_DisplayError
	bra.s	.PrintFileEnd
.WriteError
	movea.l	_DOSBase(A5),A6		; - Because of a bug in DOS v39
*					  we have to restore DOSBase....
	jsr	_LVOIoErr(A6)
	bsr.w	_SetError
	move.l	D4,D1
	jsr	_LVOClose(A6)
	lea	_WriteErrTxt(pc),A0
	bsr.w	_DisplayError
	bra.s	.PrintFileEnd	

************************
*
* Erase window contents.
*
* Inputs: none
* Results: none
*

_ClearWindow
	lea	_ConBuffer(A5),A0
	move.l	#$9B489B4A,(A0)		; Cursor Home & erase to end of display
	moveq	#4,D0
	bra.w	_ConOut_Rel

*****************************************************************
*
* Search for overgiven string....
*
* Will use the console.device as input stream and also for output.
* Searching is done only forward and also case insensitive.
*

_SearchSequence
	movem.l	D2-D4/A2-A4,-(sp)

	move.l	#$200,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)

	bsr.s	_ClearWindow

	tst.l	_TextPtr(A5)
	beq.s	.end

	lea	_ConBuffer(A5),A0
	move.w	#$9B48,(A0)		; Cursor Home
	moveq	#2,D0
	bsr.w	_ConOut_Rel

	lea	_SearchText(pc),A0
	lea	_SearchTextEnd(pc),A1	; Address end of help-text
	suba.l	A0,A1			; == length text
	move.l	A1,D0			; into D0
	bsr.w	_ConOut_Reloc		; Output

	bsr.w	_CursorOn

	lea	_IOReqString(A5),A3	; Buffer to store the complete string the user enters
	moveq	#0,D3			; Amount of already stored chars
	moveq	#0,D4			; Position in textbuffer

	movea.l	A3,A0			; Clear IOReqString
	move.w	#256-1,D0
.clear
	clr.b	(A0)+
	subq.w	#1,D0
	bcc.s	.clear

	lea	_CharBuffer(A5),A0	; At least, two chars wide (only for console reading)
	clr.l	(A0)			; Indicator: Nothing entered!

.loop
	moveq	#2,D0
	lea	_CharBuffer(A5),A0
	lea	_ReadIo(A5),A1
	move.l	D0,IO_LENGTH(A1)	; Number of chars to read
	move.l	A0,IO_DATA(A1)
	move.b	#IOF_QUICK,IO_FLAGS(A1)
	move.w	#CMD_READ,IO_COMMAND(A1) ; Command READ
	movea.l	_SysBase(A5),A6
	jsr	_LVODoIO(A6)		; Send command

	lea	_CharBuffer(A5),A0	; Get the chars
	tst.b	(A0)			; Too bad, no char
	beq.s	.loop
	
	lea	_CharBuffer(A5),A0	; Get address of buffer
	move.b	(A0),D0			; Get the char (or sequencer <CSI> ($9B))
	move.b	1(A0),D1		; When D0 sequencer, D1 keycode

	clr.l	(A0)			; Indicator: No char stored!
	bra.s	.SetString		; Parse that char...


* ------ finish (not found) ------ *
.end
	bsr.w	_CursorOff

	move.l	#$8|$200|$400,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)

	movem.l	(sp)+,D2-D4/A2-A4

	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

***********************************
*
* React to read char
*
* INPUTS:	D0 - char
*	or	D0 - sequence ($9B)
*	then	D1 - char

.SetString
	cmpi.b	#13,D0			; Carridge return?
	beq.w	.done
	cmpi.b	#8,D0			; Backspace
	beq.s	.BackSpace
	cmpi.b	#$7F,D0			; DEL
	beq.s	.Delete
	cmpi.b	#$9B,D0			; <CSI> (sequence)
	beq.w	.Sequencer
	cmpi.b	#$1B,D0			; ESC
	beq.w	.Escape

* ############ -------- Any other char -------- *
	cmpi.b	#255,D3			; Maximum editable chars
	beq.w	.loop
	move.b	D0,D2			; The char
	bsr.w	_InsertChar		; Store char (D2) to TextBuffer
	bsr.w	_PrintChar
	bra.w	.loop			; and normal...

* ############ -------- Delete last character -------- *
.BackSpace
	tst.l	D3			; At least one char stored?
	beq.w	.loop	

	tst.l	D4
	beq.w	.loop

	cmpi.b	#9,-1(A3,D4.l)
	bne.s	.donormal

	moveq	#0,D2
	bsr.w	_MoveTAB
	bsr.w	_RemChar
	bra.s	.delete			; <- see there...

* ------------------------------ *

.donormal
	lea	_ConBuffer(A5),A0
	move.w	#$9B44,(A0)		; <CSI>D
	moveq	#2,D0
	bsr.w	_ConOut_Rel

	subq.l	#1,D4
	bsr.w	_RemChar

	bra.s	.delete			; <- see there...

* ############ ------ Delete current character ------ *
.Delete
	tst.l	D3
	beq.w	.loop

	cmp.l	D3,D4
	beq.w	.loop

	bsr.w	_RemChar

.delete
	tst.l	D4
	beq.s	.dprint			; Start of line (first char)
	lea	_ConBuffer(A5),A0
	move.w	#$9B44,(A0)		; <CSI>D
	moveq	#2,D0
	bsr.w	_ConOut_Rel
.dprint
	bsr.w	_PrintChar

	cmp.l	D3,D4
	bne.s	.chardeleted

	lea	_ConBuffer(A5),A0
	move.w	#$9B50,(A0)		; <CSI>1D
	moveq	#2,D0
	bsr.w	_ConOut_Rel

.chardeleted
	bra.w	.loop


* ############ ------ Cursor keys or something like that picked... ------ *
.Sequencer	; D0=$9B, D1=xx,
*	 where xx is:
*	HELP		$3F
*	CursorLeft 	$44
*	CursorRight	$43
*	CursorUp	$41
*	CursorDown	$42
	tst.l	D3
	beq.w	.loop

	cmpi.b	#$44,D1
	beq.s	.left
.right
	cmp.w	D3,D4
	beq.w	.loop

	moveq	#~0,D2
	cmpi.b	#9,0(A3,D4.l)
	bne.s	.charright
	bsr.w	_MoveTAB
	bra.w	.loop
.charright
	addq.l	#1,D4
	lea	_ConBuffer(A5),A0
	move.w	#$9B43,(A0)		; <CSI>C
	moveq	#2,D0
	bsr.w	_ConOut_Rel	
	bra.w	.loop
* ------------------------------ *

.left
	tst.w	D4
	beq.w	.loop

	moveq	#0,D2
	cmpi.b	#9,-1(A3,D4.l)
	bne.s	.charleft
	bsr.w	_MoveTAB
	bra.w	.loop

.charleft
	subq.l	#1,D4
	lea	_ConBuffer(A5),A0
	move.w	#$9B44,(A0)		; <CSI>D
	moveq	#2,D0
	bsr.w	_ConOut_Rel
	bra.w	.loop

* ############ ------- Escape key pressed... -------- *
.Escape
	cmpi.b	#255,D3			; Maximum editable chars
	beq.w	.loop
	move.b	#'·',D2
	bsr.w	_InsertChar
	bsr.w	_PrintChar
	bra.w	.loop

* ############ ------- Carridge Return - string complete! ------- *
.done
	tst.l	D3			; If user cancled entering
	beq.w	.end

	clr.b	(A3,D3.l)		; Terminator
	bsr.w	_CursorOff

* ------- Replace '·' (synonym for escape) through escape character ------- *
	lea	_IOReqString(A5),A0	; Buffer with chars...
.escapeSearch
	tst.b	(A0)
	beq.s	.searchStart
	cmpi.b	#'·',(A0)+
	bne.s	.escapeSearch
	move.b	#27,-1(A0)
	bra.s	.escapeSearch

* -------- Search for the overgiven string --------- *
.searchStart
	lea	_IOReqString(A5),A2	; Buffer with chars...
	movea.l	_TextPtr(A5),A3		; Text start
	addq.l	#2,A3			; Overread #$200A
	movea.l	A3,A4
	adda.l	_BufferSize(A5),A4	; Size of chars of text
	subq.l	#4,A4			; Ignore introducing ($200A) and terminator
.search
	move.l	D3,-(sp)
	move.l	A2,-(sp)
	move.l	A3,-(sp)
	bsr.w	_strincmp		; Compare case insensitive strings
	lea	12(sp),sp
	tst.l	D0
	beq.s	.found			; D0 = 0 means ok.

	addq.l	#1,A3			; Else, next char
	cmpa.l	A3,A4			; Check against limit
	bls.s	.notfound		; If out of limit
	bra.s	.search			; Else, search
.found
	move.l	A3,D0			; Found text
	addq.l	#1,D0			; No trouble shooting....
	move.l	D0,_SearchStrPtr(A5)	; There where we can continue if user said "search next"
	move.l	D3,_SearchStrLen(A5)	; Remember length of string to search for

* -------- Search for linestart -------- *
	movea.l	_TextPtr(A5),A0
	addq.l	#2,A0			; Overread #$200A
.searchLF
	cmpi.b	#10,(A3)		; LineFeed (line start)
	beq.s	.foundLineStart
	cmpa.l	A0,A3			; Does it fit?
	bls.s	.notfound
	subq.l	#1,A3			; Else one less char...
	bra.s	.searchLF
.foundLineStart
	move.l	#$8|$200|$400,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)

	move.l	A3,D0
	movem.l	(sp)+,D2-D4/A2-A4

	move.l	D0,-(sp)
	bsr.w	_GetCurrentLine		; Compute the line (last one in window)
	move.l	(sp)+,D6		; First char in window
	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

* ############ ------- Couldn't find the string... ------- *
.notfound
	suba.l	A0,A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVODisplayBeep(A6)

	clr.l	_SearchStrPtr(A5)
	clr.l	_SearchStrLen(A5)

	bra.w	.end

****************************************************************
*
* Move a char which is a tabulator - to the left or to the right
*
* D2	- indicator: zero = leftmove, unequal zero = move right
*

_MoveTAB
	lea	_ConBuffer(A5),A0	; Buffer for created string
	move.b	#$9B,(A0)		;<CSI>
	lea	_IOReqString(A5),A1	; Buffer with chars
	moveq	#12,D0			; Initial column offset, here "Search for: " <- 12 chars
*	For a real editor replace 12 through 0, 'cause of line start...

	tst.b	D2
	beq.s	.leftsetup		; ...because left move cursor
.rightsetup
	move.l	A0,-(sp)
	lea	0(A3,D4.l),A0
	bra.s	.searchtab
.leftsetup
	move.l	A0,-(sp)
	lea	-1(A3,D4.l),A0
.searchtab
	cmpa.l	A0,A1			; Last char before tab?
	beq.s	.gottab			; If found
	addq.w	#1,D0			; Else counter for chars plus 1
	cmpi.b	#9,(A1)			; A tab?
	bne.s	.next1			; If not...
	addq.w	#7,D0			; Else calc position (every time divisible through 8)
	andi.w	#-8,D0
.next1
	addq.l	#1,A1			; Get next char('s position(address))
	bra.s	.searchtab		; And search further
.gottab	; Current position in D0 before tab
	movea.l	(sp)+,A0
	tst.b	D2
	bne.s	.rightmove
.leftmove
	move.b	#'D',D2
	move.l	D0,D1
	addq.l	#8,D1			; Add a char (1) and make width divisible by 8 (7) 
	andi.l	#-8,D1
	sub.l	D0,D1			; Number of space to move left
	subq.l	#1,D4
	bra.s	.write

.rightmove	
	move.b	#'C',D2
	move.l	D0,D1
	addq.l	#8,D1			; Add a char (the tab) and make width divisible by 8 (7) 
	andi.l	#-8,D1
	sub.l	D0,D1
	addq.l	#1,D4

.write
	addi.b	#'0',D1			; Convert it into ASCII
	move.b	D1,1(A0)		; Into ConBuffer
	
	move.b	D2,2(A0)		; <CSI>nD = cursor n positions backward
	moveq	#3,D0			; Three chars for output
	bsr.w	_ConOut_Rel		; Output!

	rts

**************************************************
*
* Print yet entered char to window.
*
* INPUTS:	D3 - amount of chars in TextBuffer
*		D4 - current BufPosition
*
_PrintChar
	cmp.l	D3,D4
	bne.s	.givestring

	tst.l	D3
	beq.s	.erase

	lea	-1(A3,D3),A0		; Address string (including new charcter)
	moveq	#1,D0
	bsr.w	_ConOut_Reloc
	rts

.givestring
	lea	_ConBuffer(A5),A0
	move.w	#$9B4B,(A0)		; <CSI>K [erase to end of line]
	moveq	#2,D0
	bsr.w	_ConOut_Rel

	lea	-1(A3,D4),A0		; Address string (including new charcter)
	move.l	D3,D0			; Length
	move.l	D4,D1			; - minus current position
	addq.l	#1,D0
	bsr.w	_ConOut_Reloc		; Print rest of string

* Because the cursor is at end of line, we have to move it to current BufPosition...
	move.l	D4,-(sp)
	move.l	D3,D4			; End of line = current BufPosition

.loopmove
	moveq	#0,D2			; Indicator: left move
	cmpi.b	#9,-1(A3,D4.l)		; A tab?
	bne.s	.moveleft		; If not...
	bsr.w	_MoveTAB		; Else, move it as tab...
	bra.s	.movedone		; done (for this time)

.moveleft
	subq.l	#1,D4			; BufPosition minus 1
	lea	_ConBuffer(A5),A0
	move.l	#$9B314400,(A0)		; <CSI>1D
	moveq	#3,D0
	bsr.w	_ConOut_Rel		; Move cursor 1 position left

.movedone
	move.l	(sp),D0			; Get original BufPosition
	cmp.l	D0,D4			; reached?
	bne.s	.loopmove		; If not
	addq.l	#4,sp
.done
	rts
.erase
	lea	_ConBuffer(A5),A0
	move.w	#$9B50,(A0)		; <CSI>1D
	moveq	#2,D0
	bsr.w	_ConOut_Rel
	rts

*******************************
*
* Insert a char in text buffer
*
* INPUTS:	D2 - the char to store
*		D3 - amount of currently stored chars
*		D4 - currently used BufPosition
* RESULTS:	D3 - increased by one
*		D4 - increased by one

_InsertChar
	cmp.l	D3,D4
	beq.s	.atend			; It's currently the last char...

	lea	0(A3,D4.l),A0		; Source
	lea	1(A3,D4.l),A1		; Destination
	move.l	D3,D0
	sub.l	D4,D0
	bsr.s	_DupCopy		; Free room at current position in textbuffer
	move.b	D2,0(A3,D4.l)		; and store there the char

	addq.l	#1,D3
	addq.l	#1,D4
	rts
.atend					; Insert char at last position
	move.b	D2,0(A3,D4.l)
	clr.b	1(A3,D4.l)		; Terminator
	addq.l	#1,D3
	addq.l	#1,D4
	rts

*****************************************************
*
* Because Exec function CopyMem() cannot be used when
* "ascended overlay copying" is required,
* we have to make an own, which copies "reverse" the
* datas.
*
* Inputs: A0/A1/D0   -  source/destination/size
*

_DupCopy
	subq.l	#1,D0
.loop
	move.b	0(A0,D0.l),0(A1,D0.l)
	subq.l	#1,D0
	bcc.s	.loop
	rts

******************************************************************
*
* Remove char in text buffer which currently stays on BufPosition
*
* INPUTS:	D3 - currently amount of char in buffer (old length)
*		D4 - current buffers poisition (BufPosition)
* REULTS:	char on BufPosition removed
*		D3 - decreased by one (char removed)
* NOTES:	D4 unchanged...
*

_RemChar
	subq.l	#1,D3			; New size
	move.l	D3,D0			; Amount chars in buffer
	move.l	D4,D1			; Buffers position
	sub.l	D1,D0			; Number of bytes behind BufPosition
	beq.s	.endchar
	bmi.s	.endchar
	lea	1(A3,D4.l),A0		; Source
	lea	0(A3,D4.l),A1		; Destination
	movea.l	_SysBase(A5),A6
	jsr	_LVOCopyMem(A6)
.endchar
	clr.b	0(A3,D3.l)
	rts

****************************************************************
*
* Compare case insensitive string1 and string2 with width-limit.
*
* Input:  string1, string2, num-chars (stackargs)
* Result: D0 = FALSE (0L) if strings are the same.
*

_strincmp	;cargs	string1.l,string2.l, num-chars.l
	move.l	D2,-(sp)
	movea.l	8(sp),A0
	movea.l	12(sp),A1
	move.l	16(sp),D2
	andi.l	#$FFFF,D2
	subq.w	#1,D2
.start
	move.b	(A0)+,D0
	bsr.s	_UpperCase
	move.b	D0,D1
	move.b	(A1)+,D0
	bsr.s	_UpperCase
	tst.b	D0
	bne.s	.tst
	tst.b	D1
	beq.s	.same
.tst
	cmp.b	D0,D1
	bne.s	.differ
	dbf	D2,.start
.same
	move.l	(sp)+,D2
	moveq	#0,D0
	rts
.differ
	move.l	(sp)+,D2
	moveq	#-1,D0
	rts

*********************************************
*
* Change char in D0 to uppercase if possible.
* Supports all ASCII-one characters!
*
* Returns char in D0
*

_UpperCase
	tst.b	D0
	beq.s	.back
	cmpi.b	#96,D0
	bls.s	.back
	cmpi.b	#122,D0
	bls.s	.change
	cmpi.b	#255,D0
	beq.s	.back
	cmpi.b	#223,D0
	bhi.s	.change
	rts
.change
	andi.b	#$DF,D0
.back
	rts


*************************************************
*
* If the N-key is pressed, we are at this point.
* Same as SearchSequence() but without any
* input()...
*
_ContinueSearch
	movem.l	D2/A2-A4,-(sp)

	move.l	#$200,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)

	tst.l	_TextPtr(A5)		; Any text to examine?
	beq.w	.end
	lea	_IOReqString(A5),A0	; Any search string given?
	tst.b	(A0)
	beq.w	.end
	move.l	_SearchStrLen(A5),D2	; Length of search string set?
	beq.w	.end
	tst.l	_SearchStrPtr(A5)	; An address remembered?
	beq.s	.end

	lea	_IOReqString(A5),A2	; String to search for....
	movea.l	_SearchStrPtr(A5),A3	; Address from where to search
	movea.l	_TextPtr(A5),A4		; Address text-start
	addq.l	#2,A4			; Overread #$200A
	adda.l	_BufferSize(A5),A4	; = end of text
	subq.l	#4,A4
.search
	move.l	D2,-(sp)
	move.l	A2,-(sp)
	move.l	A3,-(sp)
	bsr.w	_strincmp
	lea	12(sp),sp
	tst.l	D0
	beq.s	.found
	cmpa.l	A3,A4
	bls.s	.notfound
	addq.l	#1,A3
	bra.s	.search
.found
	move.l	A3,D0
	addq.l	#1,D0
	move.l	D0,_SearchStrPtr(A5)	; Remember address where we found string (plus 1 byte)
	move.l	D2,_SearchStrLen(A5)

	movea.l	_TextPtr(A5),A0		; Address text-start
	addq.l	#2,A0			; Overread #$200A
.searchLF
	cmpi.b	#10,(A3)
	beq.s	.foundLineStart
	cmpa.l	A0,A3			; Does it fit?
	bls.s	.notfound
	subq.l	#1,A3			; Else one less char...
	bra.s	.searchLF
.foundLineStart
	move.l	A3,D0

	movem.l	(sp)+,D2/A2-A4

	move.l	D0,-(sp)
	bsr.s	_GetCurrentLine

	move.l	#$8|$200|$400,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)

	move.l	(sp)+,D6			; First char in window
	bsr.w	_RestoreCurrentPage
	bra.w	_Loop

.notfound
	suba.l	A0,A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVODisplayBeep(A6)

.end
	move.l	#$8|$200|$400,D0
	movea.l	_WindowPtr(A5),A0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVOModifyIDCMP(A6)
	movem.l	(sp)+,D2/A2-A4

	bsr.w	_RestoreCurrentPage
	bra.w	_Loop


******************************************
*
* Compute current line.
*
* Input: D0 - address within text buffer.
*

_GetCurrentLine
	movea.l	_TextPtr(A5),A0
	move.l	D0,A1
	moveq	#0,D1
.cmp
	cmpi.b	#10,(A0)
	beq.s	.add
.tst
	cmpa.l	A0,A1
	beq.s	.found
.next
	addq.l	#1,A0
	bra.s	.cmp
.add
	addq.l	#1,D1
	bra.s	.tst
.found
	moveq	#0,D0
	move.w	_StdPageSize(A5),D0	; Amount of lines in window
	add.l	D0,D1
	move.l	D1,_Line(A5)
	rts


***************************
*
* Display commands summary.
*
* Inputs: none
* Results: none
*

_DisplayHelp
	bsr.w	_SetActionWait		; See there
	bsr.w	_ClearWindow

	lea	_HelpText(pc),A0	; Address help-text
	lea	_HelpTextEnd(pc),A1	; Address end of help-text
	suba.l	A0,A1			; == length text
	move.l	A1,D0			; into D0
	bsr.w	_ConOut_Reloc		; Output

	move.l	A2,-(sp)
1$
	movea.l	_SysBase(A5),A6
	movea.l	_WindowPtr(A5),A2
	movea.l	wd_UserPort(A2),A2
	movea.l	A2,A0
	jsr	_LVOWaitPort(A6)
	movea.l	A2,A0
	jsr	_LVOGetMsg(A6)
	movea.l	D0,A1
	movea.l	D0,A2
	jsr	_LVOReplyMsg(A6)

	cmpi.w	#H_Key+$80,im_Code(A2)	; H-key released?
	bne.s	1$

	movea.l	_WindowPtr(A5),A2
	movea.l	wd_UserPort(A2),A2
	movea.l	A2,A0
	jsr	_LVOWaitPort(A6)	; Wait for any event
	movea.l	A2,A0
	jsr	_LVOGetMsg(A6)
	movea.l	D0,A1
	jsr	_LVOReplyMsg(A6)

	movea.l	(sp)+,A2

	tst.l	_TextPtr(A5)		; Any text there?
	beq.s	2$			; If not
	bsr.w	_RestoreCurrentPage	; Else restore the page
2$
	bra.w	_Loop


**************************
*
* Display the standard....
*
* Inputs: none
* Results: none
*

_About
	lea	_AboutTxt(pc),A0		; I like this...
	bsr.w	_DisplayError
	bra.w	_Loop


****************************************
*
* Display informations about program....
*
* Inputs: none
* Results: none
*

_Info
	move.l	#_TableSize,D0		; Size BSS
	addq.l	#7,D0
	andi.l	#-8,D0			; Aligned size
	move.l	D0,-(sp)

	lea	_startup(pc),A0		; Code start
	subq.l	#4,A0			; Next hunk...
	movea.l	(A0),A0			; BPTR next hunk
	adda.l	A0,A0
	adda.l	A0,A0			; == APTR next hunk
	move.l	-4(A0),D0		; Size next hunk
	subq.l	#8,D0			; Ignore hunk-header (8 bytes)
	move.l	D0,-(sp)		; Size datas-chip

	lea	_Divutable(pc),A0	; Start datas
	lea	_EndDatas(pc),A1	; End datas
	sub.l	A0,A1			; == size datas
	move.l	A1,D0
	addq.l	#3,D0
	andi.l	#-4,D0			; Aligned size (longword)
	move.l	D0,-(sp)

	lea	_startup(pc),A0		; Entry point of program
	lea	_Divutable(pc),A1	; End of code
	suba.l	A0,A1			; == size of code
	move.l	A1,-(sp)

	pea	_InfoTxt(pc)		; Text...
	bsr.w	_FmtDisplay
	lea	20(sp),sp		; Restore stack	
	bra.w	_Loop

*************************
*
* Allow messages for now.
*
* Inputs: none
* Results: none
*

_SetActionWait
	move.l	A0,-(sp)
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	clr.b	MP_FLAGS(A0)
	movea.l	(sp)+,A0
	rts

***********************************
*
* Do not allow any message for now.
*
* Inputs: none
* Results: none
*

_SetNILWait
	move.l	A0,-(sp)
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	move.b	#PA_IGNORE,MP_FLAGS(A0)
	movea.l	(sp)+,A0
	rts

********************************************
*
* Check for user specification in tooltypes.
*
* Inputs: none
* Results: none
*

_CheckWarning
	lea	WB_arg_1(A5),A0		; Address constant of 1. argument
1$
	tst.l	(A0)			; Address 1. argument there?
	beq.s	3$
	movea.l	(A0)+,A1		; Out of it address 1. argument
	lea	_NoWarningName(pc),A2	; "NOWARN",0
	moveq	#6,D0			; 7 loops
2$
	cmpm.b	(A1)+,(A2)+		; Compare char for char
	bne.s	1$			; "NOWARN"
	dbf	D0,2$
	st.b	_NoWarnFlag(A5)

3$
	lea	WB_arg_1(A5),A0		; Address constant of 1. argument
4$
	tst.l	(A0)			; Address 1. argument there?
	beq.s	6$
	movea.l	(A0)+,A1		; Out of it address 1. argument
	lea	_NoCheckPrinterTxt(pc),A2	; "NOPRTCHECK",0
	moveq	#10,D0			; 11 loops
5$
	cmpm.b	(A1)+,(A2)+		; Compare char for char
	bne.s	4$
	dbf	D0,5$
	st.b	_NoCheckPrtFlag(A5)
6$
	rts

*************************************************
*
* Check for user specification in tooltypes.
* If specification was made, execute the command.
* Inputs: none
* Results: none
*

_CheckExecute
	lea	WB_arg_1(A5),A0
.NextTType
	tst.l	(A0)			; Argument there?
	beq.s	.EndExecute		; No
	movea.l	(A0)+,A1		; Address overgiven string
	lea	_ExecuteTxt(pc),A2	; Address string to compare
	moveq	#7,D0			; 8 chars to compare
.CheckTType
	cmpm.b	(A1)+,(A2)+		; Compare strings
	bne.s	.NextTType		; "EXECUTE="
	dbf	D0,.CheckTType
	movea.l	A1,A0			; Pointer to following string

	moveq	#0,D4
	lea	_ConBuffer(A5),A1
1$
	move.b	(A0)+,(A1)+
	bne.s	1$
	move.l	_stdout(A5),D3
	bne.s	2$
	lea	_NilName(pc),A0
	move.l	A0,D1
	move.l	#MODE_NEWFILE,D2
	movea.l	_DOSBase(A5),A6
	jsr	_LVOOpen(A6)
	move.l	D0,D4
	beq.s	.EndExecute
	move.l	D4,D3
2$
	lea	_ConBuffer(A5),A0
	move.l	A0,D1
	moveq	#0,D2
	movea.l	_DOSBase(A5),A6
	jsr	_LVOExecute(A6)
	tst.l	D4
	beq.s	.EndExecute
	move.l	D4,D1
	jsr	_LVOClose(A6)	
.EndExecute
	rts

**********************************
*
* Init gadgets for "DisplayError".
* Do it position independent.
*
* Inputs: None
* Results: None
*

_InitGadgets
	movem.l	D0-D2/A0-A4/A6,-(sp)

BoolGadFlags	EQU	GADGIMMEDIATE|RELVERIFY

	lea	_Gad1(A5),A0
	move.w	#20,gg_LeftEdge(A0)
	move.w	#78,gg_TopEdge(A0)
	move.w	#74,gg_Width(A0)
	move.w	#19,gg_Height(A0)
	move.w	#GADGHIMAGE|GADGIMAGE,gg_Flags(A0)
	move.w	#BoolGadFlags,gg_Activation(A0)
	move.w	#BOOLGADGET,gg_GadgetType(A0)
	move.w	#1,gg_GadgetID(A0)

	lea	_Gad2(A5),A1
	moveq	#gg_SIZEOF,D0
	bra.s	2$
1$
	move.b	(A0)+,(A1)+
2$
	dbf	D0,1$

	lea	_Gad2(A5),A0
	clr.l	(A0)			; No next gadget!  - otherwise on second
*					  initializing it would point to itself!!!
	move.w	#226,gg_LeftEdge(A0)
	move.w	#2,gg_GadgetID(A0)

	lea	_GTxt1(A5),A0
	move.b	#1,(A0)			; DetailPen
	lea	_GTxt2(A5),A0
	move.b	#1,(A0)			; DetailPen

	lea	_Image.1(pc),A0
	lea	_Image.2(pc),A1
	lea	_Gad1(A5),A2
	lea	_Gad2(A5),A3

	move.l	A3,(A2)
	move.l	A0,gg_GadgetRender(A2)
	move.l	A1,gg_SelectRender(A2)
	lea	_GTxt1(A5),A4
	move.l	A4,gg_GadgetText(A2)

	move.l	A0,gg_GadgetRender(A3)
	move.l	A1,gg_SelectRender(A3)
	lea	_GTxt2(A5),A4
	move.l	A4,gg_GadgetText(A3)

	lea	_GTxt1(A5),A0
	lea	_GStr1(pc),A1
	move.l	A1,it_IText(A0)

	lea	_GTxt2(A5),A0
	lea	_GStr2(pc),A1
	move.l	A1,it_IText(A0)

	lea	_startup(pc),A0		; First instruction of Viewer (startup-code)
	subq.l	#4,A0			; Pointer to BPTR next hunk
	movea.l	(A0),A0			; BPTR NextHunk
	adda.l	A0,A0
	adda.l	A0,A0			; APTR NextHunk
	addq.l	#4,A0			; Section Chip (_Gad.1, size 190 bytes)
	movea.l	A0,A1
	lea	190(A1),A1		; _Gad.2
	lea	_Image.1(pc),A2
	lea	_Image.2(pc),A3
	move.l	A0,ig_ImageData(A2)
	move.l	A1,ig_ImageData(A3)

	bsr.s	_CenterGadTxt

	movem.l	(sp)+,D0-D2/A0-A4/A6
	rts

_CenterGadTxt
	lea	_Gad1(A5),A2		; First-Gadget
	bra.s	.set
.NextGadget
	tst.l	(A2)			; Next gadget?
	beq.w	.NoNext
	movea.l	(A2),A2
.set
	move.w	gg_GadgetType(A2),D0
	btst	#0,D0			; BoolGadget ?
	beq.s	.NextGadget		; If not

	tst.l	gg_GadgetText(A2)	; Intuition-text-structure?
	beq.s	.NextGadget
	movea.l	gg_GadgetText(A2),A0
	movea.l	A0,A3			; Save Intuition-text-structure
	tst.l	it_IText(A0)		; Any Text placed?
	beq.s	.NextGadget
	movea.l	it_IText(A0),A0		; Pointer to string
	movea.l	A0,A1
	moveq	#-1,D0
.getChars
	tst.b	(A1)+
	dbeq	D0,.getChars
	not.l	D0			; Length in chars of string
	movea.l	_ErrWindowPtr(A5),A1	; Window
	movea.l	wd_WScreen(A1),A1	; Screen's
	lea	sc_RastPort(A1),A1	; RastPort!!! <- default font!!!
	movea.l	_GfxBase(A5),A6
	jsr	_LVOTextLength(A6)	; Get stringlength in pixel

	move.w	gg_Width(A2),D1		; Width of gadget

	lsr.w	#1,D0			; Half textlength
	lsr.w	#1,D1			; Half gadget width
	sub.w	D0,D1			; Offset 1. char
	move.w	D1,it_LeftEdge(A3)	; Store it in IntuiText-structure

	moveq	#0,D2			; Flags
	movea.l	_ErrWindowPtr(A5),A0	; Window
	movea.l	wd_WScreen(A0),A0	; Get screen's
	lea	sc_RastPort(A0),A0	; rastport - not window's one, because
*					  the default-font is used for a gadget-text
	move.w	rp_TxHeight(A0),D0	; Height in pixel of font
	btst	#0,D0			; Font-height even (8, 10, 12 a.s.o.)?
	bne.s	2$
1$
	move.b	#1,D2	
2$
	move.w	#19,D1			; Height gadget
	lsr.w	#1,D0			; Half
	lsr.w	#1,D1			; Half
	sub.w	D0,D1			; Y-offset font
	add.w	D2,D1			; Add (may be NULL) for even font-sizes
	move.w	D1,it_TopEdge(A3)	; Set Top-Offset
	bra.w	.NextGadget
.NoNext
	rts

***************
*
* Init windows.
*
* Inputs: none
* Results: none
*

_InitStandard
	lea	_WindowRecord(A5),A0
	move.b	#1,nw_DetailPen(A0)
	move.b	#3,nw_BlockPen(A0)
	move.l	#$8|$40|$200|$400,nw_IDCMPFlags(A0)
	move.l	#1|2|4|8|$10|$400|$1000|$10000,nw_Flags(A0)
	move.w	#240,nw_MinWidth(A0)	
	move.w	#70,nw_MinHeight(A0)	
	moveq	#-1,D0
	move.w	D0,nw_MaxWidth(A0)
	move.w	D0,nw_MaxHeight(A0)
	move.w	#CUSTOMSCREEN,nw_Type(A0)

	lea	_ErrWindowStruc(A5),A0
	move.w	#320,nw_Width(A0)
	move.w	#100,nw_Height(A0)
	move.b	#-1,nw_DetailPen(A0)
	move.b	#-1,nw_BlockPen(A0)
	move.l	#$40|$400,nw_IDCMPFlags(A0)
	move.l	#$1000|$10000,nw_Flags(A0)
	move.w	#320,nw_MinWidth(A0)	
	move.w	#100,nw_MinHeight(A0)	
	move.w	#320,nw_MaxWidth(A0)
	move.w	#100,nw_MaxHeight(A0)
	move.w	#CUSTOMSCREEN,nw_Type(A0)

	rts


****************************************************************************
*
* Allocate AudioIO-request
*
* Inputs: Priority (should be NULL or negative)  D0 (byte, word, longword, but signed!)
*
* Result: APTR IOAudio - pointer to IORequest or zero upon error
*
* Notes: IOAudio is larger than it seems, so never deallocate it on your own.
*

IOReq_size	EQU	68+4	; size: divisible by eight
MsgPort_size	EQU	34+6	; size: divisible by eight
IOAudio_size	EQU	IOReq_size+MsgPort_size

_AllocIOAudioA ; (D0)(Pri)
	movem.l	D2/A3-A4/A6,-(sp)

	move.l	D0,D2			; Pri

	moveq	#IOAudio_size,D0	; 68 bytes IOAudio, 34 bytes MsgPort - aligned!
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	tst.l	D0
	beq.w	.AllocAudioEnd		; Error no mem
	movea.l	D0,A4			; IOReq ( *IOAudio)
	movea.l	D0,A3			; IOAudio
	lea	IOReq_size(A3),A3	; Skip IOAudio - thus pointer to MessagePort

	moveq	#-1,D0			; Any signal will do it
	jsr	_LVOAllocSignal(A6)
	cmpi.l	#-1,D0			; Failed?
	beq.w	.errNoSignal

	move.b	D0,MP_SIGBIT(A3)	; SignalBit
	suba.l	A1,A1
	jsr	_LVOFindTask(A6)	; Own task
	move.l	D0,MP_SIGTASK(A3)	; Task who is signalled
	move.b	#NT_MSGPORT,LN_TYPE(A3) ; Type = message port
	lea	MP_MSGLIST(A3),A0
	NEWLIST	A0			; Set up empty list

	btst	#31,D2			; A signed long value?
	bne.s	.signed			; If so...
	btst	#15,D2			; A signed word value?
	beq.s	.setup			; If not...
.signed
	bset	#7,D2			; Make a signed byte
.setup
	move.b	D2,LN_PRI(A4)		; Priority of message (IOAudio->io_Message->ln_Pri)
	move.b	#NT_REPLYMSG,LN_TYPE(A4) ; Type = ~message - due to a buck in CheckIO()
	move.l	A3,MN_REPLYPORT(A4)	; Set replyport
	move.w	#ioa_SIZEOF,MN_LENGTH(A4); Length of message

	lea	_Channels(pc),A0
	move.l	A0,ioa_Data(A4)		; Address channel map
	move.l	#4,ioa_Length(A4)	; Length channel map
	move.b	#ADIOF_NOWAIT,IO_FLAGS(A4)	; Do not wait until channels are unlocked
	move.w	#ADCMD_ALLOCATE,IO_COMMAND(A4)	; Alloc channels upon opening device

	lea	_AudioName(pc),A0	; Device
	movea.l	A4,A1			; IOReq
	moveq	#0,D0			; Unit
	moveq	#0,D1			; Flags
	jsr	_LVOOpenDevice(A6)
	tst.l	D0
	bne.s	.errNoDev

	move.l	A4,D0			; IOAudio
.AllocAudioEnd
	movem.l	(sp)+,D2/A3-A4/A6
	rts

.errNoMem
	moveq	#ERROR_NO_FREE_STORE,D0
	bsr.s	.SetIoErr
	moveq	#0,D0
	bra.s	.AllocAudioEnd
.errNoSignal
	move.l	#ERROR_NO_MORE_ENTRIES,D0
	bsr.s	.SetIoErr
	bsr.s	.FreeAudioIOReq
	moveq	#0,D0
	bra.s	.AllocAudioEnd
.errNoDev
	move.l	#ERROR_OBJECT_IN_USE,D0
	bsr.s	.SetIoErr
	moveq	#0,D0
	move.b	MP_SIGBIT(A3),D0
	jsr	_LVOFreeSignal(A6)
	bsr.s	.FreeAudioIOReq
	moveq	#0,D0
	bra.s	.AllocAudioEnd
.FreeAudioIOReq
	movea.l	A4,A1
	moveq	#IOAudio_size,D0
	jmp	_LVOFreeMem(A6)

.SetIoErr
	movea.l	276(A6),A0		; ThisTask(A6)
	cmpi.b	#NT_PROCESS,LN_TYPE(A0)	; Are we a process or task?
	bne.s	.done
	move.l	D0,pr_Result2(A0)	; Set error code in process' error field
.done
	rts

*************************************************************************
*
* Free through AllocAudioIO() allocated IORequest, MessagePort, Signalbit.
*
* Inputs: IOAudio A0, APTR
*
* Results: None
*

_FreeIOAudioA ; (A0)(IOAudio)
	movem.l	A3-A4/A6,-(sp)
	move.l	A0,D0
	beq.s	.out
	movea.l	A0,A4
	movea.l	A0,A3
	lea	IOReq_size(A3),A3	; Skip IOAudio

	tst.l	IO_DEVICE(A4)
	beq.s	.NotInProgress

	movea.l	A4,A1

*	clr.b	LN_TYPE(A4)

* Although I set the type of IORequest to zero (as stated in autodocs) CheckIO() will ever hang...
*	movea.l	_SysBase(A5),A6
*	jsr	_LVOCheckIO(A6)		; A process running?
*	tst.l	D0			; ~0 == no process
*	bne.s	.NotInProgress

	movea.l	A4,A1
	ABORTIO

*	movea.l	A4,A1
*	jsr	_LVOWaitIO(A6)

.NotInProgress
	moveq	#0,D0
	move.b	MP_SIGBIT(A3),D0	; Get allocated signal
	jsr	_LVOFreeSignal(A6)	; Free allocated signal

	movea.l	A4,A1
	jsr	_LVOCloseDevice(A6)	; Close the audio-device

	movea.l	A4,A1
	moveq	#IOAudio_size,D0	; Full size (aligned)
	jsr	_LVOFreeMem(A6)		; Free allocated memory
.out
	movem.l	(sp)+,A3-A4/A6
	rts

*******************************************************
*
* Move the datas to the audio-channels.
* Breaks the current IOAudio-process.
* Does not wait until datas are completely worked out.
*
* Inputs: D0 (ULONG) Length in Bytes
*	  D1 (UWORD) Cycles ( NULL = neverending)
*	  D2 (UWORD) Period
*	  D3 (UWORD) Volume
*	  A0 (APTR) IOAudio
*	  A1 (APTR) AudioDatas (must stay in chip-mem)
*
* Results: NULL - error - zero IOAudio
*

_SendIOAudioA ; (D0,D1,D2,D3,A0,A1)(length,cycles,period,volume,IOAudio,audiodata)
	movem.l	D2-D5/A2-A3/A6,-(sp)

	movea.l	A0,A2			; IOAudio
	movea.l	A1,A3			; audiodata
*		   D2			; period
*		   D3			; volume
	move.l	D0,D4			; length
	move.w	D1,D5			; cycles
	move.l	A0,D0
	beq.s	.failed
*
** There seems to be a bug in the audio.device. CheckIO() will here
** return ever that there is a process running, even there isn't one.
** If we _do_ ABORTIO with an afterward WaitIO() (convention!) we wait
** here until world's ruin....
*
	movea.l	A2,A1
	movea.l	_SysBase(A5),A6
	jsr	_LVOCheckIO(A6)		; A process running?
	tst.l	D0			; ~0 == no process
	bne.s	.NotInProgress

	movea.l	A2,A1
	ABORTIO

.NotInProgress
	movea.l	A2,A1			; IOAudio
	move.l	A3,ioa_Data(A1)
	move.l	D4,ioa_Length(A1)
	move.w	D2,ioa_Period(A1)
	move.w	D3,ioa_Volume(A1)
	move.w	D5,ioa_Cycles(A1)
	move.b	#ADIOF_PERVOL|ADIOF_SYNCCYCLE|IOF_QUICK,IO_FLAGS(A1)
	move.w	#CMD_WRITE,IO_COMMAND(A1)
	BEGINIO				; BEGINIO and ABORTIO are MARCOS of "exec/io.i"!
	move.l	A2,D0
.out
	movem.l	(sp)+,D2-D5/A2-A3/A6
	rts
.failed
	moveq	#0,D0
	bra.s	.out

*******************************************
*
** Make the sound audible
*

_AudioHit
	movem.l	D2-D7,-(sp)
	tst.b	_AudGadget(A5)
	beq.w	1$
	tst.l	_AudioBuffer(A5)
	beq.w	1$
	tst.l	_IOAudio(A5)
	beq.w	1$

	movea.l	_IOAudio(A5),A0
	move.b	IO_ERROR(A0),D0		; Any error?
	bpl.s	.gogo			; No...

	bsr.w	_FreeIOAudioA		; Error, so free device block
	moveq	#-50,D0			; and allocate a new one
	bsr.w	_AllocIOAudioA		; with the same priority
	move.l	D0,_IOAudio(A5)
	beq.w	.errorPlay		; If we still can't them...

.gogo
	move.l	_BODYSize(A5),D0
	move.l	_AudioBufferSize(A5),D1
	cmp.l	D0,D1
	bls.s	2$

* Normal, one shot sample play, sample size lower or equal to 28 kbyte 
	move.l	_BODYSize(A5),D0
	moveq	#1,D1
	move.l	_AudioPeriod(A5),D2
	moveq	#64,D3
	movea.l	_IOAudio(A5),A0
	move.l	_AudioBuffer(A5),A1
	bsr.w	_SendIOAudioA

	movea.l	_IOAudio(A5),A0
	tst.b	IO_ERROR(A0)
	bne.w	.errorPlay

	bra.w	.done			; Done

* Smart, sample size taller than 28 kbyte
2$
	movea.l	_IOAudio(A5),A0
	movea.l	MN_REPLYPORT(A0),A0
	move.b	MP_SIGBIT(A0),D1	; Get SigBit of IO Request
	moveq	#0,D4
	move.b	D1,D4
	moveq	#1,D0
	lsl.l	D1,D0			; ... and convert it into a bitmask
	move.l	D0,D7

	movea.l	_WindowPtr(A5),A0	; Same for our window
	movea.l	wd_UserPort(A0),A0
	move.b	MP_SIGBIT(A0),D1
	moveq	#1,D0
	lsl.l	D1,D0
	or.l	D0,D7			; Combine both mask

	move.l	_BODYSize(A5),D6	; The size of the whole audio datas
	moveq	#0,D5			; How many bytes already played

	moveq	#0,D0			; Refer to chip-ram buffer 0
	bsr.w	.SetupAudBuffer
	move.l	D0,D2			; Amount datas to play

3$	
	tst.l	D2
	beq.w	.done
	move.l	D2,D0			; Play how many ....
	moveq	#1,D1			; One cycle
	move.l	_AudioPeriod(A5),D2	; Period
	moveq	#64,D3			; Volume
	move.l	_IOAudio(A5),A0		; Device IO Request block
	move.l	_AudioBuffer(A5),A1	; Datas
	bsr.w	_SendIOAudioA		; Play them!

	moveq	#1,D0			; Refer to chip-ram buffer 1
	bsr.s	.SetupAudBuffer
	move.l	D0,D2
	beq.s	.done

	movea.l	_IOAudio(A5),A0
	tst.b	IO_ERROR(A0)		; Error occurred?
	bne.s	.errorPlay

	movea.l	_SysBase(A5),A6
	move.l	D7,D0			; Mask
	jsr	_LVOWait(A6)		; Wait for this part to finish
	moveq	#0,D3
	btst.l	D4,D0			; Not an audio signal?
	beq.w	4$			; If no audio signal!

.InJump
	move.l	D2,D0			; Play how many ....
	moveq	#1,D1
	move.l	_AudioPeriod(A5),D2
	moveq	#64,D3
	movea.l	_IOAudio(A5),A0
	move.l	_AudioBuffer(A5),A1
	lea	14*1024(A1),A1
	bsr.w	_SendIOAudioA

	moveq	#0,D0			; Refer to chip-ram buffer 0
	bsr.s	.SetupAudBuffer

	move.l	D0,D2

	movea.l	_IOAudio(A5),A0
	tst.b	IO_ERROR(A0)
	bne.s	.errorPlay

	movea.l	_SysBase(A5),A6
	move.l	D7,D0
	jsr	_LVOWait(A6)		; Wait for that part to finish
	moveq	#1,D3
	btst.l	D4,D0			; Not an audio signal?
	beq.s	4$			; If no audio signal!

	bra.s	3$			; Restart (next data block)

.errorPlay
	lea	_AudErrTxt(pc),A0
	bsr.w	_DisplayError
	bra.s	1$
.done
	movea.l	_SysBase(A5),A6
	movea.l	_IOAudio(A5),A1
	jsr	_LVOWaitIO(A6)
1$
	movem.l	(sp)+,D2-D7
	bra.w	_Loop

* -------- Fill either first or second buffer with audio datas -------- *
* D0 = 0, 1st buffer, D0 = 1, second buffer

.SetupAudBuffer
	subi.l	#14*1024,D6		; Try to work out 14 kbyte
	bcs.s	.overload		; If there isn't such a amount

	movea.l	_BODYPtr(A5),A0		; Pointer to datas (in fast ram/hopefully)
	add.l	D5,A0			; Fetch datas that aren't worked out yet
	movea.l	_AudioBuffer(A5),A1	; Chip-ram buffer (28 kbyte)
	mulu.w	#14*1024,D0		; Two which part we refer (14 kbyte)
	adda.l	D0,A1
	move.l	#14*1024,D0		; Size: 14 kbyte to copy
	movea.l	_SysBase(A5),A6
	jsr	_LVOCopyMemQuick(A6)
	move.l	#14*1024,D0		; Size to play: 14 kbyte
	add.l	D0,D5			; Amount datas that worked out already
	rts

.overload
	add.l	#14*1024,D6		; Get rest of datas

	movea.l	_BODYPtr(A5),A0
	add.l	D5,A0
	movea.l	_AudioBuffer(A5),A1
	mulu.w	#14*1024,D0		; To which chip-ram buffer we refer ?
	adda.l	D0,A1
	move.l	D6,D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOCopyMem(A6)
	add.l	D6,D5
	move.l	D6,D0			; Size to play
	moveq	#0,D6			; No more datas
	rts

* -------- React to user input (while something is played)-------- *
4$
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	movea.l	_SysBase(A5),A6
	jsr	_LVOGetMsg(A6)
	tst.l	D0
	beq.s	7$

	movea.l	D0,A1
	move.l	20(A1),D0		; im_Class
	move.w	24(A1),D1		; im_Code
	move.l	28(A1),_IAddr(A5)

	movem.l	D0-D1,-(sp)
	jsr	_LVOReplyMsg(A6)
	movem.l	(sp)+,D0-D1

	cmpi.l	#$200,D0		; CLOSEWINDOW ?
	bne.s	5$
	movem.l	(sp)+,D2-D7
	bsr.s	.WaitAction
	bra.w	_End			; If so...
5$
	cmpi.l	#$40,D0			; GADGETUP
	bne.s	6$
	movea.l	_IAddr(A5),A0
	cmpi.w	#3,gg_GadgetID(A0)
	bne.s	7$
	bsr.s	.WaitAction
	bra.w	2$			; Redo from start!
6$
	cmpi.l	#$400,D0		; RAWKEY?
	bne.s	7$			; If not...
	cmpi.w	#L_Key,D1
	bne.s	7$
	movem.l	(sp)+,D2-D7
	bsr.s	.WaitAction
	bra.w	_LoadNew
7$
	bsr.s	.WaitAction
	tst.l	D3
	beq.w	.InJump			; Jump where we can continue
	bra.w	3$

* -------- Ignore multiple intuition messages and wait for the IO to complete -------- *
.WaitAction
	movea.l	_WindowPtr(A5),A0
	movea.l	wd_UserPort(A0),A0
	movea.l	_SysBase(A5),A6
	jsr	_LVOGetMsg(A6)
	tst.l	D0
	beq.s	8$
	movea.l	D0,A1
	jsr	_LVOReplyMsg(A6)
	bra.s	.WaitAction
8$
	movea.l	_IOAudio(A5),A1
	jsr	_LVOWaitIO(A6)
	rts

*************************************************
*
** Load Audio File
*

_LoadAudio
	lea	_8SVXTxt(pc),A0
	bsr.w	_DisplayError
	tst.l	D0
	beq.w	_BinaryFile

	bsr.s	_GetAudioSettings

	moveq	#-50,D0
	bsr.w	_AllocIOAudioA
	move.l	D0,_IOAudio(A5)
	beq.s	.error

	bsr.w	_DisplayAudioGadget

	addq.l	#4,sp			; Remove "bsr.w _CheckFile"
	bra.w	_Loop

.error
	bsr.w	_FreeAudio
	bsr.w	_FreeFile
	lea	_8SVXErrTxt(pc),A0
	bsr.w	_DisplayError
	addq.l	#4,sp
	bra.w	_Loop


_GetAudioSettings
	bsr.w	_CheckFibDelta
	tst.l	D0
	beq.w	.error

	move.l	#28*1024,D0
	move.l	D0,_AudioBufferSize(A5)
	move.l	#MEMF_CLEAR|MEMF_CHIP|MEMF_PUBLIC,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	move.l	D0,_AudioBuffer(A5)
	beq.w	.error

	movea.l	_TextPtr(A5),A0		; Address datas
	move.l	_FileSize(A5),D0	; Size datas
	cmpi.w	#'FO',(A0)
	beq.s	.startScan
	addq.l	#2,A0
	subq.l	#2,D0
.startScan
	lea	12(A0),A0
	subi.l	#12,D0
	move.l	#'VHDR',D1
	bsr.w	.getChunk
	tst.l	D1
	beq.s	.error
.scanBody
	move.l	A0,_VHDRPtr(A5)
	addq.l	#8,_VHDRPtr(A5)
	move.l	#'BODY',D1
	bsr.w	.getChunk
	tst.l	D1
	beq.s	.error
.gotBody
	move.l	A0,_BODYPtr(A5)
	addq.l	#8,_BODYPtr(A5)
	move.l	4(A0),_BODYSize(A5)

	move.l	_VHDRPtr(A5),A0
	moveq	#0,D1
	move.w	12(A0),D1

* Hertz to Period, the slow way...
	move.l	#100000000,D0
*	move.l	D1,D1			; Hertz
	moveq	#28,D2
	mulu.w	D2,D1

	moveq	#-1,D2
.divlong
	addq.l	#1,D2
	sub.l	D1,D0
	bcc.s	.divlong

	move.l	D2,_AudioPeriod(A5)

	move.l	_BODYSize(A5),D0
	move.l	_AudioBufferSize(A5),D1
	cmp.l	D0,D1
	bhi.s	.cpy

	move.l	_BODYPtr(A5),A0
	move.l	_AudioBuffer(A5),A1
	move.l	#28*1024,D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOCopyMemQuick(A6)
	rts

.cpy
	move.l	_BODYPtr(A5),A0
	move.l	_AudioBuffer(A5),A1
	move.l	_BODYSize(A5),D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOCopyMem(A6)
	rts

.error
	lea	_8SVXErrTxt(pc),A0
	bsr.w	_DisplayError
	bsr.w	_FreeFile
	bsr.w	_FreeAudio
	addq.l	#8,sp			; Remove "bsr.w _CheckFile" and "bsr.s GetAudioSettings"
	bra.w	_Loop

.getChunk
	cmp.l	(A0),D1
	beq.s	.chunkFound
.getNextChunk
	move.l	4(A0),D2		; Size of this chunk
	addq.l	#1,D2
	andi.l	#-2,D2			; In case it was odd, it's now even
	addq.l	#8,D2			; Skip chunk name and its size entry
	sub.l	D2,D0			; A rest left?
	beq.s	.chunkError
	bmi.s	.chunkError
	lea	0(A0,D2),A0		; Point to next chunk name
	cmp.l	(A0),D1			; Compare
	bne.s	.getNextChunk
.chunkFound
	rts
.chunkError
	moveq	#0,D1
	rts

_FindVHDR
	move.l	D0,D2			; Size file
	subi.l	#12,D2
	lea	12(A0),A1		; Chunk name
.restart
	move.l	4(A1),D1		; Chunk size
	addq.l	#1,D1
	andi.l	#-2,D1			; Even chunk size
	addq.l	#8,D1			; Chunk name + sizeof(chunk size var) (4 bytes)
	sub.l	D1,D2
	beq.s	.notfound
	bmi.s	.notfound
	lea	0(A1,D1),A1		; Next chunk name
	cmpi.l	#'VHDR',(A1)
	bne.s	.restart
.found
	addq.l	#8,A1
	bra.s	_TestIfFibDeltaComp
.notfound
	lea	_8SVXErrTxt(pc),A0
	bsr.w	_DisplayError
	bsr.w	_FreeFile
	lea	12(sp),sp			; Remove "bsr.w _CheckFile" and "bsr.s GetAudioSettings" and "bsr.s _CheckFibDelta"
	bra.w	_Loop


_FreeAudio
	tst.l	_AudioBuffer(A5)
	beq.s	1$
	movea.l	_AudioBuffer(A5),A1
	move.l	_AudioBufferSize(A5),D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)
	clr.l	_AudioBuffer(A5)
1$
	move.l	_IOAudio(A5),D0
	beq.s	2$
	movea.l	D0,A0	
	bsr.w	_FreeIOAudioA
	clr.l	_IOAudio(A5)
2$
	bsr.w	_RemoveAudioGadget
	rts

_CheckFibDelta
	movem.l	D2-D4/A2-A4,-(sp)
	move.l	_FileSize(A5),D0
	movea.l	_TextPtr(A5),A0
	addq.l	#2,A0			; Overread
	subq.l	#2,D0

	cmpi.l	#'FORM',(A0)		; IFF?
	bne.s	_CheckFibEnd
	cmpi.l	#'8SVX',8(A0)		; 8SVX?
	bne.s	_CheckFibEnd
	cmpi.l	#'VHDR',12(A0)		; IFF?
	bne.w	_FindVHDR
	lea	20(A0),A1
_TestIfFibDeltaComp
	cmpi.b	#1,15(A1)
	bne.s	_CheckFibEndOk
	bra.s	_StartUnpack
_CheckFibEnd
	moveq	#0,D0
	movem.l	(sp)+,D2-D4/A2-A4
	rts
_CheckFibEndOk
	moveq	#-1,D0
	movem.l	(sp)+,D2-D4/A2-A4
	rts


_StartUnpack
	move.l	D0,D1
	movea.l	A0,A1
	moveq	#0,D2
1$
	subq.l	#2,D1
	bls.s	_CheckFibEnd
	addq.l	#2,D2
	cmpi.w	#'BO',(A1)+
	bne.s	1$
	addq.l	#6,D2			; plus 'BODY' text ('DY' plus room for 1 longword)
	move.l	2(A1),D3		; Length Body
	addq.l	#6,A1			; Ignore 'DY' plus length

	movea.l	A0,A2			; IFF-Header
	movea.l	A1,A3			; Compressed datas
*	A2 pointer to IFF header
*	A3 pointer to compressed datas
*	D2 length IFF header
*	D3 length sample (compressed) datas
	move.l	D2,D0
	add.l	D3,D0
	add.l	D3,D0			; Length new IFF-file! (2* D3 !!!)
	addq.l	#3,D0			; + 7 - 4 = 3 ( because of 2*(n-2) ! )
	andi.l	#-8,D0
	move.l	D0,D4			; New IFF-file length
	move.l	#MEMF_CLEAR|MEMF_PUBLIC,D1
	movea.l	4.w,A6
	jsr	_LVOAllocMem(A6)
	tst.l	D0
	beq.s	_CheckFibEnd
	movea.l	D0,A4
*	A2 pointer to IFF header
*	A3 pointer to compressed datas
*	A4 pointer to allocated memory
*	D2 length IFF header
*	D3 length sample (compressed) datas
*	D4 size allocated memory
	move.l	A2,A0
	movea.l	A4,A1
	move.l	D2,D0
	subq.l	#4,D0			; Minus length of 'BODY' length set
	jsr	_LVOCopyMem(A6)		; Copy IFF-Header

	add.l	D3,4(A4)		; Add double size of datas of FORM-chunk
	subq.l	#4,4(A4)
	clr.b	35(A4)			; Erase comression sign

	move.l	D3,D0			; length datas
	movea.l	A3,A0			; Source datas
	movea.l	A4,A1
	add.l	D2,A1			; Destination (pointer right behind IFF header!)
	move.l	D3,D1
	add.l	D1,D1			; New length of BODY = length * 2
	subq.l	#4,D1			; Because of 2*(n-2) !
	move.l	D1,-4(A1)		; Set length

	bsr.s	_FibDeltaUnpack		; Unpack datas

	bsr.w	_FreeFile

	move.l	D4,_BufferSize(A5)
	move.l	D2,D0
	add.l	D3,D0
	add.l	D3,D0			; 2 * D3!!!!
	subq.l	#4,D0
	move.l	D0,_FileSize(A5)
	move.l	A4,_TextPtr(A5)
	bra.w	_CheckFibEndOk

******************************************************************************
*
* FibDelatUnpack
*
* Based on Steve Hayes' DUnpack for his Fibonacci Delta compression algorythm.
*
* Converted to assembly by Jörg van de Loo
*			   Hövel 15
*			   47559 Kranenburg
*			   Germany
*

_FibDeltaUnpack	; (numdatas,source,destination)(D0,A0,A1)
	movem.l	D2-D5/A2,-(sp)

	subq.l	#2,D0		; numdatas-2 ( n - 2 )
	moveq	#0,D1
	move.b	1(A0),D1	; x = source[1] = initial value!
	addq.l	#2,A0		; source + 2
*	movea.l	A1,A1		; destination
*
** (rawdatas-2,data,source+2,destination)(D0,D1,A0,A1)
*
	move.l	D0,D2		; maximum datas =
	add.l	D2,D2		; doubled ( 2*(n-2) )
	moveq	#0,D3		; internal counter ( i )
	moveq	#0,D5		; Dummy
	lea	__DeltaTable(pc),A2 ; Table of deltas to add to value x
	bra.s	.checkend
.next
	move.l	D3,D4		; counter
	lsr.l	#1,D4		; counter / 2
	move.b	0(A0,D4.l),D5	; d = source[i]
	btst	#0,D3		; even or odd, i.e. low nibble or high nibble to affect
	beq.s	.highnibble
.lownibble
	andi.b	#15,D5		; d &= 15 (only low nibble (4 bits))
	bra.s	.store
.highnibble
	lsr.b	#4,D5		; d / 16 (high nibble (4 bits) on low nibble's position)
.store
	move.b	0(A2,D5.w),D4	; Delta out of table
	add.b	D4,D1		; x += Delta
	move.b	D1,0(A1,D3.l)	; write data value (uncompressed now!)
	addq.l	#1,D3		; i ++

.checkend
	cmp.l	D3,D2
	bhi.s	.next

	movem.l	(sp)+,D2-D5/A2
	move.b	D1,D0		; return x
	rts

__DeltaTable
	dc.b	-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21


*************************************************
*
** Init Audio Hit Gadget
*
_DisplayAudioGadget
	movem.l	D2/A2-A3,-(sp)

	lea	_Gad3(A5),A2
	clr.l	(A2)
	move.w	#8,gg_LeftEdge(A2)
	move.w	#6,gg_TopEdge(A2)
	move.w	#45,gg_Width(A2)
	move.w	#28,gg_Height(A2)
	move.w	#GADGHIMAGE|GADGIMAGE,gg_Flags(A2)
	move.w	#BoolGadFlags,gg_Activation(A2)
	move.w	#BOOLGADGET,gg_GadgetType(A2)
	move.w	#3,gg_GadgetID(A2)

	lea	_Image.3(pc),A0
	lea	_Image.4(pc),A1

	move.l	A0,gg_GadgetRender(A2)
	move.l	A1,gg_SelectRender(A2)

	lea	_startup(pc),A0		; First instruction of Viewer (startup-code)
	subq.l	#4,A0			; Pointer to BPTR next hunk
	movea.l	(A0),A0			; BPTR NextHunk
	adda.l	A0,A0
	adda.l	A0,A0			; APTR NextHunk
	addq.l	#4,A0			; Section Chip (_Gad.1, size 190 bytes)
	lea	380(A0),A0		; Skip both images (each 190 bytes)
	lea	336(A0),A1		; Pointer to Select Audio Image
	lea	_Image.3(pc),A2
	lea	_Image.4(pc),A3
	move.l	A0,ig_ImageData(A2)
	move.l	A1,ig_ImageData(A3)

	movea.l	_WindowPtr(A5),A0	; Window
	movea.l	wd_RPort(A0),A3		; ^RastPortPtr
	lea	_Gad3(A5),A1		; Audio gadget
	moveq	#0,D0			; Begin with number zero
	moveq	#-1,D1			; All gadgets
	moveq	#0,D2
	movea.l	D2,A2			; No requester
	move.l	_IntuitionBase(A5),A6
	jsr	_LVOAddGList(A6)	; Set gadgets to window

	lea	_Gad3(A5),A0		; Gadgets
	movea.l	_WindowPtr(A5),A1	; Window
	moveq	#0,D2
	movea.l	D2,A2			; No requester
	jsr	_LVORefreshGList(A6)	; Draw gadgets

	st.b	_AudGadget(A5)

	movem.l	(sp)+,D2/A2-A3
	rts

_RemoveAudioGadget
	tst.b	_AudGadget(A5)
	beq.s	1$
	movea.l	_WindowPtr(A5),A0
	lea	_Gad3(A5),A1
	moveq	#1,D0
	movea.l	_IntuitionBase(A5),A6
	jsr	_LVORemoveGList(A6)

	clr.b	_AudGadget(A5)
1$
	rts

********************************************************
*
*  (C) 1994 J.v.d.Loo
*
*  AA-support routines
*
*  Decompressor and 32 bit gun colour converter
*
*  Taken out of BitMapSaver
*
* Inputs: none
* Results: D0 = 1 when all went ok
*

* ------------------------------------------------------ *
* This is an fully decrompress routine for images of 64bit boundary (modulo).

_Convert
	movem.l	D2-D6/A2-A4,-(sp)

	bsr.w	_Init24BitPal		; Grey colour image setup when no palette set...

	movea.l	_WindowPtr(A5),A0	; Window
	movea.l	wd_RPort(A0),A0		; Its rastport
	movea.l	rp_BitMap(A0),A0	; BitMap being used
	moveq	#BMA_FLAGS,D1		; Ask for flags being used
	movea.l	_GfxBase(A5),A6
	cmpi.w	#38,LIB_VERSION(A6)	; OS 3 required for this check
	bls.s	.std			; If not available, treat it as the original GFX device
*					  is used...
	jsr	_LVOGetBitMapAttr(A6)
	andi.l	#BMF_STANDARD,D0	; Standard bitmap or one created by a 3rd graphic device?
	beq.s	.alien
.std
	move.l	#MEMF_CHIP,_TypeOfMem(A5)	; BitMap forced to CHIP-RAM (standard AMIGA device)
	bra.s	.doconvert
.alien
	move.l	#0,_TypeOfMem(A5)	; BitMap forced to FAST-RAM (3rd party GFX device)

.doconvert
	movea.l	_SourceFilePtr(A5),A0	; Address datas
	cmpi.l	#'FORM',(A0)+		; IFF ?
	bne.w	.finish_1
	addq.l	#4,A0			; Length IFF-file!?!?
	cmpi.l	#'ACBM',(A0)
	bne.s	.check4ILBM
	addq.l	#4,A0
	bra.s	.okType
.check4ILBM
	cmpi.l	#'ILBM',(A0)+		; Picture?
	bne.w	.finish_1
.okType
	move.l	_SourceFileSize(A5),D4
	subi.l	#12,D4			; Length datas - length header
.searchChunks
	subq.l	#4,D4			; Length datas -4
	beq.w	.finish_1		; If end reached
	bmi.w	.finish_1
	move.l	(A0)+,D3		; Chunk-name
	cmpi.l	#'BMHD',D3		; Bitmap-header?
	beq.s	.foundBMHD
	cmpi.l	#'CAMG',D3		; ViewPort-display?
	beq.w	.foundCAMG
	cmpi.l	#'CMAP',D3		; Colour-map?
	beq.w	.foundCMAP
	cmpi.l	#'BODY',D3		; Datas?
	beq.w	.foundBODY
	cmpi.l	#'ABIT',D3		; Amiga Bitplane Datas?
	beq.w	.foundABIT 
.unknownChunk
	subq.l	#4,D4			; Datas -4
	move.l	(A0)+,D0		; Length of this chunk
	addq.l	#1,D0
	andi.l	#-2,D0			; Through 2 divisible
	sub.l	D0,D4			; Datas minus (over)readed entries
	lea	0(A0,D0.w),A0		; New address
	bra.s	.searchChunks

.foundBMHD
	subq.l	#4,D4			; Datas -4
	move.l	(A0)+,D0		; Save number entries
	lea	_Width(A5),A1		; Address data-array
	moveq	#0,D1
	move.w	(A0),D1			; Get width
	move.l	D1,_RealIWidth(A5)	; Non aligned width of image
	addi.l	#15,D1
	andi.l	#-16,D1
	move.l	D1,_ImageWidth(A5)	; Save dafault width (aligned)
	addi.l	#63,D1
	andi.l	#-64,D1			; Set up to BURST-FETCH mode, needed for AGA
	move.w	D1,(A1)			; Save width
	move.w	2(A0),2(A1)		; Height
	move.w	4(A0),4(A1)		; X-Position
	move.w	6(A0),6(A1)		; Y-Position
	move.b	8(A0),8(A1)		; Depth
	move.b	9(A0),9(A1)		; Masking-type
	move.b	10(A0),10(A1)		; compression-mode
	move.b	11(A0),11(A1)		; Unused
	move.w	12(A0),12(A1)		; Transparent colour
	move.b	14(A0),14(A1)		; X-aspect
	move.b	15(A0),15(A1)		; Y-aspect
	move.w	16(A0),16(A1)		; Page width
	move.w	18(A0),18(A1)		; Page height
	lea	(A0,D0.w),A0		; Overread header
	sub.l	D0,D4			; Length Datas minus entries
	bra.w	.searchChunks

.foundCAMG
	subq.l	#4,D4			; Datas -4
	move.l	(A0)+,D0		; Length
	addq.l	#1,D0
	andi.l	#-2,D0			; Through 2 divisible
	move.l	(A0),_ViewPortMod(A5)	; ViewPort mode
	andi.l	#$FFFF9ABD,_ViewPortMod(A5)	; means:
*	bclr	#1,D0			; no genlocVideo
*	bclr	#6,D0			; no pfba
*	bclr	#8,D0			; no genlocAudio
*	bclr	#10,D0			; no dualpf
*	bclr	#13,D0			; no vpHide
*	bclr	#14,D0			; no sprites

	lea	0(A0,D0.w),A0		; Skip unused
	sub.l	D0,D4			; Length datas
	bra.w	.searchChunks

.foundCMAP
	subq.l	#4,D4			; Datas -4
	move.l	(A0)+,D0		; Entry length (ever through 2 divisible!!!)
	move.l	D0,-(sp)		; Remember
	divu.w	#3,D0			; /3
	andi.l	#$FFFF,D0
	move.l	D0,_CMapNumEntries(A5)	; = number of words of Colourmap
	lea	_Colourmap(A5),A1	; Address colour-array
	move.l	A0,_RGB32Values(A5)
	move.l	A0,-(sp)
	cmpi.l	#256*3,D0
	bhi.s	.getRGB32

.getRGB
	moveq	#0,D1
	move.b	(A0)+,D1		; R-value
	andi.w	#$F0,D1
	lsl.w	#4,D1			; Clear Half-byte position (G-value)
	move.b	(A0)+,D2		; G-value
	andi.w	#$F0,D2			; Mask it out
	or.w	D2,D1			; Store G-value
	move.b	(A0)+,D2		; B-value
	andi.w	#$F0,D2
	lsr.b	#4,D2			; Half-byte position
	or.w	D2,D1			; D1 = RGB-word
	move.w	D1,(A1)+		; Store RGB-word
	subq.l	#1,D0
	bgt.s	.getRGB

.getRGB32
	move.l	_CMapNumEntries(A5),D0
	movea.l	_RGB32Values(A5),A0
	lea	_RGB32Colours(A5),A1
	bsr.w	_RGBtoRGB32
	movea.l	(sp)+,A0
	move.l	(sp)+,D0
	addq.l	#1,D0
	andi.l	#-2,D0	
	sub.l	D0,D4			; Datas minus (over)readed entries
	lea	0(A0,D0.l),A0		; New address
	bra.w	.searchChunks

.foundBODY
	cmpi.b	#1,_Compresstyp(A5)
	bhi.w	.finish_3
	tst.b	_Masking(A5)
	beq.s	.go
	move.b	_Masking(A5),D0
	btst.l	#0,D0
	beq.s	.go
	tst.b	_NoWarnFlag(A5)
	bne.s	.go
	movem.l	A0-A1,-(sp)
	lea	_WarnMaskingTxt(pc),A0	; MASKING = DATA of 1st line for all bitplanes + masking line
	bsr.w	_DisplayError		;           DATA of 2nd line for all bitplanes + masking line
	move.l	#5,_errno(A5)		;           DATA of 3rd line for all bitplanes + masking line
	movem.l	(sp)+,A0-A1		;           ........... and so on
.go
	lea	_BitmapStruc(A5),A2	; Address bitmap-structure
	moveq	#23,D0
	addq.l	#8,A2
.clear
	clr.l	(A2)+			; Clear all 24 bitplane pointers
	subq.w	#1,D0
	bcc.s	.clear

	lea	_BitmapStruc(A5),A2	; Address bitmap-structure
	moveq	#0,D0			; Clear it
	move.w	_Width(A5),D0		; Pixel width
	lsr.w	#3,D0			; /8 = bytes
	move.w	D0,(A2)+		; Bytes per row
	move.w	_Height(A5),(A2)+	; Height graphic
	move.b	_Depth(A5),1(A2)	; Number of bitplanes

*
** Allocate needed bitplanes (all in once).
** <- D0 still holds number of bytes per line.
*
	move.l	A0,-(sp)		; Save current address
	movea.l	_SysBase(A5),A6		; Base Exec
	mulu.w	_Height(A5),D0		; = size of one bitplane
	move.l	D0,D2			; to D2

	moveq	#0,D1			; Clear it
	move.b	_Depth(A5),D1		; Number of bitplanes

*
** For those bug I searched 3 days... - so stupid I'm.
** I use normally images up to 736*566 pixel, that means that one plane is
** 736/8*566 pixel = 52072 bytes large, this size fits in a word,
** so "mulu" #8,Dx did not cause trouble (for 8 bitplanes).
** While testing "BitMapSaver" with an images of 960*724 pixel width, my 
** A4000 crashed - no guru but no input was furthermore possible!
** Today I got it. 960/8 = 120 = fits in a word, mulu #724,120 = ? -
** 86880 bytes = longword!!! Until that point all went ok, but after
** mulu.w #8,86880 (8 bitplanes) the value was not as you may expect 695040
** instead of it 170752 was returned. So the images was loaded to unallocated
** memory, "Amiga hang up".
** The crash occurred each time when DOS-function "Write" was called - and
** because there is a bug in the v39 ROM of the dos.library, I thought this
** was a bug of it, too.
** [( v39 bug: After a read/write error occures and the "Write"-routine returns
**    to the program, the baseregister A6 does not contain the DOSBase any more.)]
** But further:
** The mistake I made was to multiply a longword with a word - what is not
** possible with the 68000 instruction "mulu.w". I know this, but I never
** cared in this routine about it....
** But... here is the solution...
*

	moveq	#0,D0			; Zero !!!
	bra.s	.x1
.mul
	add.l	D2,D0			; Longword multiply!!!
.x1
	dbf	D1,.mul

	move.l	D0,_AllPlaneSize(A5)	; Save size of all bitplanes
	move.l	_TypeOfMem(A5),D1	; Set as CHIP or FAST
	ori.l	#MEMF_CLEAR,D1		; Requirements
	jsr	_LVOAllocMem(A6)	; Mem demand
	move.l	D0,_Bitplane(A5)	; Save memory address
	beq.w	.finish_2		; If error

	lea	_BitmapStruc(A5),A0	; Address bitmap-structure
	moveq	#0,D1			; Clear it
	move.w	(A0),D1			; Bytes per row
	mulu.w	2(A0),D1		; Number bytes of one bitplane

	moveq	#0,D2
	move.b	5(A0),D2		; Number of bitplanes
	addq.l	#8,A0			; Address constant for first plane

	movea.l	D0,A1			; Address memory
.StoreBPPtr
	move.l	A1,(A0)+		; Set address of bitplane to constant
	add.l	D1,A1			; Get next bitplane's memory address
	subq.b	#1,D2			; Decrease number of bitplanes
	bne.s	.StoreBPPtr		; If not all are set yet...

*
** Do it normal.
*
	movea.l	(sp)+,A0		; Get back current address	

	move.l	D4,D2			; Size in bytes of datas

	moveq	#0,D0			; Initialiize them with NULL for first time
	move.l	D0,D1
	move.l	D1,D3
	move.l	D3,D4
	move.l	D4,D5			; Linecounter

	addq.l	#4,A0
	subq.l	#4,D2

	lea	_BitmapStruc(A5),A2	; Address bitmap-structure
	addq.l	#8,A2			; Address pointer to first bitplane

	move.w	_Width(A5),D3		; Pixelwidth of image
	lsr.w	#3,D3			; in bytes
	move.b	_Depth(A5),D4		; Number of planes

	tst.b	_Compresstyp(A5)
	bne.s	.Decompress		; If compressed...

	movem.l	D0-D1/A0-A1,-(sp)
	tst.b	_NoWarnFlag(A5)
	bne.s	.NoWarn.1
	lea	_WarnUncompressedTxt(pc),A0
	bsr.w	_DisplayError
	move.l	#5,_errno(A5)
.NoWarn.1
	movem.l	(sp)+,D0-D1/A0-A1

	bra.w	.StoreUnpacked

.Decompress
	moveq	#0,D6			; Bitplanecounter
.Decompressing
	lsl.w	#2,D6			; Bitplanecounter * 4 = longword adjustment
	movea.l	0(A2,D6.w),A3		; Current bitplane
	lsr.w	#2,D6			; Normal
* Instead of the last three lines you can write
*	movea.l	0(A2,D6.w*4),A3
* if you have a turboboard.

	move.w	D3,D0			; Bytes per line
	mulu.w	D5,D0			; mutilply with current line
	lea	0(A3,D0.l),A3		; Startoffset to A3
	movea.l	A3,A4			; Address plane(x) to A4
	move.l	_ImageWidth(A5),D0	; Real pixel width of image
	lsr.w	#3,D0			; in bytes
	lea	0(A4,D0.w),A4		; == End of line
.CheckOperation
	subq.l	#1,D2			; Data counter
	bmi.w	.IncorrectSize
	moveq	#0,D0
	move.b	(A0)+,D0
	cmpi.b	#-128,D0		; #-128 = no operation
	beq.s	.NoOperation
	cmpi.b	#127,D0
	bhi.s	.StoreNeg		; If negativ (greater #128!)
.CopyBytes
	subq.l	#1,D2
	bmi.w	.IncorrectSize
	move.b	(A0)+,(A3)+
	dbf	D0,.CopyBytes
	bra.s	.NoOperation
.StoreNeg
	neg.b	D0			; To positive value
	subq.l	#1,D2
	bmi.w	.IncorrectSize
	move.b	(A0)+,D1		; Next byte
.StoreNegCopy
	move.b	D1,(A3)+		; Store byte
	dbf	D0,.StoreNegCopy	; While not all
.NoOperation
	tst.l	D2
	beq.w	.finish
	bmi.s	.IncorrectSize

	cmpa.l	A3,A4			; Position(x),line(x) the same as
*					; the end of line(x),plane(x)?
	bhi.s	.CheckOperation

	addq.w	#1,D6			; Increase planecounter
	cmp.w	D4,D6			; Last plane?
	bne.s	.Decompressing

	move.b	_Masking(A5),D0
	btst.l	#0,D0
	beq.s	.goon
	bsr.w	_IgnoreCompMaskLine

.goon
	addq.w	#1,D5			; Next line
	lea	_BitmapStruc(A5),A1
	cmp.w	2(A1),D5		; Last line?
	bne.s	.Decompress

	bra.w	.finish

.StoreUnpacked
	moveq	#0,D6			; Bitplanecounter
.StoreUncompress
	lsl.w	#2,D6			; Bitplanecounter * 2 = longword adjustment
	movea.l	0(A2,D6.w),A3		; Current bitplane
	lsr.w	#2,D6			; Normal

	move.w	D3,D0			; Bytes per line
	mulu.w	D5,D0			; multiply with current line
	lea	0(A3,D0.l),A3		; StartOffset to A3
	movea.l	A3,A4			; Address plane(x) to A4
	move.l	_ImageWidth(A5),D0	; Real pixel width of image
	lsr.w	#3,D0			; in bytes
	lea	0(A4,D0.w),A4		; == End of line

*	move.w	D0,D0			; Set counter (already done!)
	bra.s	.StoreUncmp_1		; 'Cause of DBF
.StoreUncmp
	move.b	(A0)+,(A3)+		; Copy byte into bitplane
.StoreUncmp_1
	dbf	D0,.StoreUncmp		; until all are done

	addq.w	#1,D6			; Increase planecounter
	cmp.w	D4,d6			; All planes worked out?
	bne.s	.StoreUncompress	; No - so do further

	move.b	_Masking(A5),D0
	btst.l	#0,D0
	beq.s	.goon1
	bsr.w	_IgnoreMaskLine

.goon1
	addq.w	#1,D5			; Next line

	lea	_BitmapStruc(A5),A1
	cmp.w	2(A1),D5		; Last line?
	bne.s	.StoreUnpacked		; No...

	bra.s	.finish

.IncorrectSize
	lea	_IncorrectSizeTxt(pc),A0
	bsr.w	_DisplayError
	move.l	#20,_errno(A5)
	movem.l	(sp)+,D2-D6/A2-A4
	moveq	#0,D0			; Bad IFF-file
	rts
.finish_3
	lea	_NoByteRunTxt(pc),A0
	bsr.w	_DisplayError
	move.l	#20,_errno(A5)
	movem.l	(sp)+,D2-D6/A2-A4
	moveq	#0,D0			; Unknown compression methode
	rts
.finish_2
	lea	_AllocBufErrTxt(pc),A0
	bsr.w	_DisplayError
	addq.w	#4,sp			; Overread "move.l A0,-(sp)"
	movem.l	(sp)+,D2-D6/A2-A4
	moveq	#-1,D0			; Error, no mem
	rts

.finish_1
	lea	_NoIFFFileTxt(pc),A0
	bsr.w	_DisplayError
	move.l	#20,_errno(A5)
	movem.l	(sp)+,D2-D6/A2-A4
	moveq	#0,D0			; Not an IFF-file
	rts
.finish
	movem.l	(sp)+,D2-D6/A2-A4
	moveq	#1,D0			; No error
	rts

*
** This is the engine to store the datas of the ABIT-chunk into the
** planar-datas needed for plain Amigas-screens. I ask myself a lot times
** why no demo-coder use this type of data, instead of it they use RAW-datas
** which is the same, but without an IFF-header...
*
.foundABIT
	lea	_BitmapStruc(A5),A2	; Address bitmap-structure
	moveq	#0,D0			; Clear it
	move.w	_Width(A5),D0		; Pixel width
	lsr.w	#3,D0			; /8 = bytes
	move.w	D0,(A2)+		; Bytes per row
	move.w	_Height(A5),(A2)+	; Height graphic
	move.b	_Depth(A5),1(A2)	; Number of bitplanes

*
** Allocate needed bitplanes (all in once).
** <- D0 still holds number of bytes per line.
*
	move.l	A0,-(sp)		; Save current address

	mulu.w	_Height(A5),D0		; = size of one bitplane
	move.l	D0,D2			; to D2

	move.b	_Depth(A5),D1		; Number of bitplanes
	moveq	#0,D0			; Zero !!!
.addsize
	add.l	D2,D0			; Longword multiply!!!
	subq.b	#1,D1
	bne.s	.addsize

	move.l	D0,_AllPlaneSize(A5)	; Save size of all bitplanes
	move.l	#MEMF_CHIP|MEMF_CLEAR,D1 ; Requirements
	movea.l	_SysBase(A5),A6		; Base Exec
	jsr	_LVOAllocMem(A6)	; Mem demand
	move.l	D0,_Bitplane(A5)	; Save memory address
	beq.s	.finish_2		; If error

	lea	_BitmapStruc(A5),A0	; Address bitmap-structure
	move.w	(A0),D1			; Bytes per row
	mulu.w	2(A0),D1		; Number bytes of one bitplane

	move.b	5(A0),D2		; Number of bitplanes
	addq.l	#8,A0			; Address constant for first plane

	movea.l	D0,A1			; Address memory
.StoreBAddr
	move.l	A1,(A0)+		; Set address of bitplane to constant
	adda.l	D1,A1			; Get next bitplane's memory address
	subq.b	#1,D2			; Decrease number of bitplanes
	bne.s	.StoreBAddr		; If not all are set yet...

	movea.l	(sp)+,A0		; Get back current address (source)	
	addq.l	#4,A0			; Overread length entry
	move.l	D4,D2			; Size in bytes of datas
	subq.l	#8,D2			; Minus two longword ( ABIT[length] )

	lea	_BitmapStruc(A5),A2	; Address bitmap-structure
	addq.l	#8,A2			; Address pointer to first bitplane
	moveq	#0,D3
	move.w	_Width(A5),D3		; Pixelwidth of page (64 bit boundary)
	lsr.w	#3,D3			; in bytes
	move.l	_ImageWidth(A5),D4	; Aligned width (16 bit boundary)
	lsr.l	#4,D4			; in words
	move.w	_Height(A5),D5		; Number of lines
	move.b	_Depth(A5),D6		; Number of planes

*	A0 - original Datas
*	A2 - BitPlane-Address-Array
*	D2 - length original Datas
*	D3 - Pagewidth (boundary 64 bit) in bytes (longword)
*	D4 - Image width ( boundary 16 bit)
*	D5 - Height of Image in number of lines
*	D6 - Depth

	subq.w	#1,D4			; 'Cause of DBF
	subq.w	#1,D5			; 'Couse of DBF

	move.w	D4,D1
	move.w	D5,D0

	movea.l	(A2)+,A3		; Out of constant address of bitplane
	movea.l	A3,A4			; ...also in A4
	adda.l	D3,A4			; Next line's address (destination) after comming loop

.copyLine
	move.w	(A0)+,(A3)+		; Store data-word
	subq.l	#2,D2
	beq.w	.finish
	bcs.w	.IncorrectSize
	dbf	D1,.copyLine		; Store this line...

	movea.l	A4,A3			; Next line's address into A3
	adda.l	D3,A4			; Add  bytesize of one line to A4
	move.w	D4,D1			; Image width in number of words
	dbf	D0,.copyLine		; Store next line

	subq.b	#1,D6			; One less bitplane to go...
	beq.w	.finish

* One complete Bitplane stored, so do next
	movea.l	(A2)+,A3		; Next bitplane's address out of constant
	movea.l	A3,A4			; Address also in A4
	adda.l	D3,A4			; Address next line of this Bitplane
	move.w	D5,D0			; Number of lines
	move.w	D4,D1			; Image width in number of words
	bra.s	.copyLine		; Store next bitplane


*
** These routines are only called if a mask is set for the picture (brush)
*

_IgnoreMaskLine		; Uncompressed IFF
	move.l	_ImageWidth(A5),D0
	lsr.w	#3,D0
	adda.l	D0,A0
	sub.l	D0,D2
	rts


_IgnoreCompMaskLine	; Compressed IFF
	move.l	D3,-(sp)
	move.l	_ImageWidth(A5),D3
	lsr.w	#3,D3
	moveq	#0,D1


.CheckOperation
	cmp.w	D3,D1
	beq.s	.out

	subq.l	#1,D2			; Data counter
	bmi.s	.out
	moveq	#0,D0
	move.b	(A0)+,D0
	cmpi.b	#-128,D0		; #-128 = no operation
	beq.s	.NoOperation
	cmpi.b	#127,D0
	bhi.s	.StoreNeg		; If negativ (greater #128!)
.CopyBytes
	subq.l	#1,D2
	bmi.s	.out
	addq.l	#1,A0			; Store byte of mask to nowhere...
	addq.w	#1,D1
	dbf	D0,.CopyBytes
	bra.s	.NoOperation
.StoreNeg
	neg.b	D0			; To positive value
	subq.l	#1,D2
	bmi.s	.out
	addq.l	#1,A0
.StoreNegCopy
	addq.w	#1,D1			; Store byte of mask to nowhere and decrease counter...
	dbf	D0,.StoreNegCopy	; While not all
.NoOperation
	tst.l	D2
	bmi.s	.out
	bra.s	.CheckOperation
.out
	movem.l	(sp)+,D3
	rts

*************************************************************
*
* Init the standard palette (RGB32) to one which contains
* only grey values, so called Grey Palette.
* Since the OS doesn't support 24 bit screens and 3rd party
* GFX boards will not allow custom applications to copy
* 24 bitplanes into a screen they made via OS functions,
* the first 8 bitplanes are treated as they contain only grey
* colours (those 8 which we gonna display).
* When there is a device that will allow to copy 24 bitplanes
* to a screen, Viewer can display it immediately, since
* I never stripped the code to support only 8 bitplanes,
* although 3rd party graphic board software emulation does!
*

_Init24BitPal
	move.l	#256,D0
	lea	_RGB32Colours(A5),A1
	move.l	D0,D1
	swap	D1			; number of colours (1st word) start at colour (2nd word)
	move.l	D1,(A1)+		; store number of entries in table and
*					  startoffset for colours

.GoAhead
	movem.l	D2-D4,-(sp)

	moveq	#0,D1
	moveq	#0,D2
	moveq	#0,D3
	bra.s	.sneek
.convert
	moveq	#2,D4			; 3 loops
.storeOneLW
*	move.b	D1,D1			; the value
	move.b	D1,D3			; save it
	andi.b	#$F,D3			; only low nibble
	move.b	D3,D2			; also in D2
	lsl.b	#4,D2			; store it as high nibble
	add.b	D3,D2			; add low nibble

	move.b	D1,(A1)+		; save high byte of high word
	move.b	D2,(A1)+		; save low byte of high word
	move.b	D2,(A1)+		; save high byte of low word
	move.b	D2,(A1)+		; save low byte of low word

	dbf	D4,.storeOneLW		; for one colour (R, G, B)
	addq.b	#1,D1
.sneek
	dbf	D0,.convert
	moveq	#0,D0
	move.l	D0,(A1)			; terminator!!!

	movem.l	(sp)+,D2-D4
	rts

***************************************************************
*
** Check if the hardware display supports 8 bit per gun as the
** original AMIGA hardware. If not, brighten up the display...
*
** Because only simple device for the AMIGA are available (3rd
** party gfx-boards) this routine might not work perfectly since
** those cards don't work proberly in an AMIGA surround due to
** their limits and not implemented AMIGA features:
** only 3 colour sprites, only one sprite, no soft-scrolling
** screens, no overscan, only one hardware screen, incorrect
** bits per gun (a 256 colour display offers only 262144 colour
** palette) where the original double A chip set offers 16.7 million!)
** and a lot more.
*

_BrightenColours
	movem.l	D0-D2/A0-A1/A6,-(sp)
* GetDisplayInfoData( 0, di, sizeof( di), DTAG_DISP, DisplayID)
	suba.l	A0,A0			; Handle
	lea	_DisplayInfo(A5),A1	; Buffer
	moveq	#dis_SIZEOF,D0		; sizeof
	move.l	#DTAG_DISP,D1		; TAG
	move.l	_ViewPortMod(A5),D2	; DisplayID
	movea.l	_GfxBase(A5),A6
	cmpi.w	#38,LIB_VERSION(A6)
	beq.s	.done			; Since we have not AMIGA OS3...
	jsr	_LVOGetDisplayInfoData(A6)
	tst.l	D0
	beq.s	.done

	lea	_DisplayInfo(A5),A0
	move.b	RedBits(A0),D0
	cmpi.b	#7,D0
	bls.s	.adjust

	move.b	GreenBits(A0),D0
	cmpi.b	#7,D0
	bls.s	.adjust

	move.b	BlueBits(A0),D0
	cmpi.b	#7,D0
	bhi.s	.done

.adjust
* AdjustPal32( struct DisplayInfo *, struct RGB32 *)
	lea	_RGB32Colours(A5),A1
	bsr.s	_AdjustPal32
.done
	movem.l	(sp)+,D0-D2/A0-A1/A6
	rts

***********************************************************
*
** Adjust (brighten) RGB32 colour table values to supported
** less than 8 bits per gun.
*
** This routine was just a quick hack...
*
** Only useful when a simple 3rd party graphic device is
** installed, such as for IBM-compatible computers which are
** adapted to the AMIGA system, e.g. Picasso II(+) & IV,
** Picollo, Picollo SD 64, Retina Z2 & Z3, CyberVision 64,
** CyberVision 64 3D etc. .
** Does the GVP (Spectrum) and the Merlin support 8 bit per
** gun also in non 24 bit displays? If you know, tell me.
*

_AdjustPal32
	movem.l	D2-D7,-(sp)

	btst	#7,_BMHDFlags(A5)	; Indicates if colourmap of file is
	bne.s	.RGB32			; stored as 8-bit values (AGA resolution (RGB32))

*
** This one is to convert the original RGB4 values (now RGB32) to values
** which looks on this simple device (3rd party gfx device) the same as
** with the OCS or ECS CHIP SET.
*
.RGB4
	move.b	RedBits(A0),D5		; e.g. 6
	moveq	#8,D0
	sub.b	D5,D0			; 8 - 6 = 2
	moveq	#16,D5
	mulu.w	D0,D5			; = 16

	move.b	GreenBits(A0),D6	; e.g. 5
	moveq	#8,D0
	sub.b	D6,D0			; 8 - 5 = 3
	moveq	#16,D6
	mulu.w	D0,D6			; = 24

	move.b	BlueBits(A0),D7		; e.g. 4
	moveq	#8,D0
	sub.b	D7,D0			; 8 - 4 = 4
	moveq	#16,D7
	mulu.w	D0,D7			; = 32
	bra.s	.doit

*
** This one to adjust palette to reflect less bits per gun as the AA (AGA) hardware.
*
.RGB32
	moveq	#0,D0
	move.b	RedBits(A0),D0		; e.g. 6
	moveq	#32,D1			; = 32 (256 luminanz / 8 bit per luminanz = 32)
	mulu.w	D0,D1			; 6 * 32  = 192
	move.l	#256,D5
	sub.w	D1,D5			; 256 - 192 = 64
	divu.w	D0,D5			; 64 / 6 = ~10

	moveq	#0,D0
	move.b	GreenBits(A0),D0	; e.g. 5
	moveq	#32,D1			; = 32 (256 luminanz / 8 bit per luminanz = 32)
	mulu.w	D0,D1			; 5 * 32  = 160
	move.l	#256,D6
	sub.w	D1,D6			; 256 - 160 = 96
	divu.w	D0,D6			; 96 / 5 = ~19

	moveq	#0,D0
	move.b	BlueBits(A0),D0		; e.g. 4
	moveq	#32,D1			; = 32 (256 luminanz / 8 bit per luminanz = 32)
	mulu.w	D0,D1			; 4 * 32  = 128
	move.l	#256,D7
	sub.w	D1,D7			; 256 - 128 = 128
	divu.w	D0,D7			; 128 / 4 = 32

.doit
	move.l	(A1)+,D0		; Number of colours (1st word, offset colour 2nd word)
	swap	D0			; D0 = number colours used
	bra.s	.dec 
.loop
	move.l	D0,-(sp)		; number of colours

	move.l	(A1),D0			; Colour value (red) (32 bit)
	moveq	#24,D1			; into
	lsr.l	D1,D0			; lowest byte
	add.w	D5,D0
.adjred
	cmpi.w	#255,D0			; Range check
	bls.s	.okred
	move.l	#255,D0
.okred	
	bsr.s	.storeNew

	move.l	(A1),D0			; Colour value (green) (32 bit)
	moveq	#24,D1			; into
	lsr.l	D1,D0			; lowest byte
	add.w	D6,D0
.adjgreen
	cmpi.w	#255,D0			; Range check
	bls.s	.okgreen
	move.l	#255,D0
.okgreen
	bsr.s	.storeNew

	move.l	(A1),D0			; Colour value (blue) (32 bit)
	moveq	#24,D1			; into
	lsr.l	D1,D0			; lowest byte
	add.w	D7,D0
.adjblue
	cmpi.w	#255,D0			; Range check
	bls.s	.okblue
	move.l	#255,D0
.okblue	
	bsr.s	.storeNew

	move.l	(sp)+,D0
.dec
	subq.w	#1,D0
	bcc.s	.loop
	
	movem.l	(sp)+,D2-D7
	rts

.storeNew
	move.w	D0,D1
	lsl.w	#8,D0
	andi.w	#$F,D1			; Only low nible
	move.b	D1,D0
	lsl.b	#4,D1
	or.b	D0,D1
	move.b	D1,D0
	lsl.l	#8,D0
	move.b	D1,D0
	lsl.l	#8,D0
	move.b	D1,D0
	move.l	D0,(A1)+		; Store new computed red value
	rts

********************************************************
* V39 RGB32 format
*
* Highest byte of longword contains colour-value, e.g. 237 (0xED).
* The rest (lower 3 bytes) containing the low nibble of
* the highest byte, here 13, fully:
* ED DD DD DD == 0xEDDDDDDD
*
* Inputs: D0 - number of colours to convert (max. 256)
*         A0 - RGB source table (like CMAP chunk)
*         A1 - RGB32 destionation buffer (safety = (256*3+2)*4 bytes large)
* Results: RGB32 buffer filled with 32bit RGB values (used by LoadRGB32, SA_Colors32)
*          D0 == -1L on error (too much colours, max. 256)

_RGBtoRGB32 	; (colours, tableRGB, tableRGB32)(D0, A0, A1)
	andi.l	#$1FF,D0		; max 256 colours
	cmpi.w	#256,D0
	bls.s	.cok			; if not more colours
	move.l	#256,D0
.cok
	move.l	D0,D1
	swap	D1			; number of colours (1st word) start at colour (2nd word)
	move.l	D1,(A1)+		; store number of entries in table and
*					  startoffset for colours

	btst	#7,_BMHDFlags(A5)	; Full byte used by colour value?
	bne.s	.GoAhead		; If so...

	cmpi.w	#32,D0			; More than 32 colours?
	bhi.s	.AGA			; Assumption: an AGA-picture where the programmer forgot
*					  to set the bit

	bsr.s	.ModifyColours		; Else take as 4-bit
	bra.s	.GoAhead	

.AGA
	bset	#7,_BMHDFlags(A5)	; Indicates it's valid

.GoAhead
	movem.l	D2-D4,-(sp)

	moveq	#0,D1
	moveq	#0,D2
	moveq	#0,D3
	bra.s	.sneek
.convert
	moveq	#2,D4			; 3 loops
.storeOneLW
	move.b	(A0)+,D1		; get value
	move.b	D1,D3			; save it
	andi.b	#$F,D3			; only low nibble
	move.b	D3,D2			; also in D2
	lsl.b	#4,D2			; store it as high nibble
	add.b	D3,D2			; add low nibble

	move.b	D1,(A1)+		; save high byte of high word
	move.b	D2,(A1)+		; save low byte of high word
	move.b	D2,(A1)+		; save high byte of low word
	move.b	D2,(A1)+		; save low byte of low word

	dbf	D4,.storeOneLW		; for one colour (R, G, B)
.sneek
	dbf	D0,.convert
	moveq	#0,D0
	move.l	D0,(A1)			; terminator!!!

	movem.l	(sp)+,D2-D4
	rts

.failed
	moveq	#-1,D0
	rts

*
** Change 4-bit colour value to 8-bit colour value ( needed for LoadRGB32() )
*
.ModifyColours
	movem.l	D0-D2/A0,-(sp)
	bra.s	2$
1$
	move.b	(A0)+,D1		; Get value
	andi.b	#$F0,D1			; Ignore unused nibble
	move.b	D1,D2			; Save result
	lsr.b	#4,D2			; High nibble to low nibble
	add.b	D2,D1			; Make new value
	move.b	D1,-1(A0)		; Store new computed value
2$
	dbf	D0,1$			; Until all are done
	movem.l	(sp)+,D0-D2/A0
	rts

********************************************************
*
** This routine will only be called before the dimension
** and MonitorID grab is fired up!
*
_CheckEHB
	movem.l	D0-D2/A0-A1,-(sp)

	move.l	_ViewPortMod(A5),D0	; Original (not modified till now)
	andi.l	#V_EXTRA_HALFBRITE,D0
	beq.s	.done

	lea	_RGB32Colours(A5),A0
	move.l	(A0),D0		; Get color offset and amount colors e.g. 0x00200000
	swap	D0		; e.g. 0x00000020
	moveq	#0,D2
	move.w	D0,D2		; Remember amount colors (e.g. 32)
	add.w	D0,D0		; Double amount of colors (e.g. 64)
	swap	D0
	move.l	D0,(A0)+	; Store new amount of colors

	move.l	D2,D0		; Amount colors (e.g. 32)
	move.l	D0,D1		; ditto
	lsl.l	#3,D0		; Amount colors * 8
	lsl.w	#2,D1		; Amount colors * 4
	add.l	D1,D0		; == amount colors in bytes (e.g. 32) * 12)
	lea	0(A0,D0.l),A1	; Destination

	move.l	D2,D0		; e.g. 32
	add.w	D0,D0		; == 64
	add.w	D2,D0		; == 96 runs (== 384 bytes of source to touch)
	bra.s	.loopdec
.loop
	move.l	(A0)+,D1
	lsr.l	#1,D1
	move.l	D1,(A1)+
.loopdec
	dbf	D0,.loop
	clr.l	(A1)
.done
	movem.l	(sp)+,D0-D2/A0-A1
	rts

**************************
*
* Convert binary to ascii.
*
* Inputs: none
* Results: none
*

_ConvertBinary
	movem.l	D2-D7/A2-A4,-(sp)

	move.l	_BufferSize(A5),D2	; Length allocated buffer
	move.l	_FileSize(A5),D3	; Real filelength
	movea.l	_TextPtr(A5),A2		; Adress buffer
	addq.l	#2,A2			; Skip #$020A

	bsr.w	_GetConvertedSize
	move.l	D0,D4			; Save new size
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)
	movea.l	D0,A4			; Save new buffer pointer
	tst.l	D0
	beq.w	.ErrorAlloc		; Upon error
	movea.l	D0,A3			; Address buffer
	move.w	#$200A,(A3)+		; Write Blank and LineFeed


* A4 - allocated buffer - do not scratch
* A3 - allocated buffer - used
* A2 - old datas - used
* D4 - allocated size - do not scratch
* D3 - FileSize - used

	moveq	#0,D7			; New filesize
	moveq	#-16,D5			; Linenumber

	movea.l	A3,A0			; Address buffer
1$
	tst.l	D3			; Soruce file end?
	beq.w	.end			; If so...
	cmpi.l	#15,D3			; Do we have a rest of 4 longwords to convert?
	bls.w	.ARest			; If not...
	addi.l	#16,D5			; Else add 16 bytes (4 longwords)
	move.l	D5,D0			; Line number
	bsr.w	_comhex			; Convert count to ascii
	move.b	#':',(A0)+		; Write colon at end of number
	move.b	#' ',(A0)+		; Write 2 blanks
	move.b	#' ',(A0)+
	addi.l	#11,D7			; New filelength plus 11 bytes

	move.l	(A2),D0			; Get 1. longword of line to convert
	bsr.w	_comhex			; Convert it to ascii
	move.b	#' ',(A0)+		; Write Blank
	addi.l	#9,D7			; New filesize plus 9

	move.l	4(A2),D0		; 2. longword
	bsr.w	_comhex
	move.b	#' ',(A0)+
	addi.l	#9,D7

	move.l	8(A2),D0		; 3. longword
	bsr.w	_comhex
	move.b	#' ',(A0)+
	addi.l	#9,D7

	move.l	12(A2),D0		; 4. longword
	bsr.w	_comhex
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	addi.l	#12,D7

	subi.l	#16,D3			; Old filesize -16
	moveq	#15,D0			; 16 bytes to write
0$
	move.b	(A2)+,D1		; Get byte
	cmpi.b	#31,D1			; Displayable char?
	bls.s	.exchange		; If not
	cmpi.b	#160,D1			; Displayable char?
	bhi.s	.ok			; If so
	cmpi.b	#127,D1			; Displayable char
	bls.s	.ok			; If so
.exchange
	move.b	#'.',(A0)+		; Not displayable, exchange through point
	bra.s	2$
.ok
	move.b	D1,(A0)+		; Displayable...
2$
	dbf	D0,0$			; Number of bytes in one line (16)
	move.b	#10,(A0)+		; Write LineFeed
	addi.l	#17,D7			; New filelength +17
	bra.w	1$	

* ------------ *

.ARest	; Less than 16 bytes....
	addi.l	#16,D5			; Linenumber
	move.l	D5,D0			; Convert linenumber (binary)
	bsr.w	_comhex			; into ascii-chars
	move.b	#':',(A0)+		; Write colon after linenumber
	move.b	#' ',(A0)+
	move.b	#' ',(A0)+
	addi.l	#11,D7			; New filelength +11 bytes

	movea.l	A2,A1			; Address current offset in source file
	move.l	D3,D5			; Rest-length of old file
.longLoop
	cmpi.b	#3,D5			; Less than 3 bytes?
	bls.s	.byteWidth

	subq.l	#4,D5			; Because one longword contains 4 bytes

	move.l	(A1)+,D0		; Get longword to convert
	bsr.w	_comhex			; into ascii
	move.b	#' ',(A0)+
	addi.l	#9,D7			; New filesize plus 9
	bra.s	.longLoop

.byteWidth
	subq.b	#1,D5			; Old filelength -1
	bcs.s	.MakeASCII		; When end is reached
	move.b	(A1)+,D0		; Get byte
	bsr.w	_comhexByte		; and convert it into ascii
	addq.l	#1,D7			; New filelength +1
	bra.s	.byteWidth

.MakeASCII	
	move.l	A0,-(sp)		; Current buffer address
	moveq	#-1,D0			; Counter
3$
	cmpi.b	#10,-(A0)		; Find LineFeed of last line
	dbeq	D0,3$
	not.l	D0			; Compute length
	movea.l	(sp)+,A0		; Current buffer address
	moveq	#49,D1			; At this position we write down the ascii-values
	sub.b	D0,D1
4$
	move.b	#' ',(A0)+		; Write as much Blank until we reach position 49
	addq.l	#1,D7			; New filelength +1
	dbf	D1,4$

	add.l	D3,D7			; Add rest of old filelength to new filelength
	move.l	D3,D0			; Rest
	subq.b	#1,D0			; Because of DBF
5$
	move.b	(A2)+,D1		; Get value
	cmpi.b	#31,D1			; Displayable char?
	bls.s	6$
	cmpi.b	#160,D1			; Displayable char?
	bhi.s	7$
	cmpi.b	#127,D1			; Displayable char?
	bls.s	7$
6$
	move.b	#'.',(A0)+		; Not displayable!
	bra.s	8$
7$
	move.b	D1,(A0)+
8$
	dbf	D0,5$
	bra.w	.end			; ....finish

* --------------- *

.end
	move.b	#10,(A0)		; Last char of file should be a LineFeed
	bsr.w	_FreeFile		; Free old file (buffer)
	move.l	A4,_TextPtr(A5)		; New buffer address
	move.l	D4,_BufferSize(A5)	; New buffer size
	move.l	D7,_FileSize(A5)	; New filesize
	movem.l	(sp)+,D2-D7/A2-A4
	rts

.ErrorAlloc
	lea	_AllocErrTxt(pc),A0	; Display error
	bsr.w	_DisplayError
	bsr.w	_FreeFile		; Free old file
	movem.l	(sp)+,D2-D7/A2-A4
	addq.l	#4,sp
	bra.w	_Loop

_GetConvertedSize
	move.l	_FileSize(A5),D0	; Original
	move.l	D0,D1
	lsl.l	#2,D0			; *4
	lsr.l	#2,D1			; /4
	add.l	D1,D0			; == * 4.25
	addi.l	#76,D0			; For safety
	andi.l	#-8,D0			; Align size
	rts

_comhex
	move.l	D2,-(sp)
	moveq	#7,D1
1$
	rol.l	#4,D0
	move.l	D0,D2
	and.b	#$F,D2
	addi.b	#'0',D2
	cmpi.b	#'9',D2
	bls.s	2$
	addq.b	#7,D2
2$
	move.b	D2,(A0)+
	dbf	D1,1$
	move.l	(sp)+,D2
	rts

_comhexByte
	move.l	D2,-(sp)
	moveq	#1,D1
1$
	rol.b	#4,D0
	move.b	D0,D2
	and.b	#$F,D2
	addi.b	#'0',D2
	cmpi.b	#'9',D2
	bls.s	2$
	addq.b	#7,D2
2$
	move.b	D2,(A0)+
	dbf	D1,1$
	move.l	(sp)+,D2
	rts

******************************************************************************
*
* This routine will extract the ASCII-characters of a `known' document.
* It will only search for each known-chunk, remember the length of it, and
* then it allocates a buffer based on the computed length, and after that,
* it will re-scan the file and copy the plain characters into the new allocated
* buffer.
*
* This routine is rather a joke than useful...
*

_LoadFCFile
	tst.b	_NoWarnFlag(A5)		; Allowed to display warnings?
	bne.s	.doit			; If not...

	lea	_IFFAsciiTxt(pc),A0	; Else, give out this
	bsr.w	_DisplayError		; message

	tst.l	D0			; User said ok.?
	beq.w	_BinaryFile		; If not, don't display...

.doit
	movea.l	_TextPtr(A5),A0		; Start of datas
	addq.l	#2,A0			; Overread $200A ( Blank and LineFeed )
	movea.l	A0,A1
	move.l	_BufferSize(A5),D0	; Get length of buffer
	subq.l	#2,D0			; Because of Blank and LineFeed ($200A)
	move.l	D0,D1
	moveq	#0,D4			; Amount of charcaters

	cmpi.l	#'CAT ',(A0)
	beq.s	.valid
	cmpi.l	#'LIST',(A0)
	beq.s	.valid
	cmpi.l	#'FORM',(A0)		; Check IDs
	bne.w	.errNonStd

	cmpi.l	#'SWRT',8(A0)
	beq.s	.valid
	cmpi.l	#'WOWO',8(A0)
	beq.s	.valid
	cmpi.l	#'FTXT',8(A0)
	bne.w	.errNonStd
.valid
	lea	12(A0),A0		; Pointer to e.g. "HYPH"-chunk
	sub.l	#12,D0

.ChunkName
	cmpi.l	#8,D0			; Less than 9 bytes?
	ble.w	.gotLength		; So call second pass

	move.l	(A0),D3			; Name of chunk
	move.l	4(A0),D2		; Length of chunk

	cmpi.l	#'FORM',D3
	beq.s	.skipType

	cmpi.l	#'CAT ',D3
	beq.s	.skipType

	cmpi.l	#'LIST',D3
	beq.s	.skipType

	cmpi.l	#'PROP',D3
	bne.s	.goon

.skipType
	lea	12(A0),A0
	sub.l	#12,D0
	bra.s	.ChunkName

.goon
	addq.l	#8,A0			; Overread chunk-name and its size setting
	subq.l	#8,D0			; Rest of filelength
	bmi.w	.errIncomplete		; Upon error

	cmpi.l	#'CHRS',D3		; Characters?
	beq.s	.addLength

	cmpi.l	#'RULE',D3		; "RULE"-chunk treated as LineFeed
	beq.s	.addLF

	cmpi.l	#'WTXT',D3		; "WTXT"-chunk treated as text
	beq.s	.addLength

	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0			; Rest of filelength
	bra.s	.ChunkName		; and scan...

.addLength	; CHRS-chunk found
	tst.l	D2			; CHRS-chunk with size zero?
	bne.s	.asciichars		; If size set

	addq.l	#1,D4			; else size == 0 so set a LineFeed
	bra.s	.next

.asciichars
	add.l	D2,D4			; else add size

.next
	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0
	bra.w	.ChunkName

.addLF	; RULE-chunk is treated as a LineFeed
	addq.l	#1,D4			; Size plus 1

	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0
	bra.w	.ChunkName

*****************************
* Parsing done ( first pass )
* Now allocate the buffer and
* store the characters.

.gotLength
	move.l	_PageWidth(A5),D7	; Limit for word-wrap

	move.l	D4,D5			; Size of characters
	add.l	#15,D5			; Plus 7 and! plus 8 bytes (8-Bytes = $200A at front and $0A
*					  at end of datas ( rest for safety ))
	andi.l	#-8,D5			; Make size divisible through eight (round it up)

	movem.l	D1/A1,-(sp)		; Remember source and source's size

	move.l	D5,D0			; Size in bytes
	move.l	#MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)	; Mem demand

	movem.l	(sp)+,D1/A1
	tst.l	D0
	beq.w	.errNoMem		; Upon error

	movea.l	D0,A2			; Destination
	movea.l	A2,A3			; Remember

	move.w	#$200A,(A2)+		; Write first down Blank and LineFeed

	movea.l	A1,A0			; Source
	move.l	D1,D0			; Length source

	lea	12(A0),A0		; Pointer to first important chunk-name (e.g. HYPH)
	subi.l	#12,D0

	moveq	#0,D6			; Amount of chars in line...

.checkChunk
	cmpi.l	#8,D0			; At least 8 bytes?
	ble.w	.done			; else pass 2 ends...

	move.l	(A0),D1			; Name of chunk
	move.l	4(A0),D2		; Length of chunk

	cmpi.l	#'FORM',D1
	beq.s	.noParseYet

	cmpi.l	#'CAT ',D1
	beq.s	.noParseYet

	cmpi.l	#'PROP',D1
	beq.s	.noParseYet

	cmpi.l	#'LIST',D1
	bne.s	.parse

.noParseYet
	lea	12(A0),A0		; Overread e.g. FORM####ANHD
	sub.l	#12,D0			; i.e. point to e.g. DLTA chunk (FORM####ANHDDLTA####)
	bra.s	.checkChunk		;					     ¯¯¯¯

.parse
	addq.l	#8,A0			; Overread chunk-name and its size
	subq.l	#8,D0
	bmi.w	.errIncomplete_1	; Upon error

	cmpi.l	#'CHRS',D1		; Characters?
	beq.s	.copyTxt

	cmpi.l	#'RULE',D1		; Or a ruler which is interpreted as a LineFeed
	beq.w	.SetLF

	cmpi.l	#'WTXT',D1		; Characters?
	beq.s	.copyTxt

	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0
	bra.s	.checkChunk		; And search again...

.copyTxt
	move.l	D2,D1			; Size of this chunk

	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	tst.l	D1			; Chunk-size == 0?
	beq.s	.OnlyLF			; Interpret as linefeed

	movea.l	A0,A1			; Source of characters
	bra.s	.cpy
.cpyChar
	cmpi.b	#9,(A1)			; Tab?
	bne.s	.store			; ...if not
	addq.b	#7,D6			; Else, this char [1] (Tab) + [7]
	andi.b	#-8,D6			; on a position which is divisable by eight
*	subq.b	#1,D6			; Minus 1, because 2 lines further we add one...
.store
	cmpi.b	#$9B,(A1)		; CSI?
	beq.s	.ignoredouble		; Ignore CSI
	cmpi.b	#15,(A1)		; Ignore shift-in etc.
	beq.s	.addLineFeed
	cmpi.b	#16,(A1)
	beq.s	.ignore
	cmpi.b	#17,(A1)
	beq.s	.ignore
	cmpi.b	#18,(A1)
	beq.s	.ignore
	move.b	(A1)+,(A2)+		; Copy characters
	cmpi.b	#10,-1(A2)		; A new line?
	beq.s	.reset
	addq.b	#1,D6			; New line length plus 1
	cmp.b	D7,D6			; Range limit reached?
	bls.s	.cpy			; If not yet reached...
	bra.s	.findterminator		; Else, split line...
.reset
	moveq	#0,D6
	bra.s	.cpy
.addLineFeed
	addq.l	#1,A1
	move.b	#10,(A2)+
	moveq	#0,D6
	bra.s	.cpy

.ignoredouble
	addq.l	#1,A1
	subq.l	#1,D1
	subq.l	#1,D4
.ignore
	addq.l	#1,A1
	subq.l	#1,D4
.cpy
	subq.l	#1,D1			; One less...
	bcc.s	.cpyChar

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0
	bra.w	.checkChunk		; and restart...

.OnlyLF	; <- Chunk-size of CHRS-chunk zero!!!
	move.b	#10,(A2)+		; Add a LineFeed at the end of each line

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0

	moveq	#0,D6			; No chars in this line at the moment!

	bra.w	.checkChunk		; Restart

.SetLF	; <- RULER
	move.b	#10,(A2)+		; Add a LineFeed at the end of each line

	addq.l	#1,D2			; Make chunk-size even
	andi.l	#-2,D2

	add.l	D2,A0			; Pointer to next chunk
	sub.l	D2,D0

	moveq	#0,D6			; No chars in this line at the moment!

	bra.w	.checkChunk		; Restart

.findterminator
	move.l	A2,-(sp)
	subq.l	#1,A2			; Pointer to last stored char
	moveq	#0,D6			; Chars in next line (this line will be split into two part)
.loop
	subq.l	#1,A2			; One less char
	addq.b	#1,D6			; Amount of chars in newline plus one
	cmp.b	D7,D6			; Range checking...
	bhi.s	.err
	cmpi.b	#9,1(A2)		; Tab?
	beq.s	.found			; <- Replace Tab through LineFeed
	cmpi.b	#' ',1(A2)		; Blank
	bne.s	.loop			; If not
.found
	move.b	#10,1(A2)		; Replace Blank or Tab through LineFeed
	movea.l	(sp)+,A2
	bra.s	.cpy

.err					; A line without any Blanks or Tabs
	moveq	#0,D6
	movea.l	(sp)+,A2
	bra.s	.cpy

***** HELLO *****

.done
	move.b	#10,(A2)		; Write as last char of ascii-file the LineFeed!
	addq.l	#1,D4

	bsr.w	_FreeFile		; Free old (not more needed datas)

	move.l	A3,_TextPtr(A5)		; Set up source
	move.l	D4,_FileSize(A5)	; Set up source's size (plain ascii-chars)
	move.l	D5,_BufferSize(A5)	; Set up source's size (extended)
	rts

.errNoMem
	lea	_NoFreeStoreTxt(pc),A0
	bsr.w	_DisplayError
	bra.w	_CheckFile_1		; Set up as binary
.errNonStd
	lea	_NoAsciiDatasTxt(pc),A0
	bsr.w	_DisplayError
	bra.w	_CheckFile_1		; Set up as binary
.errIncomplete_1
	movea.l	A3,A1
	move.l	D4,D0
	movea.l	_SysBase(A5),A6
	jsr	_LVOFreeMem(A6)
.errIncomplete
	lea	_IncompleteIFFTxt(pc),A0
	bsr.w	_DisplayError
	bra.w	_CheckFile_1		; Set up as binary

********************************************************
*
* StrToLong( ULONG mask, char *buffer );
*
*
* Convert an ascii-string into computer internal number.
* Converted are: dual, decimal, signed decimal and
* hexadecimal ascii-strings.
*
* Valid terminators for the string-counts are: NULL-byte,
* tabulator, LineFeed, Blank (Space) and the comma.
*
* Introducion for strings:
* "#" = decimal (max. 10 chars for count)
* ""  = decimal (max. 10 chars for count)
* "+" = decimal (max. 10 chars for count)
*
* "-" = signed decimal (max. 10 chars for count)
*
* "0x" = sedecimal (hexadecimal) (max. 8 chars for count)
* "$"  = sedecimal (hexadecimal) (max. 8 chars for count)
*
* "%"  = dual (max. 32 chars for count)
*
* Inputs:  D0 - when NULL (zero) the routine is working normal.
*		- You can put a key-byte (mask) into D0 - the
*		  subroutine is called then directly without
*		  checking introducing arguments, note: in this
*		  case no introducion has to be set in the ascii-
*		  string, eg: D0 contains the "$" char - then
*		  the ascii-string must be pointed to a plain
*		  text, eg. "0003f000" - result here: converted
*		  string to hexadecimal.
*	   A0 - Pointer to the string which should be converted.
* Results: Count in D0
*	   D1 contains -1L on error
*          A0 points to next argument if no error occured,
*	   otherwise check -1(A0) and (A0) for the error,
*	   it holds the char which caused the error!
*
*

	XDEF	_StrToLong
_StrToLong
	movem.l	D2-D3,-(sp)

*
** When called as C-stub, set following two lines.
*
	;move.l	12(sp),D0
	;move.l	16(sp),A0


	move.w	D0,D2			; Save mask

	moveq	#0,D0			; Count to return
	move.l	D0,D1			; Local count-buffer

	tst.w	D2			; Mask set?
	beq.s	.Sneek			; No, do it normal

	cmpi.b	#'$',D2			; Hexadecimal?
	beq.w	.Hex_01
	cmpi.w	#'0x',D2		; Hexadecimal?
	beq.w	.Hex_01
	cmpi.b	#'#',D2			; Decimal?
	beq.w	.Dec_01
	cmpi.b	#' ',D2			; Decimal?
	beq.w	.Dec_01
	cmpi.b	#'-',D2			; Signed decimal?
	beq.s	.SignedDec_01
	cmpi.b	#'%',D2			; Dual?
	beq.w	.Dual_01

.Sneek
*
** Find chars we have to skip...
*

	cmpi.b	#9,(A0)			; Tab-key?
	beq.s	.Skip
	cmpi.b	#' ',(A0)		; Blank?
	beq.s	.Skip
	cmpi.b	#'!',(A0)		; For complex string arguments
	beq.s	.Skip
	cmpi.b	#'|',(A0)		; For complex string arguments
	beq.s	.Skip
	cmpi.b	#',',(A0)		; Comma?
	beq.s	.Skip
	cmpi.b	#';',(A0)		; Semicolon?
	beq.s	.Skip
*
** Check if an interrupted end...
*
	tst.b	(A0)			; End?
	beq.w	.Error_StringToLong
	cmpi.b	#10,(A0)		; CR (LF)?
	beq.w	.Error_StringToLong
*
** Parse argument (string's introducion)...
*
	cmpi.b	#'-',(A0)		; Minus-char?
	beq.s	.SignedDec
	cmpi.b	#'+',(A0)		; Plus-char?
	beq.w	.Dec
	cmpi.b	#'$',(A0)		; Hex-char?
	beq.s	.Hex
	cmpi.b	#'%',(A0)		; Dual-char?
	beq.w	.Dual
	cmpi.b	#'#',(A0)		; Sometimes used for decimal introducion
	beq.w	.Dec
	cmpi.b	#'0',(A0)		; Zero-char?
	bne.w	.Dec_01
	cmpi.b	#'x',1(A0)		; 0x == C-introducion for hex
	bne.w	.Dec_01
	addq.l	#1,A0			; Overread '0' of '0x'
	bra.s	.Hex

* ----------------------- *

.Skip
	addq.l	#1,A0
	bra.s	.Sneek

* ----------------------- *

.SignedDec
	addq.l	#1,A0			; Overread sign
.SignedDec_01
	moveq	#9,D2			; 10 chars to convert
.SDC
	tst.b	(A0)			; End?
	beq.s	.End_SDC
	cmpi.b	#9,(A0)			; Tab-key?
	beq.s	.End_SDC
	cmpi.b	#10,(A0)		; CR (LF)-key?
	beq.s	.End_SDC
	cmpi.b	#' ',(A0)		; Blank-key?
	beq.s	.End_SDC
	cmpi.b	#',',(A0)		; Comma-key?
	beq.s	.End_SDC

	move.b	(A0)+,D1		; Get char
	cmpi.b	#'0',D1
	blt.w	.Error_StringToLong
	cmpi.b	#'9',D1
	bhi.w	.Error_StringToLong
	subi.b	#48,D1			; Computer intern number
	move.l	D0,D3			; Save D0
	lsl.l	#3,D0			; D0 * 8
	add.l	D3,D3			; D3 * 2
	add.l	D3,D0			; == mulu.l #10,D0
	add.l	D1,D0			; Store new nibble
	dbf	D2,.SDC
.End_SDC
	neg.l	D0
	bra.w	.End_StringToLong

* ----------------------- *
.Hex
	addq.l	#1,A0			; Overread introducion
.Hex_01
	moveq	#7,D2			; 8 chars to convert
.HC
	tst.b	(A0)			; End?
	beq.w	.End_StringToLong
	cmpi.b	#9,(A0)			; Tab-key?
	beq.w	.End_StringToLong
	cmpi.b	#10,(A0)		; CR (LF)-key?
	beq.w	.End_StringToLong
	cmpi.b	#' ',(A0)		; Blank-key?
	beq.w	.End_StringToLong
	cmpi.b	#',',(A0)		; Comma-key?
	beq.w	.End_StringToLong

	move.b	(A0)+,D1		; Get char
	cmpi.b	#'0',D1			; 0-char?
	blt.w	.Error_StringToLong
	cmpi.b	#'9',D1			; 9-char
	bls.s	.OkHC

	bclr.l	#5,D1			; To uppercase
	cmpi.b	#'F',D1			; F-char
	bhi.w	.Error_StringToLong
	cmpi.b	#'A',D1			; A-char?
	blt.w	.Error_StringToLong
	subi.b	#55,D1
	lsl.l	#4,D0			; Room for nibble
	or.l	D1,D0			; Store new nibble
	dbf	D2,.HC	
	bra.w	.End_StringToLong
.OkHC	
	subi.b	#48,D1			; Computer intern number
	lsl.l	#4,D0			; Room for nibble
	or.l	D1,D0			; Store new nibble
	dbf	D2,.HC
	bra.w	.End_StringToLong

* ----------------------- *
.Dec
	addq.l	#1,A0			; Overread introducion
.Dec_01
	moveq	#9,D2			; 10 chars to convert
.DC
	tst.b	(A0)			; End?
	beq.w	.End_StringToLong
	cmpi.b	#9,(A0)			; Tab-key?
	beq.s	.End_StringToLong
	cmpi.b	#10,(A0)		; CR (LF)-key?
	beq.s	.End_StringToLong
	cmpi.b	#' ',(A0)		; Blank-key?
	beq.s	.End_StringToLong
	cmpi.b	#',',(A0)		; Comma-key?
	beq.s	.End_StringToLong

	move.b	(A0)+,D1		; Get char
	cmpi.b	#'0',D1
	blt.s	.Error_StringToLong
	cmpi.b	#'9',D1
	bhi.s	.Error_StringToLong
	subi.b	#48,D1			; Computer intern number
	move.l	D0,D3			; Save D0
	lsl.l	#3,D0			; D0 * 8
	add.l	D3,D3			; D3 * 2
	add.l	D3,D0			; == mulu.l #10,D0
	add.l	D1,D0			; Store new nibble
	dbf	D2,.DC
	bra.s	.End_StringToLong

* ----------------------- *

.Dual
	addq.l	#1,A0			; Overread '%'
.Dual_01
	moveq	#31,D2			; 32 chars to convert
.DUC
	tst.b	(A0)			; End?
	beq.s	.End_StringToLong
	cmpi.b	#9,(A0)			; Tab-key?
	beq.s	.End_StringToLong
	cmpi.b	#10,(A0)		; CR (LF)-key?
	beq.s	.End_StringToLong
	cmpi.b	#' ',(A0)		; Blank-key?
	beq.s	.End_StringToLong
	cmpi.b	#',',(A0)		; Comma-key?
	beq.s	.End_StringToLong
	cmpi.b	#'.',(A0)		; A dot set between?
	beq.s	.Skip_Dot

	move.b	(A0)+,D1		; Get char
	subi.b	#48,D1			; Computer internal number
	cmpi.b	#1,D1
	bhi.s	.Error_StringToLong
	add.l	D0,D0			; Base = 2 - so add it!
	add.l	D1,D0			; Add also new count
	dbf	D2,.DUC
	bra.s	.End_StringToLong

.Skip_Dot
	addq.l	#1,A0
	bra.s	.DUC
* ----------------------- *

.Error_StringToLong
	movem.l	(sp)+,D2-D3
	moveq	#-1,D1
	rts

.End_StringToLong
	movem.l	(sp)+,D2-D3
	moveq	#0,D1
	rts

* ----------------------------------------------------- *
*							*
*							*
*			Data Array			*
*							*
*							*
* ----------------------------------------------------- *

_Divutable
	dc.l	1000000000
	dc.l	100000000
	dc.l	10000000
	dc.l	1000000
	dc.l	100000
	dc.l	10000
	dc.l	1000
	dc.l	100
	dc.l	10
	dc.l	1


_Image.1
	dc.w	0,0,74,19,%1
	dc.l	0
	dc.b	%1,%10			; Plane pick, plane off
	dc.l	0

_Image.2
	dc.w	0,0,74,19,%1
	dc.l	0
	dc.b	%1,%10			; Plane pick, plane off
	dc.l	0

_Image.3
	dc.w	0,0,45,28,%11
	dc.l	0
	dc.b	%11,%0			; Plane pick, plane off
	dc.l	0

_Image.4
	dc.w	0,0,45,28,%11
	dc.l	0
	dc.b	%11,%0			; Plane pick, plane off
	dc.l	0

_Channels
	dc.b	1,2,4,8			; One of those channels I want to allocate...

_GStr1
	dc.b	'Ok',0
_GStr2
	dc.b	'Abort',0
_ScreenName
	dc.b	'Viewer''s image screen',0
_WindowName
	dc.b	' Viewer V4.4 - © 92-99 ONIX',0
_IntuitionName
	dc.b	'intuition.library',0
_GfxName
	dc.b	'graphics.library',0
_DiskFontName
	dc.b	'diskfont.library',0
_DeviceName
	dc.b	'console.device',0
_AudioName
	dc.b	'audio.device',0
_ReqToolsName
	dc.b	'reqtools.library',0
_ArpName
	dc.b	'arp.library',0
_CyberGfxName
	dc.b	'cybergraphics.library',0

_AWTitle
	dc.b	'Load A File...',0
_SaveTitle
	dc.b	'Save Text File As...',0
_PageDef
	dc.b	'SCROLLWIDTH=',0
_WindowDef
	dc.b	'EXTENTWINDOW=',0
_WrapDef
	dc.b	'WRAP=ON',0
_FontSpecName
	dc.b	'FONT=',0
_OffsetSpecName
	dc.b	'WINDOWOFFSET=',0
_NoWarningName
	dc.b	'NOWARN',0
_NoCheckPrinterTxt
	dc.b	'NOPRTCHECK',0
_ExecuteTxt
	dc.b	'EXECUTE=',0
_NilName
	dc.b	'NIL:',0
* --------------------------------------------------- *

_HelpText
	dc.b	$9B,'1;31;42m'
	dc.b	'CRSR-down  :-) (n) lines down   ',10
	dc.b	'CRSR-up    :-) (n) lines up     ',10
	dc.b	'CRSR-right :-) line down        ',10
	dc.b	'CRSR-left  :-) line up          ',10
	dc.b	'L-Key      :-) load new file    ',10
	dc.b	'E-Key      :-) enlarge window   ',10
	dc.b	'H-Key      :-) this page        ',10	
	dc.b	'A-Key      :-) about page       ',10
	dc.b	'R-Key      :-) restore page     ',10
	dc.b	'T/B-Keys   :-) toggle Top/Bottom',10 
	dc.b	'HOME/END   :-) toggle Top/Bottom',10
	dc.b	'PgUp/PgDn  :-) PageUp/PageDown  ',10
	dc.b	'Ret/Enter  :-) one line down    ',10
	dc.b	'SHIFT-R    :-) single step back ',10	
	dc.b	'S_KEY      :-) search for string',10
	dc.b	'N-Key      :-) next occurrence  ',10	
	dc.b	'P/F        :-) file to prt/file ',10
	dc.b	'W/C-Keys   :-) page to prt/file ',10 
	dc.b	'PrtSc      :-) page to prt      ',10 
	dc.b	$1B,'[0m'
						
	dc.b	$9B,$48					; Cursor Home
	dc.b	$9B,'33C','  For more details read',10
	dc.b	$9B,'33C','  Viewer.doc.',10,10
	dc.b	$9B,'33C','  Press any key to continue.',10
_HelpTextEnd


_SearchText
	dc.b	$1B,'c',10,$1B,'[1mSearch for: ',$1B,'[0m'
_SearchTextEnd

*
** The first byte of a string contains the upper offset (Y-coordinate)
** where the text start (X-offset is computed). A linefeed (10) tells
** that a second (or more) string line(s) follow. NULL indicates the
** end of the string(s).
** If you have strings which only contain one line, the linefeed must
** also be set, also the NULL-byte (i.e. "30,'Decrunching failed!',10,0").
*

_NoFileMsg
	dc.b	22,'You didn''t pick a file.',10
	dc.b	'Press key "L" to load one.',10,0
_ErrorOpenWindowTxt
	dc.b	8,'Couldn''t open main-window with',10
	dc.b	'leftedge at %d, topedge at %d -',10
	dc.b	'with a width of %d pixels and a',10
	dc.b	'height of %d rows!',10,0
_ErrorOpenDevTxt
	dc.b	22,'Couldn''t open the',10
	dc.b	'"console.device". Terminating.',10,0
_EmptyTxt
	dc.b	22,'Selected file contains no',10
	dc.b	'datas. Loading file terminated.',10,0
_DirTxt
	dc.b	22,'You have chosen a directory and',10
	dc.b	'I expected a file.',10,0
_ReadErrTxt
	dc.b	22,'Could not load that file, it',10
	dc.b	'has a read error.',10,0
_OpenFileErrTxt
	dc.b	30,'Could not open file.',10,0
_AllocErrTxt
	dc.b	22,'Impossile to allocate memory',10
	dc.b	'for this file.',10,0
_ExamineErrTxt
	dc.b	30,'DOS function examine failed!',10,0
_LockErrTxt
	dc.b	22,'Cannot get lock of file, thus',10
	dc.b	'I cannot examine the file!',10,0
_ObjectFileTxt
	dc.b	8,'The selected file is an object',10
	dc.b	'module, shall I display its',10
	dc.b	'contents?',10
	dc.b	'(Converted size: %ld bytes)',10,0
_BinaryFileTxt
	dc.b	8,'The selected file contains ',10
	dc.b	'binary datas.',10
	dc.b	'Shall I display them?',10
	dc.b	'(Converted size: %ld bytes)',10,0
_NoReqTxt
	dc.b	22,'Impossible to work without',10
	dc.b	'ReqTools or Arp libraries!',10,0
_OpenPrintErrTxt
	dc.b	22,'Unable to open file or printer',10
	dc.b	'for output. Printjob aborted.',10,0
_WriteErrTxt
	dc.b	22,'Error while printing file.',10
	dc.b	'Printjob aborted.',10,0
_PrintFileTxt
	dc.b	30,'Going to write whole file...',10,0
_PrintContentsTxt
	dc.b	30,'Going to write window contents...',10,0
_PrintCancelTxt
	dc.b	30,'Job cancelled.',10,0
_PrinterOFFTxt
	dc.b	16,'Printer is turned off or',10
	dc.b	'there is no printer.',10
	dc.b	'Printing failed.',10,0
_NotOnelineTxt
	dc.b	22,'Your printer is not online.',10
	dc.b	'Printing failed.',10,0

* - These messages I love... -

_AboutTxt
	dc.b	8,'Date: 12/08/1999  10:22:29 pm',10
	dc.b	'Programmer: Joerg van de Loo.',10
	dc.b	'Simple text, binary and image viewer.',10
	dc.b	'Granted to use free of charge.',10,0
_InfoTxt
	dc.b	8,'CODE %ld - DATA %ld bytes,',10
	dc.b	'DATA-CHIP = %ld bytes,',10
	dc.b	'BSS = %ld bytes.',10
	dc.b	'Assembled with HiSoft Devpac Amiga.',10,0

* - Messages for PowerPacker(.library) support -

_PPCrunchTxt
	dc.b	8,'This is a PowerPacker',10
	dc.b	'(library) packed file.',10
	dc.b	'Unpacked length: %ld bytes.',10
	dc.b	'Shall I unpack it?',10,0

_DecrunchErrTxt
	dc.b	30,'Decrunching failed!',10,0

* - Message for displaying/loading pictures -

_ILBMTxt
	dc.b	22,'This is an IFF-ILBM file.',10
	dc.b	'Shall I display it?',10,0
_ACBMTxt
	dc.b	22,'This is an IFF-ACBM file.',10
	dc.b	'Shall I display it?',10,0
_ImageInfoTxt
	dc.b	8,'Screen: %d * %d pixels.',10
	dc.b	'Bitmap: %d * %d pixels.',10
	dc.b	'Image: %d * %d pixels.',10
	dc.b	'%ld colours, %ld bytes.',10,0
_WarnMaskingTxt
	dc.b	8,'WARNING:',10
	dc.b	'IFF makes use of masking.',10
	dc.b	'This isn''t 100% supported.',10
	dc.b	'Strange output may occur!',10,0
_WarnUncompressedTxt
	dc.b	22,'INFORMATION:',10
	dc.b	'IFF already uncompressed.',10,0
_IncorrectSizeTxt
	dc.b	22,'ERROR:',10
	dc.b	'Corrupt IFF-file!',10,0
_NoByteRunTxt
	dc.b	22,'ERROR:',10
	dc.b	'Unknown compression method!',10,0
_AllocBufErrTxt
	dc.b	30,'Error allocating bitmaps!',10,0
_NoIFFFileTxt
	dc.b	22,'Bad or incomplete IFF!',10
	dc.b	'Perhaps only a palette file?',10,0
_ErrorOpeningScreen
	dc.b	22,'Can''t open monitor/screen...',10
	dc.b	'Too many bitplanes?!?!?',10,0
_ErrorInvalidIDTxt
	dc.b	16,'Cannot find right monitor for',10
	dc.b	'installed alien gfx-board which',10
	dc.b	'does support this resolution!',10,0

* - Messages for converting IFF to ASCII -

_IFFAsciiTxt
	dc.b	16,'This IFF-file perhaps',10
	dc.b	'contains embedded strings.',10
	dc.b	'Shall I try to extract them?',10,0
_NoFreeStoreTxt
	dc.b	16,'Cannot allocate buffer',10
	dc.b	'to store plain ASCII-',10
	dc.b	'characters. Extracting aborted',10,0
_NoAsciiDatasTxt
	dc.b	16,'This file does not contain',10
	dc.b	'ASCII-characters at all or I',10
	dc.b	'cannot handle them!',10,0
_IncompleteIFFTxt
	dc.b	16,'IFF-file does not contain',10
	dc.b	'all chunks it should have.',10
	dc.b	'Incomplete (bad) IFF-file!',10,0

* - Messages for audio files -

_8SVXTxt
	dc.b	22,'This is an audio file.',10
	dc.b	'Shall I make it audible?',10,0
_8SVXErrTxt
	dc.b	8,'Error during setup of',10
	dc.b	'8SVX file. VHDR on invalid',10
	dc.b	'position or I simply ran out of',10
	dc.b	'memory!',10,0
_AudErrTxt
	dc.b	22,'Error while attempting to make',10
	dc.b	'datas audible; channel stolen?',10,0

* - The standard...

_ProgID
	dc.b	'$VER: Viewer 4.4 (12.08.99)'
*			        ^^^^
*			   Internal: 4
	dc.b	'© 1992-99 J.v.d.Loo (ONIX) - IFF-TEXT/ILBM/ACBM/8SVX viewer; RTG emulation.',0
_EndDatas

****************************************************************
*
* Image-data. Datas for gadgets, 1 colour, 190 bytes (for each).
*

	SECTION	GadgetImage,DATA_C
_Gad.1
	dc.w	$AAAA,$AAAA,$AAAA,$AAAA,$AAC0,$D555,$5555,$5555,$5555,$55C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$C000,$0000,$0000,$0000,$01C0
	dc.w	$A000,$0000,$0000,$0000,$01C0,$DFFF,$FFFF,$FFFF,$FFFF,$FFC0
	dc.w	$FFFF,$FFFF,$FFFF,$FFFF,$FFC0

_Gad.2
	dc.w	$FFFF,$FFFF,$FFFF,$FFFF,$FFC0,$FFFF,$FFFF,$FFFF,$FFFF,$FEC0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$E000,$0000,$0000,$0000,$00C0
	dc.w	$E000,$0000,$0000,$0000,$0140,$EAAA,$AAAA,$AAAA,$AAAA,$AAC0
	dc.w	$D555,$5555,$5555,$5555,$5540

*
** Normal Audio Image: 45 x 28 x 2, bitmap: 48 x 28 x 2 (336 bytes)
*
_AudioGad.1_1
	dc.w	$0000,$0000,$0000,$0000,$0000,$0008,$0000,$0000,$0008,$0000
	dc.w	$0400,$0048,$0000,$0A00,$0048,$0000,$1A00,$0048,$0000,$2A00
	dc.w	$0048,$0000,$4A00,$0048,$003C,$8A00,$0048,$0043,$8A00,$0048
	dc.w	$0042,$8A00,$0048,$0042,$8A00,$0048,$0042,$8A00,$0048,$0042
	dc.w	$8A00,$0048,$0042,$8A00,$0048,$0042,$8A00,$0048,$0042,$8A00
	dc.w	$0048,$0043,$8A00,$0048,$003C,$8A00,$0048,$0000,$4A00,$0048
	dc.w	$0000,$2A00,$0048,$0000,$1A00,$0048,$0000,$0A00,$0048,$0000
	dc.w	$0400,$0048,$0FFF,$FFFF,$FFC8,$0000,$0000,$0008,$0000,$0000
	dc.w	$0008,$7FFF,$FFFF,$FFF8
_AudioGad.1_2
	dc.w	$FFFF,$FFFF,$FFF8,$8000,$0000,$0000,$8000,$0000,$0000,$9FFF
	dc.w	$FBFF,$FF80,$9555,$5455,$5500,$9555,$4455,$5500,$9555,$5455
	dc.w	$5500,$9555,$3455,$5500,$9541,$7455,$5500,$953C,$7455,$5500
	dc.w	$953D,$7455,$5500,$953D,$7455,$5500,$953D,$7455,$5500,$953D
	dc.w	$7455,$5500,$953D,$7455,$5500,$953D,$7455,$5500,$953D,$7455
	dc.w	$5500,$953C,$7455,$5500,$9540,$7455,$5500,$9540,$3455,$5500
	dc.w	$9550,$5455,$5500,$9555,$4455,$5500,$9555,$5455,$5500,$9555
	dc.w	$5155,$5500,$9000,$0000,$0000,$8000,$0000,$0000,$8000,$0000
	dc.w	$0000,$8000,$0000,$0000

*
** Select Audio Image: 45 x 28 x 2, bitmap: 48 x 28 x 2 (336 bytes)
*
_AudioGad.2_1
	dc.w	$FFFF,$FFFF,$FFF0,$8000,$0000,$0000,$8000,$0200,$4000,$8000
	dc.w	$0500,$8000,$8000,$0D01,$0020,$8000,$1502,$0020,$8000,$2504
	dc.w	$0020,$801E,$4500,$1820,$8021,$C500,$6020,$8021,$4501,$8020
	dc.w	$8021,$4500,$0020,$8021,$4500,$0020,$8021,$4500,$FC20,$8021
	dc.w	$4500,$0020,$8021,$4500,$0020,$8021,$4501,$8020,$8021,$C500
	dc.w	$6020,$801E,$4500,$1820,$8000,$2504,$0020,$8000,$1502,$0020
	dc.w	$8000,$0D01,$0020,$8000,$0500,$8020,$8000,$0200,$4020,$8000
	dc.w	$0000,$0020,$8000,$0000,$0020,$87FF,$FFFF,$FFE0,$8000,$0000
	dc.w	$0000,$8000,$0000,$0000
_AudioGad.2_2
	dc.w	$0000,$0000,$0008,$0000,$0000,$0008,$0000,$0000,$0008,$0000
	dc.w	$0200,$0008,$0FFF,$F27E,$EFC8,$0AAA,$AA28,$8A88,$0AAA,$9A2A
	dc.w	$AA88,$0AA0,$BA2A,$2288,$0A9E,$3A2A,$8A88,$0A9E,$BA2A,$2888
	dc.w	$0A9E,$BA2A,$A288,$0A9E,$BA2A,$8A88,$0A9E,$BA2A,$0288,$0A9E
	dc.w	$BA2A,$AA88,$0A9E,$BA2A,$8088,$0A9E,$BA2A,$2A88,$0A9E,$3A2A
	dc.w	$8A88,$0AA0,$3A2A,$8288,$0AA0,$1A2A,$A288,$0AA8,$2A28,$A888
	dc.w	$0AAA,$A22A,$AA88,$0AAA,$AA2A,$2A88,$0AAA,$A82A,$AA88,$0AAA
	dc.w	$AA2A,$8A88,$0AAA,$AA2A,$AA88,$0800,$0000,$0008,$0000,$0000
	dc.w	$0008,$7FFF,$FFFF,$FFF8

	END
