* Prefs -	Set up alternate preferences without running the
*		program by the same name.
*
*		Working version finished 5/30/87 jec
*
* Included equate files.
* -----------------------------------------------------------------------
	NOLIST
	INCLUDE "exec/types.i"
	INCLUDE "exec/libraries.i"
	INCLUDE "libraries/dos.i"
	INCLUDE "libraries/dosextens.i"
	INCLUDE "exec/memory.i"
	INCLUDE "intuition/intuition.i"
	LIST

* External references
* -----------------------------------------------------------------------

	XREF		_AbsExecBase

	EXTERN_LIB	OpenLibrary
	EXTERN_LIB	CloseLibrary
	EXTERN_LIB	Open
	EXTERN_LIB	Close
	EXTERN_LIB	Read
	EXTERN_LIB	Write
	EXTERN_LIB	Output
	EXTERN_LIB	AllocMem
	EXTERN_LIB	FreeMem
	EXTERN_LIB	GetPrefs
	EXTERN_LIB	SetPrefs

* Local Equates
* ------------------------------------------------------------------------
TRUE	EQU	-1
FALSE	EQU	0

* Macros
* ------------------------------------------------------------------------

* Calls to dos.library and exec library
DOSCall MACRO
	LINKLIB _LVO\1,_DOSBase
	ENDM

ExeCall MACRO
	LINKLIB _LVO\1,_AbsExecBase
	ENDM

IntCall MACRO
	LINKLIB _LVO\1,_IntBase
	ENDM

* The print routine and argument setup
PRINT	MACRO
	lea.l	\1(PC),A0
	move.l	d5,d1
	jsr	print
	ENDM

* The code segment
* -------------------------------------------------------------------------
	RORG	0			; Relocatable code.

	jsr	argtrim 		; clean up command line
	MOVEM.L D0/A0-A2,-(SP)		; Save command line (OpenLibrary trashes).
	moveq	#0,d0

	;------ get Exec's library base pointer:
	LEA.L	DOSName(PC),A1		; name of dos library
	move.l	#LIBRARY_VERSION,d0

	ExeCall OpenLibrary
	MOVE.L	D0,_DOSBase		; Save library pointer
	beq	cleanup

	LEA.L	IntName(PC),A1		; name of dos library
	move.l	#LIBRARY_VERSION,d0

	ExeCall OpenLibrary
	MOVE.L	D0,_IntBase		; Save library pointer
	beq	cleanup

	; REGISTER USAGE:
	;	A0	= scratch after command line used.
	;	A5	= memory buffer pointer
	;	A6	= dos library base pointer
	;	D1-3	= AmigaDOS scratch argument registers
	;	D4	= file pointer
	;	D5	= output handle

*	Obtain the output handle (needed for write)
	DOSCall Output
	MOVE.L	D0,D5			; Save for the write

	MOVEM.L (SP)+,D0/A0-A2		; restore command line etc.

*	Now check if we have an argument.  If we have, attempt to open it.
	cmpi.b	#0,(a0) 		; a null string for an argument ?
	beq	noopen			; yes

	cmpi.b	#'-',(a0)               ; parameter?
	bne	openit			; just filename - load it
	addq	#1,a0
	cmpi.b	#'s',(a0)               ; save?
	bne.s	openit			; no, load instead
	moveq	#1,d0
	move.b	d0,saveit
	addq	#1,a0

*	Open specified name.  Place name in D1, access mode in D2
openit:
	cmpi.b	#' ',(a0)
	bne.s	op2
	addq	#1,a0
op2:
	move.l	a0,d1
	move.l	#MODE_OLDFILE,d2
	tst.b	saveit
	beq.s	op3
	move.l	#MODE_NEWFILE,d2
op3:
	movem.l d2-d7/a0-a6,-(sp)
	DOSCall Open
	movem.l (sp)+,d2-d7/a0-a6
	move.l	d0,d4			; remember for later
	beq	noopen			; did we get a lock?

	move.l	#pf_SIZEOF,D0		; size of the block
	move.l	#MEMF_PUBLIC,D1 	; memory requirement

	MOVEM.L D2-D7/A0-A6,-(SP)	; in case AllocMem trashes (it does...)
	ExeCall AllocMem		; args D0, D1 returns into D0
	MOVEM.L (SP)+,D2-D7/A0-A6	; restore registers
	move.l	d0,a5			; save it for later
	beq	nomem			; but did it work?

	move.l	a5,a0			; buffer to use
	move.l	#pf_SIZEOF,d0
	IntCall GetPrefs

	move.l	d4,d1			; file pointer
	move.l	a5,d2			; buffer to read into
	tst.b	pointer 		; are we just doing the pointer?
	bne	dopoint 		; yes, go do it
	move.l	#pf_SIZEOF,d3		; # bytes to use
	tst.b	saveit			; are we saving or loading?
	beq.s	nope			; nope, loading
	DOSCall Write			; save it out
	bra	cleanup 		; ..and quit!
nope:
	DOSCall Read			; read new prefs
	cmp.l	d0,d3			; see if enough read
	bne	notall			; couldn't read

	move.l	a5,a0			; buffer again
	move.l	#pf_SIZEOF,d0		; # of bytes
	moveq	#TRUE,d1		; nonzero in d1 = TRUE
	IntCall SetPrefs		; set new preferences & tell everbody
	bra	cleanup 		; and quit.

dopoint:
	move.l	d4,d1
	move.l	a5,d2
	add.l	#pf_PointerMatrix,d2
	move.l	#POINTERSIZE*2+8,d3
	tst.b	saveit
	beq.s	readit
	DOSCall Write
	bra.s	cleanup
