;==================================================================
;===
;===	Name:	Console Library
;===
;===	Author:	Bjørn Reese
;===
;===	This source is Public Domain.
;===
;==================================================================

;--- Comment ------------------------------------------------------
;
; TAB = 8	;	POINTER = ^
;
; Source is rather messy and it could have been better documented
; but I'm really to lazy.
;
; The label convention used in this source is descriped in the
; article "PROGDOC.ART". If you're not in possesion of it just
; ignore the leading lower case letters of the labels.
;
; Keep the code PC-relative and ReEntrant!
; ( i.e. local variables on stack [ with LINK ] )
;
;------------------------------------------------------------------

;--- System -------------------------------------------------------

DEBUG	= 1	;0 = No Debugging

	INCDIR	INCLUDE:

vir	REG	d2-d7/a2-a6	;Very Important Registers
all	REG	d0-d7/a0-a6

TRUE	= 0
FALSE	= -1

;--- Include ------------------------------------------------------

	INCLUDE	exec/resident.i
	INCLUDE	exec/nodes.i
	INCLUDE	exec/lists.i
	INCLUDE	exec/initializers.i
	INCLUDE	exec/libraries.i
	INCLUDE	exec/exec_lib.i
	INCLUDE	exec/ports.i
	INCLUDE	exec/memory.i
	INCLUDE	graphics/text.i
	INCLUDE	libraries/dos_lib.i
	INCLUDE	devices/inputevent.i
	INCLUDE	devices/conunit.i
	INCLUDE	intuition/intuition_lib.i
	INCLUDE	intuition/intuition.i
	INCLUDE	work/con_lib.i		;or whereever you got them.
	INCLUDE	work/con.i

_LVORawKeyConvert	= -48
ThisTask		= 276
CSI			= 155

IEQUALIFIER_SHIFT	= IEQUALIFIER_LSHIFT!IEQUALIFIER_RSHIFT
IEQUALIFIER_COMMAND	= IEQUALIFIER_LCOMMAND!IEQUALIFIER_RCOMMAND
IEQUALIFIER_ALT		= IEQUALIFIER_LALT!IEQUALIFIER_RALT

;--- Macro --------------------------------------------------------

CALL:	MACRO	;Call System Function	name
	jsr	_LVO\1(a6)
	ENDM

PUSH:	MACRO	;Push to stack		reg-list
	movem.l	\1,-(sp)
	ENDM

PULL:	MACRO	;Pull from stack	reg-list
	movem.l	(sp)+,\1
	ENDM

DLINK:	MACRO	;Dynamic Link		An,<ea>
	move.l	\1,-(sp)
	move.l	sp,\1
	suba.w	\2,sp
	ENDM

ABSW:	MACRO	;Absolute Value Word	<ea>
	addq.w	#1,\1
	and.w	#-2,\1
	ENDM

RETURN:	MACRO	;Return			{ Error [-127..128] }
	IF	NARG=0
	moveq	#0,d0
	ELSE
	moveq	#\1,d0
	ENDC
	rts
	ENDM


;--- Constant -----------------------------------------------------

cVersion	= 2
cRevision	= 0
cPriority	= 0

cAcceptBufferSize= 30


;==================================================================
;==================================================================
;===								===
;===			CODE  AREA				===
;===								===
;==================================================================
;==================================================================

	SECTION	ConLib,CODE

	IFNE	DEBUG
start:	jmp	DebugCode
	ENDC

;------------------------------------------------------------------
;	@IllegalStart
;------------------------------------------------------------------
;
; If Library is executed it will perform this procedure, which
; displays an error message on Standard Output Stream.
;
;------------------------------------------------------------------

IllegalStart:
	move.l	$0004.w,a6		;If Library is executed
	move.l	378(a6),a0
	lea	sDosName(pc),a1
	CALL	FindName		;Find Dos Library
	move.l	d0,a6
	CALL	Output			;Find Standard Output Stream
	move.l	d0,d1
	beq.s	.End
	pea	sDosText(pc)
	move.l	(sp)+,d2
	move.l	#sDosTextEnd-sDosText,d3
	CALL	Write			;Write Error Text
.End	RETURN	30			;Report an error

;==================================================================
;===
;===	Standard Resident Library Structure
;===
;==================================================================

	CNOP	0,4
RomTag:
	dc.w	RTC_MATCHWORD
	dc.l	RomTag
	dc.l	EndLib
	dc.b	RTF_AUTOINIT
	dc.b	cVersion
	dc.b	NT_LIBRARY
	dc.b	cPriority
	dc.l	sLibName
	dc.l	sLibID
	dc.l	Init
Init:
	dc.l	con_SIZEOF	;Positive BaseSize
	dc.l	LibFuncTable
	dc.l	LibDataTable
	dc.l	LibInit


;------------------------------------------------------------------
LibFuncTable:
	dc.l	LibOpen		;Open Library
	dc.l	LibClose	;Close Library
	dc.l	LibExpunge	;Remove Library
	dc.l	LibExtFunc	;free for expansion

	dc.l	OpenCon
	dc.l	CloseCon
	dc.l	DoFormat
	dc.l	UserNotes
	dc.l	DefineChars
	dc.l	DisplayRaw
	dc.l	Display
	dc.l	Accept
	dc.l	AcceptString
	dc.l	SetMsgHandler
	dc.l	GetInfo
	dc.l	SetGfx
	dc.l	GotoXY
	dc.l	Cursor
	dc.l	Scroll
	dc.l	Convert

	dc.l	-1

;------------------------------------------------------------------
LibDataTable:
	INITBYTE	LH_TYPE,NT_LIBRARY
	INITLONG	LN_NAME,sLibName
	INITBYTE	LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
	INITWORD	LIB_VERSION,cVersion
	INITWORD	LIB_REVISION,cRevision
	INITLONG	LIB_IDSTRING,sLibID
	dc.l	0	

;==================================================================
;===
;===	Private Library Functions
;===
;==================================================================

;------------------------------------------------------------------
;	@LibInit
;------------------------------------------------------------------
;
; Initialize Library.
;
;------------------------------------------------------------------
; IN	d0.l	= ConBase
;	a0.l	= SegList [ from LoadSeg() ]
; OUT	d0.l	= ConBase
;------------------------------------------------------------------

LibInit:
	PUSH	all

	move.l	d0,a4			;--- SET UP LIB VALUES
	move.l	a0,con_SegList(a4)
	clr.l	con_IntBase(a4)
	lea	pSysBase(pc),a1
	move.l	$0004.w,(a1)
	move.l	pSysBase(pc),a6

	moveq	#0,d0			;--- OPEN INTUITION LIBRARY
	lea	sIntName(pc),a1
	CALL	OpenLibrary
	move.l	d0,con_IntBase(a4)

	moveq	#0,d0			;--- OPEN MATHFFP LIBRARY
	lea	sMathName(pc),a1
	CALL	OpenLibrary
	move.l	d0,con_MathBase(a4)

	lea	dWriteReplyPort(pc),a1	;--- MAKE REPLYPORT
	CALL	AddPort

	PULL	all
	rts

;------------------------------------------------------------------
;	@LibOpen
;------------------------------------------------------------------
;
; Open Library.
;
;------------------------------------------------------------------
; IN	a6.l	= ConBase
; OUT	d0.l	= ConBase
;------------------------------------------------------------------

LibOpen:
	addq.w	#1,LIB_OPENCNT(a6)
	bclr	#LIBB_DELEXP,LIB_FLAGS(a6)
	move.l	a6,d0
	rts

;------------------------------------------------------------------
;	@LibClose
;------------------------------------------------------------------
;
; Close Library.
;
; Expunge if (LIB_OPENCNT = 0) AND (LIBB_DELEXP IN LIB_FLAGS)
;
;------------------------------------------------------------------
; IN	a6.l	= ConBase
; OUT	-
;------------------------------------------------------------------

LibClose:
	moveq	#0,d0
	subq.w	#1,LIB_OPENCNT(a6)
	bne.s	.Exit
	btst	#LIBB_DELEXP,LIB_FLAGS(a6)
	beq.s	.Exit
	bra.s	LibExpunge
.Exit	rts


;------------------------------------------------------------------
;	@LibExpunge
;------------------------------------------------------------------
;
; Expunge Library.
;
; This procedure is called if Exec tries to gain some memory.
;
;------------------------------------------------------------------
; IN	a6	= ConBase
; OUT	d0.l	= NULL (Stay in memory)
;		  ! SegList (UnLoadSeg me)
;------------------------------------------------------------------

LibExpunge:
	PUSH	d1-d7/a0-a6
	move.l	a6,a4
	move.l	pSysBase(pc),a6
	tst.w	LIB_OPENCNT(a4)
	bne.s	.DontExpungeYet

	lea	dWriteReplyPort(pc),a1	;--- REMOVE REPLYPORT
	CALL	RemPort

	move.l	con_MathBase(a4),a1	;--- CLOSE MATHFFP LIBRARY
	CALL	CloseLibrary

	move.l	con_IntBase(a4),a1	;--- CLOSE INTUITION LIBRARY
	CALL	CloseLibrary

	move.l	con_SegList(a4),d2
	move.l	a4,a1
	CALL	Remove			;--- REMOVE LIB NODE
	moveq	#0,d0

	move.l	a4,a1			;--- FREE LIB SPACE
	move.w	LIB_NEGSIZE(a4),d0
	suba.l	d0,a1			;PTR = LIBBASE - LIB_NEGSIZE
	add.w	LIB_POSSIZE(a4),d0	;SIZE = LIB_NEGSIZE + LIB_POSSIZE
	CALL	FreeMem
	move.l	d2,d0
	bra.s	.Exit

.DontExpungeYet
	bset	#LIBB_DELEXP,LIB_FLAGS(a4)
	moveq	#0,d0

.Exit	PULL	d1-d7/a0-a6
	rts


;------------------------------------------------------------------
;	@LibExtFunc
;------------------------------------------------------------------
;
; Dummy.
;
;------------------------------------------------------------------

LibExtFunc:
	moveq	#0,d0
	rts


;==================================================================
;===
;===	Public Library Functions
;===
;==================================================================

;------------------------------------------------------------------
;	@OpenCon
;------------------------------------------------------------------
;
; Open a Console Window.
;
; A Console Window is an Intuition Window with console.device
; attached.
;
;------------------------------------------------------------------
; IN	d0.w	= CursorMode
;	a0.l	= Window Struct
; OUT	d0.l	= ConHandle
;------------------------------------------------------------------

vpConBase	SET	-4
vpMyWindow	SET	vpConBase-4
vpConHandle	SET	vpMyWindow-4
vwCursor	SET	vpConHandle-2
vSizeOf		SET	vwCursor

