* 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"
	INCLUDE "offsets/exec.i"
	INCLUDE "offsets/dos.i"
	INCLUDE "offsets/intuition.i"
	LIST

	ifd	CAPE
	EXEOBJ
	objfile 'ram:Prefs'
	optimon -1
	endc

* Stack Frame Offsets
* ------------------------------------------------------------------------
DOSBase 	EQU	-10
IntBase 	EQU	-6
pointer 	EQU	-2
saveit		EQU	-1

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

* The code segment
* -------------------------------------------------------------------------
	link	a4,#-10
	jsr	argtrim 		; clean up command line
	MOVEM.L D0/A0-A2,-(SP)          ; Save command line (OpenLibrary trashes).

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

	move.l	_AbsExecBase,a6
	Call	OpenLibrary
	MOVE.L	D0,DOSBase(a4)          ; Save library pointer
	beq	cleanup

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

	Call	OpenLibrary
	MOVE.L	D0,IntBase(a4)          ; 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)
	move.l	DOSBase(a4),a6
	Call	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

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

*	Open specified name.  Place name in D1, access mode in D2
openit:
	cmpi.b	#' ',(a0)
	bne.s	op2
	addq.l	#1,a0
op2:
	move.l	a0,d1
	move.l	#MODE_OLDFILE,d2
	tst.b	saveit(a4)
	beq.s	op3
	move.l	#MODE_NEWFILE,d2
op3:
	move.l	DOSBase(a4),a6
	Call	Open			; check for the file
	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...)
	move.l	_AbsExecBase,a6
	Call	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
	move.l	IntBase(a4),a6
	Call	GetPrefs

	move.l	d4,d1			; file pointer
	move.l	a5,d2			; buffer to read into
	tst.b	pointer(a4)             ; are we just doing the pointer?
	bne	dopoint 		; yes, go do it
	move.l	#pf_SIZEOF,d3		; # bytes to use
	tst.b	saveit(a4)              ; are we saving or loading?
	beq.s	nope			; nope, loading
	move.l	DOSBase(a4),a6
	Call	Write			; save it out
	bra	cleanup 		; ..and quit!
nope:
	move.l	DOSBase(a4),a6
	Call	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
	move.l	IntBase(a4),a6
	Call	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(a4)
	beq.s	readit
	move.l	DOSBase(a4),a6
	Call	Write
	bra.s	cleanup
readit:
	move.l	DOSBase(a4),a6
	Call	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
	move.l	IntBase(a4),a6
	Call	SetPrefs		; set new preferences & tell everbody
	bra.s	cleanup 		; and quit.

nomem:
	move.l	d5,d1
	move.l	#S_NOMEM,d2
	move.l	#S_NOMLEN,d3
	move.l	DOSBase(a4),a6
	Call	Write
	bra.s	afterfree

noopen:
	move.l	d5,d1
	move.l	#S_NOPEN,d2
	move.l	#S_NOPLEN,d3
	move.l	DOSBase(a4),a6
	Call	Write
	bra.s	FINISHED

notall:
	move.l	d5,d1
	move.l	#S_NREAD,d2
	move.l	#S_NRELEN,d3
	move.l	DOSBase(a4),a6
	Call	Write

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
	move.l	_AbsExecBase,a6
	Call	FreeMem
	MOVEM.L (SP)+,D1-D7/A0-A6       ; restore registers

afterfree:
	move.l	d4,d1
	move.l	DOSBase(a4),a6
	Call	Close
	tst.l	DOSBase(a4)
	beq.s	af1
	move.l	DOSBase(a4),a1
	move.l	_AbsExecBase,a6
	Call	CloseLibrary
af1:
	tst.l	IntBase(a4)
	beq.s	af2
	move.l	IntBase(a4),a1
	Call	CloseLibrary
af2:
	move.l	#RETURN_OK,D0
FINISHED:
	unlk	a4
	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:
	move.b	#0,pointer(a4)
	cmpi.b	#'p',-1(a1)
	bne.s	argret
	cmpi.b	#'.',-2(a1)
	bne.s	argret
	move.b	#1,pointer(a4)
argret:
	movem.l (sp)+,d1-d7/a1-a6       ; restore registers
	rts

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

	CNOP	0,4
DOSName 	DC.B	'dos.library',0
IntName 	DC.B	'intuition.library',0
S_NOMEM 	DC.B	'No memory',10
S_NOMLEN	EQU	*-S_NOMEM
S_NOPEN 	DC.B	'Couldn''t find file!',10
S_NOPLEN	EQU	*-S_NOPEN
S_NREAD 	DC.B	'Couldn''t read new Preferences!',10
S_NRELEN	EQU	*-S_NREAD
	END