readit:
	DOSCall Read
	cmp.l	d0,d3			; see if enough read
	bne.s	notall			; couldn't read

	move.l	a5,a0			; buffer again
	move.l	#pf_SIZEOF,d0		; # of bytes
	moveq	#TRUE,d1		; nonzero in d1 = TRUE
	IntCall SetPrefs		; set new preferences & tell everbody
	bra.s	cleanup 		; and quit.

nomem:
	PRINT	S_NOMEM
	bra.s	afterfree

noopen:
	PRINT	S_NOPEN
	bra.s	FINISHED

notall:
	PRINT	S_NREAD

cleanup:
	; start off by freeing allocated memory.
	move.l	a5,a1
	MOVEM.L D1-D7/A0-A6,-(SP)	; in case FreeMem trashes
	move.l	#pf_SIZEOF,D0
	ExeCall FreeMem
	MOVEM.L (SP)+,D1-D7/A0-A6	; restore registers

afterfree:
	move.l	d4,d1
	DOSCall Close
	tst.l	_DOSBase
	beq.s	af1
	move.l	_DOSBase,a1
	ExeCall CloseLibrary
af1:
	tst.l	_IntBase
	beq.s	af2
	move.l	_IntBase,a1
	ExeCall CloseLibrary
af2:
	move.l	#RETURN_OK,D0
FINISHED:
	rts

* Subroutines
* ------------------------------------------------------------------------

********************************************************************************
* argtrim:	a routine to trim the end of a command line and null terminate
*		it. This is achieved in the following manner:
*		Start at the end and run back until a non-whitespace (nl/blank)
*		character is encountered. If this is a quote, toss it.
*		If the *first* character is a quote, bump the start address by
*		one. No pretense of quote matching here.
*		 Inputs:	address in A0, length in D0
*		 Outputs:	address in A0.
********************************************************************************

argtrim:
	movem.l d1-d7/a1-a6,-(sp)	; save registers

	move.l	a0,a1
	add.l	d0,a1
	subq	#2,a1
	cmpi.b	#'"',(a1)               ; ends with a quote?
	bne.s	checkline		; no
	subq	#1,d0			; yes - decrement count
	move.l	d0,d1
	move.l	a0,a1			; get the temporary
at1:
	cmpi.b	#'"',(a1)
	beq.s	at2
	addq	#1,a1
	subq	#1,d1
	beq.s	checkline
	bra.s	at1
at2:
	move.b	1(a1),(a1)+
	dbf	d1,at2
	subq	#1,d0

checkline:
	cmpi.b	#1,D0			; length includes the newline
	bne.s	isline			; yes - there is something there
	move.b	#0,(a0) 		; create null string
	bra.s	argfini 		; done

isline:
;	strip off any run of blanks on the end...
	move.l	a0,a1			; computing end address of line
	add.l	d0,a1			;
	subq	#2,a1			;

toploop:
	cmp.l	a0,a1
	beq.s	empty			; single char or run of blanks

	cmpi.b	#' ',(a1)
	bne.s	endloop 		; finished the scan
	subq	#1,a1			; else back one more
	bra.s	toploop 		; and try again

endloop:
	cmpi.b	#'"',(a1)
	beq.s	nullit
nullnext:
	addq	#1,a1
nullit:
	move.b	#0,(a1)
	bra.s	argfini
empty:					; could be blanks or a single char
	cmpi.b	#' ',(a1)
	bne.s	endloop 		; or maybe a single quote!
	move.b	#0,(a0)

argfini:
	cmpi.b	#'p',-1(a1)
	bne.s	argret
	cmpi.b	#'.',-2(a1)
	bne.s	argret
	moveq	#1,d1
	move.b	d1,pointer
argret:
	movem.l (sp)+,d1-d7/a1-a6	; restore registers
	rts

********************************************************************************
* PRINT:	Passed an EA in A0, and a handle in D1, print the string.
********************************************************************************

print:
	MOVEM.L D0-D7/A0-A6,-(SP)

	; Let's find out how long this string is...
pr1:
	cmpi.b	#' ',(a0)+              ; strip leading blanks
	beq.s	pr1			;   for the size, doesn't
	subq	#1,a0			;   affect normal strings
	JSR	strlen			; Addr in A0 returns len in D0
	MOVE.L	D0,D3			; length
	MOVE.L	A0,D2			; Address
	DOSCall Write			; Handle already in D1

	; We don't check error returns from write, because there isn't a whole
	; lot we can do if console writes fail.
	MOVEM.L (SP)+,D0-D7/A0-A6	; Restore registers
	rts

********************************************************************************
* STRLEN:	How long is a piece of string? Pass a string in A0, the
*		result comes back in D0.
********************************************************************************

strlen:
	MOVEM.L D1-D7/A0-A6,-(SP)	; Save registers A0, D1 on stack.

	MOVEQ	#0,D0			; Initialize count

STRLOOP:
	; Investigate current character.
	cmpi.b	#0,(A0)+		; Is it a NUL?
	beq.s	STRFINI
	ADDQ	#1,D0			; Up the count
	bra	STRLOOP

STRFINI:
	MOVEM.L (SP)+,D1-D7/A0-A6	; Restore registers
	rts

********************************************************************************
* Data declarations
********************************************************************************

	CNOP	0,4
_DOSBase	DC.L	0
_IntBase	DC.L	0
pointer 	DC.B	0
saveit		DC.B	0
DOSName 	DC.B	'dos.library',0
IntName 	DC.B	'intuition.library',0
S_NOMEM 	DC.B	'No memory',10,0
S_NOPEN 	DC.B	'Couldn''t find file!',10,0
S_NREAD 	DC.B	'Couldn''t read new Preferences!',10,0
	END