OpenCon:
	PUSH	vir
	link	a4,#vSizeOf
	move.l	a6,vpConBase(a4)
	move.l	a0,vpMyWindow(a4)
	move.w	d0,vwCursor(a4)

	move.l	#MEMF_CLEAR,d1		;--- ALLOC MEMORY FOR ConHandle & WriteIO
	move.l	#cnh_SIZEOF+IOSTD_SIZE,d0
	move.l	pSysBase(pc),a6
	CALL	AllocMem
	move.l	d0,vpConHandle(a4)
	beq.w	.Exit
	move.l	d0,a3
	add.l	#cnh_SIZEOF,d0
	move.l	d0,cnh_WriteIO(a3)
	move.w	#256,cnh_ExLength(a3)	;default for ExLength
	move.w	vwCursor(a4),cnh_CursorStatus(a3)

	move.l	vpMyWindow(a4),a0	;--- OPEN WINDOW
	move.l	nw_IDCMPFlags(a0),d0
	and.l	#~VANILLAKEY,d0		;VANILLAKEY not allowed
	or.l	#RAWKEY,d0		;...we need RAWKEY
	move.l	d0,nw_IDCMPFlags(a0)
	move.l	vpConBase(a4),a6
	move.l	con_IntBase(a6),a6
	CALL	OpenWindow
	move.l	d0,cnh_Window(a3)
	beq.w	.Error1
	move.l	d0,a0
	move.l	wd_UserPort(a0),cnh_UserPort(a3)

	move.l	cnh_WriteIO(a3),a1	;--- OPEN CONSOLE DEVICE
	move.l	cnh_Window(a3),IO_DATA(a1)
	move.l	#nw_SIZE,IO_LENGTH(a1)
	moveq	#0,d0
	moveq	#0,d1
	lea	sConDevName(pc),a0
	move.l	pSysBase(pc),a6
	CALL	OpenDevice
	tst.l	d0
	bne.s	.Error2
	move.l	cnh_WriteIO(a3),a0
	move.l	IO_DEVICE(a0),cnh_CDBase(a3)
	move.l	IO_UNIT(a0),cnh_Unit(a3)

	move.l	cnh_UserPort(a3),a0	;--- MAKE SIGNAL
	move.b	MP_SIGBIT(a0),d0
	moveq	#0,d1
	bset	d0,d1
	move.l	d1,cnh_Signal(a3)

	lea	cnh_EchoTable(a3),a1	;--- MAKE ECHOTABLE
	move.l	#DEFMODE_GET+DEFALFANUM,d0
	bsr	DefineChars

	move.w	vwCursor(a4),d0
	move.l	vpConHandle(a4),a0
	bsr	Cursor

	move.w	#' 0',cnh_PadSpace(a3)		;PadSpace & PadZero
	move.w	#'..',cnh_PadGroup(a3)		;PadGroup & PadString
	move.w	#',E',cnh_DecimalPoint(a3)	;DecimalPoint & FloatE

	move.l	vpConHandle(a4),d0
.Exit	unlk	a4
	PULL	vir
	rts

.Error2	move.l	cnh_Window(a3),a0	;--- CLOSE WINDOW
	move.l	vpConBase(a4),a6
	move.l	con_IntBase(a6),a6
	CALL	CloseWindow

.Error1	move.l	vpConHandle(a4),a1	;--- RELEASE ALL MEMORY
	move.l	#cnh_SIZEOF+IOSTD_SIZE,d0
	move.l	pSysBase(pc),a6
	CALL	FreeMem
	moveq	#0,d0
	bra.s	.Exit

;------------------------------------------------------------------
;	@CloseCon
;------------------------------------------------------------------
;
; Close a Console Window.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
; OUT	-
;------------------------------------------------------------------

vpConBase	SET	-4
vpConHandle	SET	vpConBase-4
vSizeOf		SET	vpConHandle

CloseCon:
	PUSH	vir
	link	a4,#vSizeOf
	move.l	a6,vpConBase(a4)
	move.l	a0,vpConHandle(a4)
	beq.s	.Exit

	move.l	vpConHandle(a4),a3	;--- CLOSE CONSOLE DEVICE
	move.l	cnh_WriteIO(a3),a1
	move.l	pSysBase(pc),a6
	CALL	CloseDevice

	move.l	cnh_Window(a3),a0	;--- CLOSE WINDOW
	move.l	vpConBase(a4),a6
	move.l	con_IntBase(a6),a6
	CALL	CloseWindow

	move.l	vpConHandle(a4),a1	;--- RELEASE ALL MEMORY
	move.l	#cnh_SIZEOF+IOSTD_SIZE,d0
	move.l	pSysBase(pc),a6
	CALL	FreeMem

.Exit	unlk	a4
	PULL	vir
	rts

;------------------------------------------------------------------
;	@UserNotes
;------------------------------------------------------------------
;
; Make a user note.
;
;------------------------------------------------------------------
; IN	d0.w	= Note Number
;	a0.l	= ConHandle
;	a1.l	= ^String [ NULL terminated ]
; OUT	-
;------------------------------------------------------------------

UserNotes:
	lea	cnh_UserNotes(a0),a2
	subq.w	#1,d0
	add.w	d0,d0
	add.w	d0,d0
	and.w	#$000E,d0
	move.l	a1,(a2,d0.w)
	rts

;------------------------------------------------------------------
;	@DoFormat
;------------------------------------------------------------------
;
; Format a text string. Works much like RawDoFmt() or sprintf().
;
; DoFormat supports:
;
;	\ arguments:
;
;		Standard:	n t \ f b r v
;		Non-Standard:	@ B I U C Z[ nnn	(* =chr(nnn)* )
;		User-Defined:	#n			(* n=[1..8] *)
;
;	% arguments:
;
;		d	= signed decimal
;		u	= unsigned decimal
;		x	= hex
;		c	= char
;		s	= string
;		o	= octal
;		b	= binary (NON-STD!!)
;	  (*	e	= float (m.nnnnnnE±xx)	*)
;	  (*	f	= float (mmm.nnnnnn)	*)	For later versions
;	  (*	g	= float (%e or %f)	*)
;
; Format:	%-0xxx.yyy	+	[ s | c ]
; Format:	%-0xxx.yyyl	+	[ d | u | x | o | b ]
;
; [xxx|yyy] = * : get number from arg.list
;		  ( size = word (bit 15-8 unused) )
;
; (* For later versions: Group specifier = .zzz *)
;
;
; Refer to documentation for further detail.
;
;------------------------------------------------------------------
; IN	d0.l	= MaxLen
;	a0.l	= ConHandle
;	a1.l	= String
;	a2.l	= List of Arguments
;	a3.l	= Text Buffer
; OUT	d0.l	= Formatted String
;------------------------------------------------------------------

dof_MINUS	= 1
dof_ZERO	= 2
dof_POINT	= 3
dof_GROUP	= 4
dof_LONG	= 5
dof_NEG		= 6	;Set if decimal is < 0

vpDataStream	SET	-4
vpLastPosition	SET	vpDataStream-4
vlMaxLen	SET	vpLastPosition-4
vlPosition	SET	vlMaxLen-4
vwFieldSize	SET	vlPosition-2
vwLenSize	SET	vwFieldSize-2
vwGroupSize	SET	vwLenSize-2
vsSmallBuffer	SET	vwGroupSize-64
vwSuccess	SET	vsSmallBuffer-2
vSizeOf		SET	vwSuccess

DoFormat:
	movem.l	d1-d7/a0-a3/a5,-(sp)
	link	a4,#vSizeOf
	move.l	d0,vlMaxLen(a4)
	clr.l	vlPosition(a4)
	move.l	a1,vpDataStream(a4)
	bra.s	.Next
.Normal	bsr.s	PutCharFunc
.Next	clr.w	vwSuccess(a4)
	move.b	(a1)+,d0
	beq.s	.Exit
	cmp.b	#'%',d0
	bne.s	.NotPct
	move.l	a1,vpLastPosition(a4)
	bsr	DoProcent
	tst.w	vwSuccess(a4)
	beq.s	.Next
	move.b	#'%',d0
	bsr.s	PutCharFunc
	move.l	vpLastPosition(a4),a1
	bra.s	.Next
.NotPct	cmp.b	#'\',d0
	bne.s	.Normal
	move.l	a1,vpLastPosition(a4)
	bsr	DoBackSlash
	tst.w	vwSuccess(a4)
	bpl.s	.Next
	move.b	#'\',d0
	bsr.s	PutCharFunc
	move.l	vpLastPosition(a4),a1
	bra.s	.Next
.Exit	bsr.s	PutCharFunc		;Terminating NULL
	move.l	a3,d0
	unlk	a4
	movem.l	(sp)+,d1-d7/a0-a3/a5
	rts

;------------------------------------------------------------------
PutCharFunc:
	move.l	vlPosition(a4),d1
	cmp.l	vlMaxLen(a4),d1
	bge.s	.001
	addq.l	#1,vlPosition(a4)
.001	move.b	d0,(a3,d1.l)
	rts

;------------------------------------------------------------------
;OUT	vwSuccess.w	= Success  (( -1 = Error ))

DoProcent:
	moveq	#0,d3
	move.b	(a1)+,d0
	cmp.b	#'%',d0
	beq	PutCharFunc
	clr.w	vwFieldSize(a4)
	clr.w	vwLenSize(a4)
	clr.w	vwGroupSize(a4)
	cmp.b	#'-',d0		;left-justify?
	bne.s	.001
	bset	#dof_MINUS,d3
	move.b	(a1)+,d0
.001	cmp.b	#'0',d0		;leading zero's?
	bne.s	.002
	bset	#dof_ZERO,d3
	move.b	(a1)+,d0
.002	bsr	GetNumber	;field width?
	tst.w	d1
	bne.s	.005
	move.w	d0,vwFieldSize(a4)
	move.b	(a1)+,d0
.005	cmp.b	#'.',d0		;max len specifier?
	bne.s	.003
	bset	#dof_POINT,d3
	move.b	(a1)+,d0
	bsr	GetNumber	;max len?
	tst.w	d1
	bne.s	.006
	move.w	d0,vwLenSize(a4)
	move.b	(a1)+,d0
.006
;	cmp.b	#'.',d0		;group specifier?
;	bne.s	.003
;	bset	#dof_GROUP,d3
;	move.b	(a1)+,d0
;	bsr	GetNumber	;group?
;	tst.w	d1
;	bne.s	.003
;	move.w	d0,vwGroupSize(a4)
;	move.b	(a1)+,d0

.003	cmp.b	#'l',d0		;long?
	bne.s	.004
	bset	#dof_LONG,d3
	move.b	(a1)+,d0

.004	cmp.b	#'s',d0
	beq.w	DopeString
	cmp.b	#'d',d0
	beq.w	DopeDecimal
	cmp.b	#'x',d0
	beq.w	DopeHex
	cmp.b	#'u',d0
	beq.w	DopeUnsigned
	cmp.b	#'b',d0
	beq.w	DopeBinary
	cmp.b	#'c',d0
	beq.w	DopeChar
	cmp.b	#'o',d0
	beq.w	DopeOctal

;	cmp.b	#'e',d0
;	beq.s	DopeEFloat
;	cmp.b	#'f',d0
;	beq.s	DopeFFloat
;	cmp.b	#'g',d0
;	beq.s	DopeGFloat

DopeError:
	move.w	#FALSE,vwSuccess(a4)
	rts

;------------------------------------------------------------------
DopeString:
	btst	#dof_LONG,d3
	bne.w	DopeError
	bclr	#dof_GROUP,d3
	move.l	(a2)+,a5
	move.l	a5,d7
	moveq	#-1,d0			;Calc TextLen
.Loop	tst.b	(a5)+
	dbeq	d0,.Loop
	neg.w	d0
	subq.w	#1,d0
	move.l	d7,a5

;...and fall down through...

;------------------------------------------------------------------
;IN	d0.w	= Length of StringPart
;	a5.l	= ^StringPart to insert

StringParty:
	move.w	vwFieldSize(a4),d7	;Pad Length
	move.w	vwLenSize(a4),d6	;Put Length
	beq.s	.001
	cmp.w	d6,d0
	bhi.s	.002
.001	move.w	d0,d6
.002	sub.w	d6,d7
	bpl.s	.003
	moveq	#0,d7
.003	btst	#dof_MINUS,d3
	bne.s	.202

;--- Pre Pad
	move.b	cnh_PadSpace(a0),d0	;DoPadding
	btst	#dof_ZERO,d3
	beq.s	.101
	move.b	cnh_PadString(a0),d0
	bra.s	.101
.PreLoop
	bsr	PutCharFunc
.101	dbra	d7,.PreLoop
	bra.s	.102			;DoPutString
.PreSLoop
	move.b	(a5)+,d0
	beq.s	.103
	bsr	PutCharFunc
.102	dbra	d6,.PreSLoop
.103	rts

;--- Post Pad
.PostLoop
	move.b	(a5)+,d0		;DoPutString
	beq.s	.203
	bsr	PutCharFunc
.202	dbra	d6,.PostLoop
.203	move.b	cnh_PadSpace(a0),d0	;DoPadding
	btst	#dof_ZERO,d3
	beq.s	.201
	move.b	cnh_PadString(a0),d0
	bra.s	.201
.PostSLoop
	bsr	PutCharFunc
.201	dbra	d7,.PostSLoop
	rts

;------------------------------------------------------------------
DopeChar:
	btst	#dof_LONG,d3
	bne.w	DopeError
	bclr	#dof_GROUP,d3
	move.w	(a2)+,-(sp)
	move.l	sp,a5
	addq.l	#1,a5
	moveq	#1,d0
	bsr	StringParty
	addq.l	#2,sp
	rts

;------------------------------------------------------------------
DopeDecimal:
	move.l	a0,-(sp)
	lea	vsSmallBuffer(a4),a5
	move.l	a5,d6

	btst	#dof_LONG,d3
	bne.s	.Long
	move.w	(a2)+,d0
	ext.l	d0
	beq.s	.Last
	bra.s	.001
.Long	move.l	(a2)+,d0
	beq.s	.Last
.001	bmi.s	.Neg
	neg.l	d0
	bra.s	.002
.Neg	move.b	#'-',(a5)+
.002	lea	alDecArray(pc),a0
	moveq	#0,d1
.OLoop	move.l	(a0)+,d2
	beq.s	.Last
	moveq	#-1,d5
.Loop	add.l	d2,d0
	dbgt	d5,.Loop
	sub.l	d2,d0
	addq.w	#1,d5
	bne.s	.003
	tst.w	d1
	beq.s	.OLoop
.003	moveq	#-1,d1
	neg.b	d5
	add.b	#'0',d5
	move.b	d5,(a5)+
	bra.s	.OLoop
.Last	neg.b	d0
	add.b	#'0',d0
	move.b	d0,(a5)+
	clr.b	(a5)
	sub.l	a5,d6
	neg.w	d6
	move.w	d6,d0

	move.l	(sp)+,a0
	lea	vsSmallBuffer(a4),a5
	bra	PartyDudes


;------------------------------------------------------------------
DopeUnsigned:
	move.l	a0,-(sp)
	lea	vsSmallBuffer(a4),a5
	move.l	a5,d6
	moveq	#0,d7

	btst	#dof_LONG,d3
	bne.s	.Long
	moveq	#0,d0
	move.w	(a2)+,d0
	beq.s	.Last
	bra.s	.001
.Long	move.l	(a2)+,d0
	beq.s	.Last
	bpl.s	.001
	bclr	#31,d0
	moveq	#-1,d7

.001	neg.l	d0
	lea	alDecArray(pc),a0
	moveq	#0,d1
.OLoop	move.l	(a0)+,d2
	beq.s	.Last
	moveq	#-1,d5
.Loop	add.l	d2,d0
	dbgt	d5,.Loop
	sub.l	d2,d0
	addq.w	#1,d5
;	bne.s	.003
;	tst.w	d1
;	beq.s	.OLoop
.003	moveq	#-1,d1
	neg.b	d5
	add.b	#'0',d5
	move.b	d5,(a5)+
	bra.s	.OLoop
.Last	neg.b	d0
	add.b	#'0',d0
	move.b	d0,(a5)+
	clr.b	(a5)
	sub.l	a5,d6
	neg.w	d6
	move.w	d6,d0

	tst.w	d7
	beq.s	.004
	lea	abBlackAdder+10(pc),a0	;Bungled work!
	moveq	#0,d7
	move.w	d6,d5
	subq.w	#1,d5

.ALoop	move.b	-(a0),d1
	move.b	-(a5),d2
	add.b	d2,d1
	sub.b	d7,d1
	cmp.b	#'9',d1
	sgt	d7
	ble.s	.100
	sub.b	#10,d1
.100	move.b	d1,(a5)
	dbra	d5,.ALoop

.004	move.l	(sp)+,a0
	lea	vsSmallBuffer(a4),a5
	moveq	#9-1,d5
.4Loop	cmp.b	#'0',(a5)		;Skip leading zeroes
	bne.s	.4End
	addq.l	#1,a5
	dbra	d5,.4Loop
.4End	bra	PartyDudes


abBlackAdder:	dc.b	$02,$01,$04,$07,$04,$08,$03,$06,$04,$08
	EVEN

;------------------------------------------------------------------
DopeHex:
	lea	vsSmallBuffer(a4),a5
	btst	#dof_LONG,d3
	bne.s	.Long
	moveq	#4-1,d2
	move.w	(a2)+,d0
	beq.s	.Zero
	swap	d0
	bra.s	.ZLoop
.Long	moveq	#8-1,d2
	move.l	(a2)+,d0
	beq.s	.Zero

.ZLoop	rol.l	#4,d0
	move.b	d0,d1
	and.w	#$000f,d1
	bne.s	.001
	dbra	d2,.ZLoop
.001	move.w	d2,d5
	bra.s	.Entry

.NoZer	move.w	d2,d5
.Loop	rol.l	#4,d0
	move.b	d0,d1
	and.w	#$000f,d1
.Entry	move.b	sDopeHexString(pc,d1.w),(a5)+
	dbra	d2,.Loop
	lea	vsSmallBuffer(a4),a5
	move.w	d5,d0
	addq.w	#1,d0
	bsr	PartyDudes
	rts

.Zero	moveq	#0,d1
	move.w	d1,d2
	move.w	d2,d5
	bra.s	.Entry

sDopeHexString:
	dc.b	'0123456789ABCDEF'
	EVEN

;------------------------------------------------------------------
DopeOctal:
	lea	vsSmallBuffer(a4),a5
	btst	#dof_LONG,d3
	bne.s	.Long
	moveq	#6-1,d2
	move.w	(a2)+,d0
	beq.s	.Zero
	swap	d0
	rol.l	#1,d0
	move.b	d0,d1
	and.w	#$0001,d1
	bne.s	.001
	subq.w	#1,d2
	bra.s	.ZLoop
.Long	moveq	#11-1,d2
	move.l	(a2)+,d0
	beq.s	.Zero
	rol.l	#2,d0
	move.b	d0,d1
	and.w	#$0003,d1
	bne.s	.001
	subq.w	#1,d2

.ZLoop	rol.l	#3,d0
	move.b	d0,d1
	and.w	#$0007,d1
	bne.s	.001
	dbra	d2,.ZLoop
.001	move.w	d2,d5
	bra.s	.Entry

.NoZer	move.w	d2,d5
.Loop	rol.l	#3,d0
	move.b	d0,d1
	and.w	#$0007,d1
.Entry	move.b	sDopeHexString(pc,d1.w),(a5)+
	dbra	d2,.Loop
	lea	vsSmallBuffer(a4),a5
	move.w	d5,d0
	addq.w	#1,d0
	bsr	PartyDudes
	rts

.Zero	moveq	#0,d1
	move.w	d1,d2
	move.w	d2,d5
	bra.s	.Entry

;------------------------------------------------------------------
DopeBinary:
	lea	vsSmallBuffer(a4),a5
	btst	#dof_LONG,d3
	bne.s	.Long
	moveq	#16-1,d2
	move.w	(a2)+,d0
	swap	d0
	bra.s	.001
.Long	moveq	#32-1,d2
	move.l	(a2)+,d0

.001	btst	#dof_ZERO,d3
	bne.s	.002
.ZLoop	rol.l	#1,d0
	dbcs	d2,.ZLoop
	tst.w	d2
	bpl.s	.003
	move.b	#'0',(a5)+
	moveq	#0,d5
	bra.s	.004

.003	move.w	d2,d5
	bra.s	.005
.002	move.w	d2,d5
.Loop	rol.l	#1,d0
	bcs.s	.005
	move.b	#'0',(a5)+
	dbra	d2,.Loop
	bra.s	.004
.005	move.b	#'1',(a5)+
	dbra	d2,.Loop

.004	lea	vsSmallBuffer(a4),a5
	move.w	d5,d0
	addq.w	#1,d0
	bra	PartyDudes

;------------------------------------------------------------------
;DopeEFloat:
;	bra	DopeError
;DopeFFloat:
;	bra	DopeError
;DopeGFloat:
;	bra	DopeError

;------------------------------------------------------------------
;IN	d0.w	= StringPart Length
;	d3.l	= Flags
;	a3.l	= ^Text
;	a5.l	= ^StringPart to insert

PartyDudes:
	move.w	vwFieldSize(a4),d7
	move.w	vwLenSize(a4),d6
	beq.s	.001
	cmp.w	d6,d0
	bhi.s	.002
.001	move.w	d0,d6
.002	sub.w	d6,d7
	bpl.s	.003
	moveq	#0,d7

; d6.w	= Put Length
; d7.w	= Pad Length

.003	btst	#dof_MINUS,d3
	bne.s	PostPad

PrePad:
	move.b	cnh_PadSpace(a0),d0	;DoPadding
	btst	#dof_ZERO,d3
	beq.s	.001
	move.b	cnh_PadZero(a0),d0
	bra.s	.001
.PLoop	bsr	PutCharFunc
.001	dbra	d7,.PLoop
	bra.s	.002			;DoPutString
.SLoop	move.b	(a5)+,d0
	beq.s	.003
	bsr	PutCharFunc
.002	dbra	d6,.SLoop
.003	rts

PostPad:
	bra.s	.002			;DoPutString
.PLoop	move.b	(a5)+,d0
	beq.s	.003
	bsr	PutCharFunc
.002	dbra	d6,.PLoop
.003	move.b	cnh_PadSpace(a0),d0	;DoPadding
	btst	#dof_ZERO,d3
	beq.s	.001
	move.b	cnh_PadZero(a0),d0
	bra.s	.001
.SLoop	bsr	PutCharFunc
.001	dbra	d7,.SLoop
	rts

;------------------------------------------------------------------
;OUT	d0.w	= Success

DoBackSlash:
	move.b	(a1)+,d0
	cmp.b	#'n',d0		;LineFeed
	beq.w	.LF
	cmp.b	#'t',d0		;Tabulator
	beq.w	.Tab
	cmp.b	#'\',d0		;BackSlash
	beq	PutCharFunc
	cmp.b	#'f',d0		;FormFeed
	beq.w	.FF
	cmp.b	#'b',d0		;BackSpace
	beq.w	.BS
	cmp.b	#'#',d0		;Hash
	beq.w	.User
	cmp.b	#'@',d0		;Plain Style
	beq.w	.Plain
	cmp.b	#'B',d0		;Bold Style
	beq.w	.Bold
	cmp.b	#'I',d0		;Italic Style
	beq.w	.Italic
	cmp.b	#'U',d0		;Underline Style
	beq.w	.Under
	cmp.b	#'C',d0		;Foreground Color
	beq.w	.FColor
	cmp.b	#'Z',d0		;Background Color
	beq	.BColor
	cmp.b	#'[',d0		;Escape
	beq	.Escape
	cmp.b	#'{',d0		;CSI
	beq.w	.Csi
	cmp.b	#'r',d0		;Return
	beq.s	.Rtn
	cmp.b	#'v',d0		;Vert. Tabulator
	beq.s	.Vtab
				;--- Examine for ASCII
	bsr	GetNumber
	tst.w	d1
	bpl	PutCharFunc
.Error	move.w	#FALSE,vwSuccess(a4)
.Xit	rts

.LF	move.b	#10,d0
	bra	PutCharFunc
.Tab	move.b	#9,d0
	bra	PutCharFunc
.FF	move.b	#12,d0
	bra	PutCharFunc
.BS	move.b	#8,d0
	bra	PutCharFunc
.Rtn	move.b	#13,d0
	bra	PutCharFunc
.Vtab	move.b	#11,d0
	bra	PutCharFunc

.User	moveq	#0,d0
	move.b	(a1)+,d0
	sub.b	#'1',d0
	blt.s	.Error
	cmp.b	#8,d0
	bge.s	.Error
	add.w	d0,d0
	add.w	d0,d0
	lea	cnh_UserNotes(a0),a5
	move.l	(a5,d0.w),d0
	beq.s	.Xit
	move.l	d0,a5
	bra.s	DoCopyString

.Plain	lea	sDoStyle1(pc),a5
	bra.s	DoCopyString
.Bold	lea	sDoStyle2(pc),a5
	bra.s	DoCopyString
.Italic	lea	sDoStyle3(pc),a5
	bra.s	DoCopyString
.Under	lea	sDoStyle4(pc),a5
	bra.s	DoCopyString

.BColor	lea	sDoBgCol(pc),a5
	bra	.Color
.FColor	lea	sDoFgCol(pc),a5
.Color	move.b	(a1)+,3(a5)
	bra	DoCopyString

.Escape	move.b	#27,d0
	bra	PutCharFunc
.Csi	move.b	#155,d0
	bra	PutCharFunc

;------------------------------------------------------------------
;IN	a3.l	= ^Text
;	a5.l	= ^StringPart

DoCopyString:
	move.b	(a5)+,d0
	beq.s	.Exit
	bsr	PutCharFunc
	bra.s	DoCopyString
.Exit	rts

;------------------------------------------------------------------
;IN	d0.b	= First Char
;	a1.l	= ^String
;OUT	d0.w	= Number
;	d1.l	= Success

GetNumber:
	cmp.b	#'*',d0		;get number from args?
	beq.s	.Var
	cmp.b	#'0',d0		;one digit?
	blt.s	.Error
	cmp.b	#'9',d0
	bgt.s	.Error
	moveq	#0,d1
	and.w	#$000f,d0
	move.w	d0,d1
	move.b	(a1),d0
	cmp.b	#'0',d0		;two digits?
	blt.s	.NoMore
	cmp.b	#'9',d0
	bgt.s	.NoMore
	addq.l	#1,a1
	mulu	#10,d1		;use shift *10
	and.w	#$000f,d0
	add.w	d0,d1
	move.b	(a1),d0
	cmp.b	#'0',d0		;three digits?
	blt.s	.NoMore
	cmp.b	#'9',d0
	bgt.s	.NoMore
	addq.l	#1,a1
	mulu	#10,d1		;as above
	and.w	#$000f,d0
	add.w	d0,d1
.NoMore	move.w	d1,d0
	moveq	#0,d1
	rts
.Error	moveq	#-1,d1
	rts
.Var	move.w	(a2)+,d0
	and.w	#$00ff,d0
	moveq	#0,d1
	rts

;------------------------------------------------------------------
;	@DefineChars
;------------------------------------------------------------------
;
; Define specified CharTable according to Mode:
;
;	CASE Mode OF
;	  1: .new
;	  2: .add
;	  3: .rem
;	  4: .get
;	OTHERWISE
;	  .all
;	ENDCASE
;
;------------------------------------------------------------------
; IN	d0.l	= Mode
;	a1.l	= ^CharTable
;	a2.l	= ^ArrayOfChars
; OUT	{ CharTable modified }
;------------------------------------------------------------------

DefineChars:
	move.l	a2,a0
	subq.w	#1,d0
	beq.s	.New
	subq.w	#1,d0
	beq.s	.Add
	subq.w	#1,d0
	beq.s	.Rem
	subq.w	#1,d0
	beq.s	.Get
;------------------------------------------------------------------
.All	moveq	#0,d0			;--- DEFMODE_ALL
	bra.s	.Get
.Exit	rts

;------------------------------------------------------------------
.New	move.l	a1,d0			;--- DEFMODE_NEW
	move.w	#[CHARDEFSIZE/4]-1,d1
.NLoop	clr.l	(a1)+
	dbra	d1,.NLoop
	move.l	d0,a1			;continue down though...
;------------------------------------------------------------------
.Add	moveq	#0,d0			;--- DEFMODE_ADD
	move.b	(a0)+,d0
	beq.s	.Exit
	move.w	d0,d1
	lsr.w	#3,d0
	not.w	d1
	and.w	#$0007,d1
	bset	d1,(a1,d0.w)
	bra.s	.Add

;------------------------------------------------------------------
.Rem	moveq	#0,d0			;--- DEFMODE_REM
	move.b	(a0)+,d0
	beq.s	.Exit
	move.w	d0,d1
	lsr.w	#3,d0
	not.w	d1
	and.w	#$07,d1
	bclr	d1,(a1,d0.w)
	bra.s	.Rem

;------------------------------------------------------------------
.Get	swap	d0			;--- DEFMODE_GET
	lea	awDefDefTable(pc),a0
	adda.w	(a0,d0.w),a0
	REPT	CHARDEFSIZE/4
	move.l	(a0)+,(a1)+
	ENDR
	rts

;------------------------------------------------------------------
;	@Display
;------------------------------------------------------------------
;
; Format and Display a text string in a Console Window.
;
; Length for DoFormat calculated.
;
; Cursor turn off during display.
;
;------------------------------------------------------------------
; IN	d0.l	= MaxLen
;	a0.l	= ConHandle
;	a1.l	= ^String
;	a2.l	= ^List of Arguments
; OUT	-
;------------------------------------------------------------------

Display:
	PUSH	d7/a3
	move.l	d0,d7
	move.l	a1,a3			;--- FIND LENGTH OF TEXT
	moveq	#-1,d0
.Loop	tst.b	(a3)+
	dbeq	d0,.Loop
	neg.l	d0
	subq.w	#1,d0
	cmp.w	d7,d0			;can't be bigger than MaxLen
	ble.s	.Less
	move.w	d7,d0
.Less	add.w	cnh_ExLength(a0),d0	;+ additional space
	ABSW	d0			;align

	DLINK	a4,d0			;--- ALLOC SPACE FOR TEXTBUFFER ON STACK
	move.l	sp,a3			;point to start
	move.l	#$9b302070,(a3)+	;Cursor off
	bsr	DoFormat		;--- FORMAT STRING AND DISPLAY IT
	subq.l	#4,d0
	move.l	d0,a1
	move.l	d7,d0
	bsr.s	DisplayRaw
	unlk	a4
	move.w	cnh_CursorStatus(a0),d0
	bsr	Cursor
	PULL	d7/a3
	rts

;------------------------------------------------------------------
;	@DisplayRaw
;------------------------------------------------------------------
;
; Display an unformatted text string in a Console Window.
;
;------------------------------------------------------------------
; IN	d0.l	= MaxLen [ -1 don't care ]
;	a0.l	= ConHandle
;	a1.l	= ^Text
; OUT	-
;------------------------------------------------------------------

DisplayRaw:
	PUSH	d1/a0/a1/a6
	move.l	cnh_WriteIO(a0),a6
	move.w	#CMD_WRITE,IO_COMMAND(a6)
	move.l	a1,IO_DATA(a6)
	move.l	d0,IO_LENGTH(a6)
	lea	dWriteReplyPort(pc),a0
	move.l	a0,MN_REPLYPORT(a6)
	move.l	a6,a1
	move.l	pSysBase(pc),a6
	CALL	DoIO
	PULL	d1/a0/a1/a6
	rts

;------------------------------------------------------------------
;	@Accept
;------------------------------------------------------------------
;
; Accept an input from user.
;
;------------------------------------------------------------------
; IN	d0.l	= Flags
;	a0.l	= ConHandle
;	a1.l	= ^AcceptStructure
; OUT	d0.l	= Success
;			[ -1 = Error	]
;			[  0 = OK	]
;			[  1 = ExitFlag	]
;			[  2 = ExitChar	]
;
; GLOBALS
;	d6.l	= Flags
;	a2.l	= ^AcceptStructure
;	a3.l	= ConHandle
;	a4.l	= ^StackBuffer
;	a5.l	= ^Message
;	a6.l	= SysBase
;
;------------------------------------------------------------------

;---  THE ACCEPT STACK BUFFER
vsBufferEnd	SET	0
vsBuffer	SET	vsBufferEnd-cAcceptBufferSize
vdInputEvent	SET	vsBuffer-ie_SIZEOF
vAcceptSizeOf	SET	vdInputEvent

Accept:
	PUSH	vir
					;--- ASSIGN THE GLOBAL REGISTERS
	link	a4,#vAcceptSizeOf	;StackBuffer
	move.l	a0,a3			;ConHandle
	move.l	a1,a2			;AcceptStructure
	move.l	d0,d6			;Flags
	move.l	pSysBase(pc),a6	;ExecBase

	and.l	#~[RAWKEY!VANILLAKEY],acc_ExitFlags(a2)	;Illegal as ExitFlags

	bsr.s	EraseKeyBuffer		;--- ERASE MESSAGE BUFFER IF REQUIRED
	bsr.s	AcceptKey		;--- GO FOR IT
	tst.l	d0
	bpl.s	.Exit			;Error?
	clr.b	acc_Char(a2)		;YES! No key
.Exit	unlk	a4
	PULL	vir
	rts

;------------------------------------------------------------------
EraseKeyBuffer:
	btst	#ACCB_ERASE,d6
	beq.s	.Exit
.EraseLoop
	move.l	cnh_UserPort(a3),a0	;Erase keybuffer
	CALL	GetMsg
	tst.l	d0
	beq.s	.Exit
	move.l	d0,a1
	CALL	ReplyMsg
	bra.s	.EraseLoop
.Exit	rts

;------------------------------------------------------------------
;IN	a3.l	= ConHandle
;	a2.l	= AcceptStructure
;OUT	d0.l	= Success [ see @Accept Header ]

AcceptError:				;--- ERROR IN ACCEPT
	RETURN	-1

AcceptKey:				;--- ACCEPT A KEYSTROKE
	bsr	GetMessage
	beq.s	.AccOn
	bmi.s	AcceptError
	move.l	cnh_MsgHandler(a3),d1	;--- MESSAGE HANDLER
	beq.s	.Exit
	PUSH	d1-d7/a0-a6
	move.l	a0,d0
	move.l	d1,a5
	jsr	(a5)
	PULL	d1-d7/a0-a6
	tst.l	d0
	beq.s	AcceptKey
.Exit	clr.b	acc_Char(a2)
	rts
.AccOn	bsr	KeyWays
	bmi.s	AcceptError
	beq.s	HandleChar
HandleRawKey:				;--- HANDLE A RAWKEY
	clr.b	acc_Char(a2)		;RawKey found in acc_Code
	RETURN

HandleChar:
	bsr	ConvertChar		;--- HANDLE CHAR
	move.b	d0,acc_Char(a2)
	lea	acc_ExitTable(a2),a0	;Is it a ExitChar?
	bsr	TestChar
	beq.s	.Exit
	lea	acc_ValidTable(a2),a0	;Is it a ValidChar?
	bsr	TestChar
	bne.w	AcceptKey
	bsr	EchoChar
	RETURN
.Exit	bsr	EchoChar
	RETURN	2

;------------------------------------------------------------------
;OUT	d0.l	= Success
;			-1 = Error [no Msg on ~ACCB_WAIT]
;			 0 = OK
;			 1 = ExitFlags
;	CCR	= Success
;	a0.l	= ^Msg

GetMessage:
	move.l	cnh_UserPort(a3),a0	;--- GET MESSAGE
	CALL	GetMsg
	tst.l	d0
	bne.s	.GotCha
	btst	#ACCB_WAIT,d6
	beq.s	.NoWait			;Exit if no message and no wait
	move.l	cnh_Signal(a3),d0	;--- WAIT FOR MESSAGE
	CALL	Wait
	bra.s	GetMessage
.NoWait	RETURN	-1
.GotCha	move.l	d0,a0
	lea	im_Class(a0),a0		;Copy message
	lea	acc_Class(a2),a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	d0,a1			;--- REPLY MESSAGE
	CALL	ReplyMsg
	move.l	acc_Class(a2),d0	;--- WHAT KIND OF MESSAGE
	cmp.l	#RAWKEY,d0		;Is it RAWKEY?
	bne.s	.001
	RETURN
.001	and.l	acc_ExitFlags(a2),d0	;Ignore everything else but ExitFlags
	beq.s	GetMessage
	RETURN	1

;------------------------------------------------------------------
;OUT	d0.l	= Success
;			-1 = Error
;			 0 = OK (Handle)
;			 1 = RawKey
;	CCR	= Success

KeyWays:
	move.w	acc_Code(a2),d0		;--- MESSAGE IS RAWKEY
	btst	#ACCB_RAWKEY,d6
	bne.s	.Raw
	btst	#ACCB_DUALKEY,d6
	bne.s	.Handle
	tst.b	d0			;--- UPKEY
	bpl.s	.Down
	btst	#ACCB_UPKEY,d6
	bne.s	.Handle
.Error	RETURN	-1
.Down	btst	#ACCB_UPKEY,d6		;wait for key to be released?
	bne.s	.Error
.Handle	RETURN	0
.Raw	RETURN	1


;------------------------------------------------------------------
EchoChar:
	btst	#ACCB_ECHO,d6		;--- ECHOCHAR
	beq.s	.Exit
	lea	cnh_EchoTable(a3),a0
	bsr	TestChar
	bne.s	.Exit
	lea	vsBuffer(a4),a0
	moveq	#1,d0
	move.l	a0,a1			;Text
	move.l	a3,a0			;ConHandle
	bra	DisplayRaw
.Exit	rts

;------------------------------------------------------------------
;IN	a0.l	= Table to test
;OUT	d0.l	= Success
;	CCR

TestChar:
	moveq	#0,d0
	move.b	acc_Char(a2),d0
	moveq	#0,d1
	move.w	d0,d1
	lsr.w	#3,d0
	not.w	d1
	and.w	#$0007,d1
	btst	d1,(a0,d0.w)		;test appropriate bit
	beq.s	.Error
	RETURN	TRUE
.Error	RETURN	FALSE

;------------------------------------------------------------------
; IN	a0.l	= ^Message
; OUT	d0.b	= Char
;		  ! Error [ 0 ]

abConvertArray:
	dc.b	AKEY_BS,0,0,0,AKEY_ESC,AKEY_DEL,0
	dc.b	0,0,0,0,AKEY_ARROWUP,AKEY_ARROWDN,AKEY_ARROWRG,AKEY_ARROWLF
	dc.b	AKEY_F1,AKEY_F2,AKEY_F3,AKEY_F4,AKEY_F5
	dc.b	AKEY_F6,AKEY_F7,AKEY_F8,AKEY_F9,AKEY_F10
	dc.b	0,0,0,0,0,AKEY_HELP
	EVEN

ConvertChar:
	PUSH	d1/a0/a1/a2/a5/a6
	move.w	acc_Code(a2),d0
	and.w	#$007f,d0
	sub.b	#$41,d0
	blt.s	.Convert
	cmp.b	#$60-$41,d0
	bge.s	.Error
	move.b	abConvertArray(pc,d0.w),d0
	beq.s	.Convert
	bra.s	.Exit
.Convert
	lea	vdInputEvent(a4),a0	;InputEvent Structure
	clr.l	ie_NextEvent(a0)
	move.w	#IECLASS_RAWKEY<<8,ie_Class(a0)
	move.w	acc_Code(a2),ie_Code(a0)
	move.w	acc_Qualifier(a2),ie_Qualifier(a0)
	move.l	acc_IAddress(a2),a1
	move.l	(a1),ie_EventAddress(a0)
	lea	vsBuffer(a4),a1		;CharBuffer (destination)
	suba.l	a2,a2			;default keymap
	moveq	#4,d1			;length
	move.l	cnh_CDBase(a3),a6
	CALL	RawKeyConvert
	subq.w	#1,d0			;skip if more than 1 char was converted
	bne.s	.Error
	lea	vsBuffer(a4),a1
	move.b	(a1),d0
.Exit	PULL	d1/a0/a1/a2/a5/a6
	rts
.Error	moveq	#0,d0
	bra.s	.Exit


;------------------------------------------------------------------
;	@AcceptString
;------------------------------------------------------------------
;
; Accept the input of a string from user.
;
;------------------------------------------------------------------
; IN	d0.l	= Flags
;	a0.l	= ConHandle
;	a1.l	= ^AcceptStructure
; OUT	d0.l	= Success
;
; GLOBALS
;	d6.l	= Flags
;	a2.l	= ^AcceptStructure
;	a3.l	= ConHandle
;	a4.l	= ^StackBuffer
;	a6.l	= SysBase
;
;------------------------------------------------------------------

;---  EXTENTION OF THE ACCEPT STACK BUFFER
vsJustBuffer	SET	vAcceptSizeOf-16
vwStyle		SET	vsJustBuffer-2
vwFgCol		SET	vwStyle-2
vwBgCol		SET	vwFgCol-2
vSizeOf		SET	vwBgCol


AcceptString:
	PUSH	vir
					;--- ASSIGN THE GLOBAL REGISTERS
	link	a4,#vSizeOf	;StackBuffer
	move.l	a0,a3		;ConHandle
	move.l	a1,a2		;AcceptStructure
	move.l	d0,d6		;Flags
	move.l	pSysBase(pc),a6	;ExecBase

	and.l	#~[RAWKEY!VANILLAKEY],acc_ExitFlags(a2)	;Illegal as ExitFlags

	move.w	cnh_ExLength(a3),d0	;--- Ensure that ExLength > MaxLength
	sub.w	accs_MaxLength(a2),d0
	blt.s	.111
	neg.w	d0
	add.w	d0,cnh_ExLength(a3)
.111
	lea	-cin_SIZEOF(sp),sp	;Alloc space for info!
	move.l	sp,a1
	move.l	a3,a0
	bsr	GetInfo
	move.l	d0,a1			;--- STORE OLD GFX
	move.w	cin_Styles(a1),vwStyle(a4)
	move.w	cin_FgCol(a1),vwFgCol(a4)
	move.w	cin_BgCol(a1),vwBgCol(a4)
	tst.w	acc_XStart(a2)		;--- SET START POSITION
	bpl.s	.001
	move.w	cin_XPos(a1),acc_XStart(a2)
.001	tst.w	acc_YStart(a2)
	bpl.s	.002
	move.w	cin_YPos(a1),acc_YStart(a2)
.002	move.w	cin_XSize(a1),d1	;--- CORRECT MAXLENGTH
	lea	cin_SIZEOF(sp),sp	;Dealloc space!
	move.w	acc_XStart(a2),d0
	add.w	accs_FieldLen(a2),d0
	cmp.w	d1,d0
	ble.s	.003
	sub.w	acc_XStart(a2),d1
	ble.s	.Exit			;exit if FieldLen <= 0
	move.w	d1,accs_FieldLen(a2)
.003
	move.w	acc_Styles(a2),d0	;--- SET Styles, FgCol and BgCol
	bpl.s	.200
	move.w	vwStyle(a4),d0
.200	move.w	acc_FgCol(a2),d1
	bpl.s	.201
	move.w	vwFgCol(a4),d1
.201	move.w	acc_BgCol(a2),d2
	bpl.s	.202
	move.w	vwBgCol(a4),d2
.202	move.l	a3,a0
	bsr	SetGfx

	bsr	EraseKeyBuffer		;--- ERASE KEYBOARD BUFFER IF REQUIRED
	bsr	AcceptString2

.Exit	move.l	d0,-(sp)
	move.w	vwStyle(a4),d0		;--- RESTORE OLD GFX AND LEAVE
	move.w	vwFgCol(a4),d1
	move.w	vwBgCol(a4),d2
	move.l	a3,a0
	bsr	SetGfx
	move.l	(sp)+,d0
	unlk	a4
	PULL	vir
	rts

;------------------------------------------------------------------
;IN	a3.l	= ConHandle
;	a2.l	= AcceptStructure
;OUT	d0.l	= Success
;			-1 = Error
;			 0 = OK
;			 1 = ExitFlag

VALIDQUAL	SET	$8000!IEQUALIFIER_CAPSLOCK
VALIDQUAL	SET	VALIDQUAL!IEQUALIFIER_REPEAT
VALIDQUAL	SET	VALIDQUAL!IEQUALIFIER_NUMERICPAD
VALIDQUAL	SET	VALIDQUAL!IEQUALIFIER_SHIFT

AcceptString2:
	move.w	accs_MaxLength(a2),d0	;ensure than FieldLen <= MaxLen
	cmp.w	accs_FieldLen(a2),d0
	ble.s	.001
	btst	#ACCB_NOSCROLL,d6
	beq.s	.002
	move.w	accs_FieldLen(a2),accs_MaxLength(a2)
	bra.s	.002
.001	move.w	d0,accs_FieldLen(a2)
.002	btst	#ACCB_CONTINUE,d6
	bne.s	.003
	clr.w	accs_Position(a2)	;--- RESTART STRING
	clr.w	accs_Length(a2)
	clr.w	accs_DispPos(a2)
	btst	#ACCB_NOAMIGA,d6
	bne.s	.002
	move.l	accs_InputBuffer(a2),a0	;--- COPY STRING TO BUFFER
	move.l	accs_WorkBuffer(a2),d0
	beq.s	.003
	move.l	d0,a1
	move.w	accs_MaxLength(a2),d0
	subq.w	#1,d0
.CopyLoop
	move.b	(a0)+,(a1)+
	dbra	d0,.CopyLoop

.003	or.l	#[ACCF_WAIT],d6
	and.l	#~[ACCF_ECHO!ACCF_UPKEY!ACCF_RAWKEY!ACCF_DUALKEY],d6
	bsr	PrepareEcho

StringLoop:
	bsr	EchoBuffer
	move.w	accs_MaxLength(a2),d1	;--- TEST LASTEXIT FLAG
	cmp.w	accs_Length(a2),d1
	bgt.s	StringAgain
	btst	#ACCB_LASTEXIT,d6
	bne.w	StringExitchar
StringAgain:
	bsr	GetMessage
	beq.s	StringGo
StringEnd:				;Stop if ExitFlags or Error
	bmi.s	.Exit
	move.l	cnh_MsgHandler(a3),d1	;Hey, hold on... Let's see if
	beq.s	.Exit			;there's a handler to jump to.
	PUSH	d1-d7/a0-a6
	move.l	a0,d0			;message
	move.l	d1,a5
	jsr	(a5)
	PULL	d1-d7/a0-a6
	tst.l	d0
	beq.s	StringAgain
.Exit	clr.b	acc_Char(a2)
	rts

StringGo:
	bsr	KeyWays
	bmi.s	StringAgain
	bsr	ConvertChar
	move.b	d0,acc_Char(a2)
	beq.s	StringAgain		;Back if Qualifier or Error

	move.w	acc_Qualifier(a2),d1
	and.w	#~VALIDQUAL,d1
	bne.s	.001
	move.w	acc_Qualifier(a2),d1
	and.w	#IEQUALIFIER_SHIFT,d1
	bne.s	.002
	cmp.b	#AKEY_BS,d0		;BackSpace
	beq	KeyBackSpace
	cmp.b	#AKEY_DEL,d0		;Delete
	beq	KeyDelete
	cmp.b	#AKEY_ARROWRG,d0	;Cursor Right
	beq	KeyCRight
	cmp.b	#AKEY_ARROWLF,d0	;Cursor Left
	beq	KeyCLeft
	bra.s	.001

.002	cmp.b	#AKEY_ARROWRG,d0	;Shift Cursor Right
	beq	KeySCRight
	cmp.b	#AKEY_ARROWLF,d0	;Shift Cursor Left
	beq	KeySCLeft

.001	move.w	acc_Qualifier(a2),d1
	and.w	#IEQUALIFIER_COMMAND,d1
	beq.s	StringConvert
	btst	#ACCB_NOAMIGA,d6
	bne.s	StringConvert
	move.b	acc_Char(a2),d0
	cmp.b	#'q',d0
	beq	KeyRestore
	cmp.b	#'x',d0
	beq	KeyClearLine
	btst	#ACCB_NOSTDAMIGA,d6
	bne.s	StringConvert
	cmp.b	#'y',d0
	beq	KeyClearEOL
	cmp.b	#'a',d0
	beq	KeyToggle

StringConvert:
	lea	acc_ExitTable(a2),a0	;--- TEST FOR EXITCHAR
	bsr	TestChar
	beq.s	StringExitchar
	lea	acc_ValidTable(a2),a0	;--- TEST FOR VALIDCHAR
	bsr	TestChar
	bne	StringAgain

	btst	#ACCB_FULLSTOP,d6	;--- TEST FULLSTOP FLAG
	beq.s	.001
	btst	#ACCB_OVERWRITE,d6	;but only if we're in insert mode
	bne.s	.001
	move.w	accs_Length(a2),d1
	cmp.w	accs_MaxLength(a2),d1
	bge	StringAgain
.001	bsr	CopyChar2Buffer		;--- COPY ValidChar TO BUFFER
	bra.w	StringLoop
StringExitchar:
	RETURN	TRUE

;------------------------------------------------------------------
KeyBackSpace:				;--- BackSpace
	move.l	accs_InputBuffer(a2),a0
	move.w	accs_Position(a2),d0
	beq	StringAgain
	subq.w	#1,d0
	move.w	d0,accs_Position(a2)
	bsr	AdjustField
	move.w	accs_Length(a2),d1
	bra.s	KeyDel
KeyDelete:				;--- <DEL>
	move.l	accs_InputBuffer(a2),a0
	move.w	accs_Position(a2),d0
	move.w	accs_Length(a2),d1
	cmp.w	d1,d0
	bge	StringAgain
KeyDel:
	cmp.w	d1,d0			;move last part of string
	bge.s	.Found
	move.b	1(a0,d0.w),(a0,d0.w)
	addq.w	#1,d0
	bra.s	KeyDel
.Found	subq.w	#1,d1
	blt.w	StringLoop
	move.w	d1,accs_Length(a2)
	bra	StringLoop

KeyCRight:				;--- Cursor Right
	move.w	accs_Position(a2),d0
	cmp.w	accs_Length(a2),d0
	bge.w	StringAgain
	addq.w	#1,accs_Position(a2)
	bsr	AdjustField
	lea	sCursorRight(pc),a0
	moveq	#-1,d0
	move.l	a0,a1
	move.l	a3,a0
	bsr	DisplayRaw
	bra	StringLoop

KeyCLeft:				;--- Cursor Left
	move.w	accs_Position(a2),d0
	cmp.w	#0,d0
	ble.w	StringAgain
	subq.w	#1,accs_Position(a2)
	bsr	AdjustField
	lea	sCursorLeft(pc),a0
	moveq	#-1,d0
	move.l	a0,a1
	move.l	a3,a0
	bsr	DisplayRaw
	bra	StringLoop

KeySCRight:				;--- <SHIFT> + Cursor Right
	move.w	accs_Length(a2),d0
	cmp.w	accs_Position(a2),d0
	beq.w	StringAgain
	move.w	d0,accs_Position(a2)
	bsr	AdjustField
	bra	StringLoop

KeySCLeft:				;--- <SHIFT> + Cursor Left
	tst.w	accs_Position(a2)
	beq	StringAgain
	clr.w	accs_Position(a2)
	bsr	AdjustField
	bra	StringLoop

KeyRestore:				;--- <AMIGA> + q
	move.l	accs_WorkBuffer(a2),d0	;copy buffer to string
	beq	StringLoop
	move.l	d0,a0
	move.l	accs_InputBuffer(a2),a1
	move.w	accs_MaxLength(a2),d0
	subq.w	#1,d0
.CopyLoop
	move.b	(a0)+,(a1)+
	dbra	d0,.CopyLoop

	clr.w	accs_Position(a2)
	move.l	accs_InputBuffer(a2),a0	;determine length
	move.w	accs_MaxLength(a2),d0
	subq.w	#1,d0
	moveq	#0,d1
.TLoop	tst.b	(a0)+
	beq.s	.TExit
	addq.w	#1,d1
	dbra	d0,.TLoop
.TExit	move.w	d1,accs_Length(a2)
	bsr	AdjustField
	bra	StringLoop

KeyClearLine:				;--- <AMIGA> + x
	clr.w	accs_Position(a2)
	clr.w	accs_Length(a2)
	bsr	AdjustField
	bra	StringLoop

KeyClearEOL:				;--- <AMIGA> + y
	move.w	accs_Position(a2),accs_Length(a2)
	bsr	AdjustField
	bra	StringLoop

KeyToggle:				;--- <AMIGA> + a
	bchg	#ACCB_OVERWRITE,d6
	bra	StringLoop

;------------------------------------------------------------------
AdjustField:
	move.l	d0,-(sp)
	move.w	accs_Position(a2),d0
	sub.w	accs_FieldLen(a2),d0
	bgt.s	.001
	clr.w	d0
.001	move.w	d0,accs_DispPos(a2)
	move.l	(sp)+,d0
	rts

;------------------------------------------------------------------
CopyChar2Buffer:
	move.b	acc_Char(a2),d1
	beq.s	.Exit
	cmp.b	#CSI,d1
	beq.s	.Exit
	move.l	accs_InputBuffer(a2),a1
	move.w	accs_Position(a2),d0

	btst	#ACCB_OVERWRITE,d6
	bne.s	.OverWrite

	move.w	accs_Length(a2),d2	;adjust length
	cmp.w	accs_MaxLength(a2),d2
	bge.s	.MLoop
	addq.w	#1,d2
	move.w	d2,accs_Length(a2)
.MLoop	cmp.w	d0,d2			;move last part of string
	ble.s	.OverWrite
	subq.w	#1,d2
	move.b	(a1,d2.w),1(a1,d2.w)
	bra.s	.MLoop
.OverWrite
	move.b	d1,(a1,d0.w)		;place new char in string

	cmp.w	accs_MaxLength(a2),d0
	bge.s	.End
	addq.w	#1,d0
	cmp.w	accs_Length(a2),d0
	ble.s	.End
	move.w	d0,accs_Length(a2)

.End	move.w	d0,accs_Position(a2)
	bsr	AdjustField
.Exit	rts

;------------------------------------------------------------------
EchoBuffer:
	move.w	cnh_CursorStatus(a3),d3
	move.w	#CURSOROFF,d0		;cursor off
	move.l	a3,a0
	bsr	Cursor

	move.w	acc_XStart(a2),d0	;place cursor
	move.w	acc_YStart(a2),d1
	move.l	a3,a0
	bsr	GotoXY

	move.l	a2,-(sp)		;display string
	move.l	accs_InputBuffer(a2),a0
	move.w	accs_Length(a2),d0
	clr.b	(a0,d0.w)
	adda.w	accs_DispPos(a2),a0
	move.l	a0,-(sp)
	move.l	sp,a2
	lea	vsJustBuffer(a4),a1
	move.l	a3,a0
	moveq	#-1,d0
	bsr	Display
	addq.l	#4,sp
	move.l	(sp)+,a2

	btst	#ACCB_JUSTIFIED,d6	;Place cursor
	beq.s	.001
	move.w	accs_FieldLen(a2),d0	;;
	add.w	accs_Position(a2),d0
	sub.w	accs_Length(a2),d0
	bra.s	.002
.001	move.w	accs_Position(a2),d0
.002	sub.w	accs_DispPos(a2),d0
	add.w	acc_XStart(a2),d0
	move.w	acc_YStart(a2),d1
	move.l	a3,a0
	bsr	GotoXY

	move.w	d3,d0			;restore cursor status
	move.l	a3,a0
	bsr	Cursor
	rts

;------------------------------------------------------------------
PrepareEcho:
	PUSH	a2/a3
	btst	#ACCB_JUSTIFIED,d6
	beq.s	.001
	lea	sJEcho(pc),a1
	bra.s	.002
.001	lea	sEcho(pc),a1
.002	move.w	accs_FieldLen(a2),d0
	move.w	d0,-(sp)	;max
	move.w	d0,-(sp)	;min
	move.l	sp,a2
	move.l	a3,a0
	lea	vsJustBuffer(a4),a3
	moveq	#32,d0		;this should be enough
	bsr	DoFormat	;format text to give the new format text
	addq.l	#4,sp
	PULL	a2/a3
	rts

;------------------------------------------------------------------
;	@Convert
;------------------------------------------------------------------
;
; Convert a string to a value.
;
; Decimal, Hex and Binary supported.
; Octal and Float not supported yet.
;
;------------------------------------------------------------------
; IN	d0.l	= Flags
;	d1.w	= MaxLen (or NULL-term)
;	a1.l	= ^String
;	a2.l	= ^Space for Result (Size: 32 bits)
; OUT	d0.l	= ^Result (0 = Error)
;------------------------------------------------------------------

Convert:
	PUSH	d2-d4/a2-a4
	subq.w	#1,d0
	beq.s	ConvertDecimal
	subq.w	#1,d0
	beq	ConvertHex
	subq.w	#1,d0
	beq	ConvertOctal
	subq.w	#1,d0
	beq	ConvertBinary
ConvertError:
	moveq	#0,d0
ConvertExit:
	PULL	d2-d4/a2-a4
	rts

;------------------------------------------------------------------
ConvertDecimal:
	move.l	a1,a3
.Loop	tst.b	(a3)+
	beq.s	.ZeroFound
	dbra	d1,.Loop
.ZeroFound			;a3 points behind number
	subq.l	#1,a3
	move.l	a3,d0
	sub.l	a1,d0		;determine numbers of ciffers
	beq.s	ConvertError	;skip if too small
	cmp.w	#10,d0
	bgt.s	ConvertError	;skip if too large
	clr.l	(a2)
	lea	alDecimalArray(pc),a4
	subq.w	#1,d0
.DecLoop
	moveq	#0,d3
	move.l	(a4)+,d2
	move.b	-(a3),d3
	sub.b	#'0',d3
	blo.s	ConvertError
	cmp.b	#9,d3
	bhi.s	ConvertError
	move.l	d3,d4
	mulu	d2,d3
	swap	d2
	mulu	d2,d4
	swap	d4
	add.l	d4,d3
	add.l	d3,(a2)
	bcs	ConvertError
	dbra	d0,.DecLoop
	move.l	a2,d0
	bra.s	ConvertExit

;------------------------------------------------------------------
ConvertHex:
	move.l	a1,a3
.Loop	tst.b	(a3)+
	beq.s	.ZeroFound
	dbra	d1,.Loop
.ZeroFound			;a3 points behind number
	subq.l	#1,a3
	move.l	a3,d0
	sub.l	a1,d0		;determine numbers of ciffers
	beq	ConvertError	;skip if too small
	cmp.w	#8,d0
	bgt	ConvertError	;skip if too large
	moveq	#0,d3
	moveq	#0,d1
	subq.w	#1,d0
.HexLoop
	move.b	(a1)+,d3
	sub.b	#'0',d3
	blt	ConvertError
	cmp.b	#9,d3
	ble.s	.HexNum
	bclr	#5,d3
	sub.b	#7,d3
	cmp.b	#$0A,d3
	blt	ConvertError
	cmp.b	#$0F,d3
	bgt	ConvertError
.HexNum	lsl.l	#4,d1
	or.w	d3,d1
	dbra	d0,.HexLoop
	move.l	d1,(a2)
	move.l	a2,d0
	bra	ConvertExit

;------------------------------------------------------------------
ConvertOctal:
	RETURN	0

;------------------------------------------------------------------
ConvertBinary:
	move.l	a1,a3
.Loop	tst.b	(a3)+
	beq.s	.ZeroFound
	dbra	d1,.Loop
.ZeroFound			;a3 points behind number
	subq.l	#1,a3
	move.l	a3,d0
	sub.l	a1,d0		;determine numbers of ciffers
	beq	ConvertError	;skip if too small
	cmp.w	#32,d0
	bgt	ConvertError	;skip if too large
	clr.l	(a2)
	moveq	#0,d1
	subq.w	#1,d0
.BinLoop
	move.b	(a1)+,d3
	sub.b	#'0',d3
	blt	ConvertError
	cmp.b	#1,d3
	bgt	ConvertError
	lsr.b	#1,d3
	roxl.l	#1,d1
	dbra	d0,.BinLoop
	move.l	d1,(a2)
	move.l	a2,d0
	bra	ConvertExit

;------------------------------------------------------------------
;	@SetMsgHandler
;------------------------------------------------------------------
;
; Set Message Handler.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	a1.l	= ^NewMsgHandler
; OUT	d0.l	= ^OldMsgHandler
;------------------------------------------------------------------

SetMsgHandler:
	move.l	cnh_MsgHandler(a0),d0
	move.l	a1,cnh_MsgHandler(a0)
	rts

;------------------------------------------------------------------
;	@GetInfo
;------------------------------------------------------------------
;
; Get some information about window.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	a1.l	= ^ConInfo
; OUT	d0.l	= ^ConInfo
;------------------------------------------------------------------

GetInfo:
	PUSH	d1/a2
	move.l	cnh_Unit(a0),a2
	move.w	cu_XCCP(a2),cin_XPos(a1)
	move.w	cu_YCCP(a2),cin_YPos(a1)
	move.w	cu_XMax(a2),cin_XSize(a1)
	move.w	cu_YMax(a2),cin_YSize(a1)
	moveq	#0,d0
	move.b	cu_AlgoStyle(a2),d1
	bne.s	.001
	bset	#SGFB_PLAIN,d0
	bra.s	.004
.001	btst	#FSB_BOLD,d1
	bne.s	.002
	bset	#SGFB_BOLD,d0
.002	btst	#FSB_ITALIC,d1
	bne.s	.003
	bset	#SGFB_ITALIC,d0
.003	btst	#FSB_UNDERLINED,d1
	bne.s	.004
	bset	#SGFB_UNDERLINED,d0
.004	move.w	d0,cin_Styles(a1)
	move.b	cu_FgPen(a2),d0
	add.w	#30,d0
	move.w	d0,cin_FgCol(a1)
	move.b	cu_BgPen(a2),d0
	add.w	#40,d0
	move.w	d0,cin_BgCol(a1)
	move.l	a1,d0
	PULL	d1/a2
	rts

;------------------------------------------------------------------
;	@SetGfx
;------------------------------------------------------------------
;
; Set styles and colors for window.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	d0.w	= Styles
;	d1.w	= Foreground Color
;	d2.w	= Background Color
; OUT	-
;------------------------------------------------------------------

SetGfx:
	PUSH	a1/a2/a3
	move.l	sp,a3
	move.l	#"%dm"<<8,-(sp)	;BgCol
	move.l	#"%-d;",-(sp)	;FgCol
	btst	#SGFB_PLAIN,d0
	beq.s	.001
	move.l	#"%-d;",-(sp)
.001	btst	#SGFB_BOLD,d0
	beq.s	.002
	move.l	#"%-d;",-(sp)
.002	btst	#SGFB_ITALIC,d0
	beq.s	.003
	move.l	#"%-d;",-(sp)
.003	btst	#SGFB_UNDERLINED,d0
	beq.s	.004
	move.l	#"%-d;",-(sp)
.004	move.w	#CSI,-(sp)
	move.l	sp,a1
	addq.l	#1,a1
	move.w	d2,-(sp)	;BgCol
	move.w	d1,-(sp)	;FgCol
	btst	#SGFB_PLAIN,d0
	beq.s	.101
	move.w	#0,-(sp)
.101	btst	#SGFB_BOLD,d0
	beq.s	.102
	move.w	#1,-(sp)
.102	btst	#SGFB_ITALIC,d0
	beq.s	.103
	move.w	#3,-(sp)
.103	btst	#SGFB_UNDERLINED,d0
	beq.s	.104
	move.w	#4,-(sp)
.104	move.l	sp,a2
	moveq	#-1,d0
	bsr	Display
	move.l	a3,sp
	PULL	a1/a2/a3
	rts

;------------------------------------------------------------------
;	@GotoXY
;------------------------------------------------------------------
;
; Place cursor at (X,Y).
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	d0.w	= XPos
;	d1.w	= YPos
; OUT	-
;------------------------------------------------------------------

GotoXY:
	PUSH	a1/a2
	lea	sGotoXY(pc),a1
	move.w	d0,-(sp)
	move.w	d1,-(sp)
	move.l	sp,a2
	moveq	#-1,d0
	bsr	Display
	addq.l	#4,sp
	PULL	a1/a2
	rts

;------------------------------------------------------------------
;	@Scroll
;------------------------------------------------------------------
;
; Scroll text in window <Step> lines.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	d0.w	= Step
; OUT	-
;------------------------------------------------------------------

Scroll:
	PUSH	a1/a2
	tst.w	d0
	beq.s	.Exit
	bmi.s	.001
	lea	sScrollDn(pc),a1
	bra.s	.002
.001	lea	sScrollUp(pc),a1
.002	move.w	d0,-(sp)
	moveq	#-1,d0
	move.l	sp,a2
	bsr	Display
	addq.l	#2,sp
.Exit	PULL	a1/a2
	rts

;------------------------------------------------------------------
;	@Cursor
;------------------------------------------------------------------
;
; Set Cursor mode.
;
; Currently only ON and OFF.
;
;------------------------------------------------------------------
; IN	a0.l	= ConHandle
;	d0.w	= Mode
; OUT	-
;------------------------------------------------------------------

Cursor:
	move.l	a1,-(sp)
	move.w	d0,cnh_CursorStatus(a0)
	beq.s	.001
	lea	sCursorOn(pc),a1
	bra.s	.002
.001	lea	sCursorOff(pc),a1
.002	moveq	#-1,d0
	bsr	DisplayRaw
	move.l	(sp)+,a1
	rts


;==================================================================
;==================================================================
;===								===
;===			DATA  AREA				===
;===								===
;==================================================================
;==================================================================

;--- Variable -----------------------------------------------------

pSysBase:	dc.l	0
dWriteReplyPort:dcb.b	MP_SIZE,0

;--- Text ---------------------------------------------------------

sLibName	dc.b	'con.library',0
sLibID		dc.b	'Console Library by BReese (31 oct 1991)',13,10,0
sIntName	dc.b	'intuition.library',0
sMathName	dc.b	'mathffp.library',0
sConDevName	dc.b	'console.device',0
sDosName	dc.b	'dos.library',0

sDosText
	dc.b	10,CSI,"1mCon.library",CSI,"0m is "
	dc.b	"a Copyright © 1991 by Bjørn Reese."
	dc.b	10,"------ You can't execute me, I'm a library ------"
	dc.b	10,10,0
sDosTextEnd

sDoStyle1	dc.b	27,'[0m',0
sDoStyle2	dc.b	27,'[1m',0
sDoStyle3	dc.b	27,'[3m',0
sDoStyle4	dc.b	27,'[4m',0
sDoFgCol	dc.b	27,'[30m',0
sDoBgCol	dc.b	27,'[40m',0

sEcho		dc.b	'%%-0%d.%ds',0
sJEcho		dc.b	'%%0%d.%ds',0
sGotoXY		dc.b	CSI,'%d;%dH',0
sCursorRight	dc.b	CSI,'C',0
sCursorLeft	dc.b	CSI,'D',0
sCursorOn	dc.b	CSI,' p',0
sCursorOff	dc.b	CSI,'0 p',0
sScrollUp	dc.b	CSI,'%dS',0
sScrollDn	dc.b	CSI,'%dT',0

sClear		dc.b	12,0		;Unused
sInsCh		dc.b	CSI,'%d@',0	;-
sDelCh		dc.b	CSI,'%dP',0	;-
sInsLn		dc.b	CSI,'L',0	;-
sDelLn		dc.b	CSI,'M',0	;-
	EVEN

;--- Table --------------------------------------------------------

alDecArray:
	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	0

alDecimalArray:
	dc.l	1
	dc.l	10
	dc.l	100
	dc.l	1000
	dc.l	10000
	dc.l	100000
	dc.l	1000000
	dc.l	10000000
	dc.l	100000000
	dc.l	1000000000

awDefDefTable:
	dc.w	alDefAll-awDefDefTable
	dc.w	alDefEmpty-awDefDefTable
	dc.w	alDefAlfanum-awDefDefTable
	dc.w	alDefAlfa-awDefDefTable
	dc.w	alDefNumeric-awDefDefTable
	dc.w	alDefDecimal-awDefDefTable
	dc.w	alDefHex-awDefDefTable
	dc.w	alDefOctal-awDefDefTable
	dc.w	alDefBinary-awDefDefTable
	dc.w	alDefFloat-awDefDefTable

alDefAll:
	dc.l	$ffffffff,$ffffffff,$ffffffff,$ffffffff
	dc.l	$ffffffff,$ffffffff,$ffffffff,$ffffffff
alDefEmpty:
	dc.l	0,0,0,0,0,0,0,0
alDefAlfanum:
	dc.l	0
	dc.l	%11111111111111111111111111111111 ;<SPC> ->
	dc.l	%11111111111111111111111111111111 ;A ->
	dc.l	%11111111111111111111111111111110 ;a ->  minus <DEL>
	dc.l	0
	dc.l	%11111111111111111111111111111111 ;<S-SPC> ->
	dc.l	%11111111111111111111111111111111 ;À ->
	dc.l	%11111111111111111111111111111111 ;à ->
alDefAlfa:
	dc.l	0
	dc.l	%10000000000000000000000000000000 ;<SPC>
	dc.l	%01111111111111111111111111100000 ;ABCDEFGHIJKLMNOPQRSTUVWXYZ
	dc.l	%01111111111111111111111111100000 ;abcdefghijklmnopqrstuvwxyz
	dc.l	0
	dc.l	%10000000000000000000000000000000 ;<S-SPC>
	dc.l	%11111111111111111111111011111111 ;À ->  minus ×
	dc.l	%11111111111111111111111011111111 ;à ->  minus ÷
alDefNumeric:
	dc.l	0
	dc.l	%00000000000011101111111111000000	;,-.0123456789
	dc.l	0,0,0,0,0,0
alDefDecimal:
	dc.l	0
	dc.l	%00000000000001001111111111000000	;-0123456789
	dc.l	0,0,0,0,0,0
alDefHex:
	dc.l	0
	dc.l	%00000000000001001111111111000000	;-0123456789
	dc.l	%01111110000000000000000000000000	;ABCDEFG
	dc.l	%01111110000000000000000000000000	;abcdefg
	dc.l	0,0,0,0
alDefOctal:
	dc.l	0
	dc.l	%00000000000001001111111100000000	;-01234567
	dc.l	0,0,0,0,0,0
alDefBinary:
	dc.l	0
	dc.l	%00000000000001001100000000000000	;-01
	dc.l	0,0,0,0,0,0
alDefFloat:
	dc.l	0
	dc.l	%00000000000111101111111111000000	;+,-.0123456789
	dc.l	%00000100000000000000000000000000	;E
	dc.l	%00000100000000000000000000000010	;e^
	dc.l	0,0,0,0


;--- END OF LIBRARY -----------------------------------------------
	CNOP	0,4
EndLib:


	IFNE	DEBUG

;==================================================================
;==================================================================
;===								===
;===			DEBUG CODE AREA				===
;===								===
;==================================================================
;==================================================================

;--- Comment ------------------------------------------------------
;
; To execute a function you may use CALL or JSR.
; - CALL is is the normal and correct way to access the function.
; - JSR is used to single-step into the actual library code.
;
;------------------------------------------------------------------

;--- System -------------------------------------------------------

	BASEREG	DebugDataArea,a5

;==================================================================
;===
;===	@DebugCode
;===
;==================================================================

	SECTION	ConDebug,CODE

DebugCode:
	lea	DebugDataArea(pc),a5	;Global Data Pointer

;--- Prepare Con Library

	move.l	(_SysBase).w,a6
	lea	LibFuncTable,a0
	lea	LibDataTable,a1
	lea	LibInit,a2
	move.l	#con_SIZEOF,d0
	moveq	#0,d1
	CALL	MakeLibrary
	move.l	d0,pLibrary(a5)
	beq	.Error
	move.l	d0,a1
	CALL	AddLibrary

;--- Open Con Library

	moveq	#0,d0
	lea	sConName(a5),a1
	CALL	OpenLibrary
	move.l	d0,pConBase(a5)

;--- Open ConWindow

	move.l	pConBase(a5),a6
	lea	dMyWindow(a5),a0
	move.w	#CURSORON,d0
	CALL	OpenCon
	move.l	d0,pConHandle(a5)

;--- Test various function

	move.l	pConBase(a5),a6		;Global for tests
	bsr	TestConvert
	bsr	TestDisplay
	bsr	TestDefineChars
	bsr	TestAcceptString
	bsr	TestAccept

;--- Clean up everything

	move.l	pConBase(a5),a6
	move.l	pConHandle(a5),a0
	CALL	CloseCon

	move.l	(_SysBase).w,a6
	move.l	pConBase(a5),a1
	CALL	CloseLibrary

	move.l	pLibrary(a5),a1
	CALL	RemLibrary
.Error	moveq	#0,d0
	rts


;------------------------------------------------------------------
;	@TestConvert
;------------------------------------------------------------------
;
; Convert a number (base determined by CNV_xxx in D0)
; and print it.
;
;------------------------------------------------------------------

TestConvert:
	move.l	#CNV_HEX,d0
	moveq	#-1,d1
	lea	sNumber(pc),a1
	lea	lNumber(pc),a2
	jsr	Convert
	tst.l	d0
	beq.s	.NoCnvt

	move.l	d0,a2
	move.l	pConHandle(pc),a0
	lea	sNumberText(pc),a1
	moveq	#-1,d0
	CALL	Display
.NoCnvt	rts

;------------------------------------------------------------------
;	@TestDefineChars
;------------------------------------------------------------------
;
; DefineChars must be called before using Accept/AcceptString to
; be sure that the correct chars are defined.
;
; DEFMODE_GET and DEFMODE_NEW are used to create a table from
; scratch, whereas DEFMODE_ADD and DEFMODE_SUB are used to change
; a table.
;
;------------------------------------------------------------------

TestDefineChars:

;--- Define ValidChars in Input structure

	lea	dInput+acc_ValidTable(pc),a1
	move.l	#DEFMODE_GET+DEFALFANUM,d0
	jsr	DefineChars

;--- Define ExitChars in Input structure

	lea	dInput+acc_ExitTable(pc),a1
	move.l	#DEFMODE_NEW,d0
	lea	aExitInput(pc),a2
	jsr	DefineChars

;--- Define ValidChars in Keypress structure

	lea	dKeypress+acc_ValidTable(pc),a1
	move.l	#DEFMODE_NEW,d0
	lea	sValidKeypress(pc),a2
	jsr	DefineChars

;--- Define ExitChars in Keypress structure

	lea	dKeypress+acc_ExitTable(pc),a1
	move.l	#DEFMODE_NEW,d0
	lea	aExitKeypress(pc),a2
	jsr	DefineChars
	rts

;------------------------------------------------------------------
;	@TestDisplay
;------------------------------------------------------------------
;
; Nice and simple.
;
;------------------------------------------------------------------

TestDisplay:
	moveq	#-1,d0
	move.l	pConHandle(pc),a0
	lea	sGoodDay(pc),a1
	lea	wGoodArg(pc),a2
	jsr	Display
	rts

;------------------------------------------------------------------
;	@TestAcceptString
;------------------------------------------------------------------
;
; Get an input string and display it.
;
;------------------------------------------------------------------

TestAcceptString:

;--- Get an input string

	move.l	pConHandle(pc),a0
	move.l	#ACCF_ERASE!ACCF_FULLSTOP,d0
	lea	dInput(pc),a1
	jsr	AcceptString

;--- Display the string found in accs_InputBuffer

	lea	lInputArg(pc),a2
	lea	dInput(pc),a1
	move.l	accs_InputBuffer(a1),(a2)
	moveq	#-1,d0
	move.l	pConHandle(pc),a0
	lea	sInputText(pc),a1
	CALL	Display
	rts

;------------------------------------------------------------------
;	@TestAccept
;------------------------------------------------------------------
;
; Display a message at a certain location and wait until a valid
; char was pressed.
;
; \{ was used in the text, but GotoXY() could have been used as well
;
;------------------------------------------------------------------

TestAccept:

;--- Display message

.Again	moveq	#-1,d0
	move.l	pConHandle(pc),a0
	lea	sContinue(pc),a1
	CALL	Display

;--- Get key

	move.l	pConHandle(pc),a0
	move.l	#ACCF_WAIT!ACCF_ECHO!ACCF_ERASE,d0
	lea	dKeypress(pc),a1
	jsr	Accept

;--- Repeat until a valid key was found

	cmp.w	#2,d0
	beq.s	.Again
	tst.w	d0
	bmi.s	.Again
	rts


;==================================================================
;==================================================================
;===								===
;===			DEBUG DATA AREA				===
;===								===
;==================================================================
;==================================================================

DebugDataArea:

;--- Variable -----------------------------------------------------

pConHandle	dc.l	0
pConBase	dc.l	0
pLibrary	dc.l	0

lNumber		dc.l	0
wGoodArg	dc.w	5432
lInputArg	dc.l	0


;--- Text ---------------------------------------------------------

sConName	dc.b	'con.library',0
sWindowTitle	dc.b	' ==== ',0

sNumber		dc.b	'ffffffff',0
sNumberText	dc.b	'Number was: %lu',10,0

aExitInput	dc.b	27,13,AKEY_HELP,0
sValidKeypress	dc.b	AKEY_F1,13,'Yy',0
aExitKeypress	dc.b	27,'Nn',0

sGoodDay	dc.b	'This is a test',10,10
		dc.b	'\Z3\B Here''s a\@ number: %d',10,0
sInputText	dc.b	10,10,10,'Input was: "%s"',10,0
sContinue	dc.b	'\{12;30HContinue\{14;30H(Y/N):',0
	EVEN

;--- Table --------------------------------------------------------

;--- AcceptStructure for a simple keypress

dKeypress:
	dc.w	-1,-1			;XStart,YStart
	dc.w	-1,-1,-1		;Styles,FgCol,BgCol
	dc.l	CLOSEWINDOW		;ExitFlags
	dcb.l	7,0			;Message stuff
	dc.b	0,0			;Char,Pad001
	dcb.b	CHARDEFSIZE,-1		;ValidTable
	dcb.b	CHARDEFSIZE,-1		;ExitTable
	dcb.l	4,0			;Reserved

;--- AcceptStructure for a input line

dInput:
	dc.w	30,5			;XStart,YStart
	dc.w	SGFF_BOLD,-1,-1		;Styles,FgCol,BgCol
	dc.l	CLOSEWINDOW		;ExitFlags
	dcb.l	7,0			;Message stuff
	dc.b	0,0			;Char,Pad001
	dcb.b	CHARDEFSIZE,-1		;ValidTable
	dcb.b	CHARDEFSIZE,-1		;ExitTable
	dcb.l	4,0			;Reserved
	dc.l	sInputBuffer		;InputBuffer
	dc.l	sWorkBuffer		;WorkBuffer
	dc.w	40,30			;MaxLength,FieldLen
	dc.w	0			;Length
	dc.w	0,0			;Position,DispPos
	dcb.l	2,0			;Reserved

;--- Intuition NewWindow Structure

MyIDCMP	SET CLOSEWINDOW
MyFlags	SET WINDOWSIZING!WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
MyFlags	SET MyFlags!SMART_REFRESH!ACTIVATE!NOCAREREFRESH

dMyWindow:
	dc.w	0,11		;LeftEdge, TopEdge
	dc.w	640,245		;Width, Height
	dc.b	0,1		;DetailPen, BlockPen
	dc.l	MyIDCMP		;IDCMPFlags
	dc.l	MyFlags		;Flags
	dc.l	0,0		;FirstGadget, CheckMark
	dc.l	sWindowTitle	;Title
	dc.l	0		;Screen
	dc.l	0		;BitMap
	dc.w	640,30		;MinWidth, MinHeight
	dc.w	-1,-1		;MaxWidth, MaxHeight
	dc.w	WBENCHSCREEN	;Type

;--- Buffer -------------------------------------------------------

sInputBuffer:
	dc.b	'Original buffer',0
	dcb.b	80-[*-sInputBuffer],0
sWorkBuffer:
	dcb.b	80,0

	ENDC
