

* Crossword disc functions file
* This file contains all of the functions required to implement the
* disc access panel.


* DiscPanelOn(a6) -> d0
* a6 = ptr to main program variables
* Opens disc access panel windows & links them to a
* common userport.

* Returns d0=NULL if failed to pop up the panel.

* d0/a0 corrupt


DiscPanelOn	lea	DiscWindow1(pc),a0
		move.l	ms_handle(a6),d0
		move.l	d0,30(a0)	;set Custom screen ptr

		CALLINT	OpenWindow

		move.l	d0,dp_window1(a6)
		beq.s	DPON_Exit
		move.l	d0,a0
		move.l	RastPort(a0),dp_rastport1(a6)

		lea	DiscWindow2(pc),a0
		move.l	ms_handle(a6),d0
		move.l	d0,30(a0)

		CALLINT 	OpenWindow

		move.l	d0,dp_window2(a6)
		beq.s	DPON_Exit
		move.l	d0,a0
		move.l	RastPort(a0),dp_rastport2(a6)

		move.l	d0,a1		;now copy the
		move.l	dp_window1(a6),a0	;Userport across

		move.l	UserPort(a0),d0
		move.l	d0,dp_userport(a6)
		move.l	d0,UserPort(a1)

		move.l	a1,a0
		move.l	#GADGETUP+GADGETDOWN,d0
		add.l	#DISKINSERTED+DISKREMOVED,d0
		CALLINT	ModifyIDCMP

		moveq	#-1,d0		;signal success

DPON_Exit	rts


* DiscPanelOff(a6)
* a6 = ptr to main program variables
* Unlinks disc access panel windows from common userport,
* then closes them.

* d0/a0 corrupt


DiscPanelOff	move.l	dp_window2(a6),d0
		beq.s	DPOFF_1

		move.l	d0,a0
		clr.l	UserPort(a0)	;here delink UserPort

		moveq	#0,d0
		CALLINT	ModifyIDCMP

		move.l	dp_window2(a6),a0
		CALLINT	CloseWindow

DPOFF_1		move.l	dp_window1(a6),d0
		beq.s	DPOFF_2

		move.l	d0,a0
		CALLINT	CloseWindow

DPOFF_2		rts


* DoDiscPanel(a6)
* a6 = ptr to main program variables

* Bring disc access panel to life, then enter event handler loop
* for disc access panel until the "DONE!" gadget hit. Then, exit
* the disc access panel.

* ASSUME ALL REGISTERS CORRUPT!


DoDiscPanel	btst	#1,applic_flag2(a6)	;requesting help?
		beq.s	DDP_ok			;no

		lea	Help_DA(pc),a0	;get help panel
		moveq	#6,d0		;data

		bsr	_PopUpQR		;pop up requester

		beq	ExitDP		;and exit if NO gadget pressed

DDP_ok		bsr	DiscPanelOn

		beq.s	DoneDP

		bsr	CancelButtons	;set initial buttons states

		bsr	DiscPointer

		bset	#5,applic_flag2(a6)	;set Panel flag

		bsr	SetDF0		;show contents of DF0:

DDP_1		move.l	dp_userport(a6),a0
		lea	ehb_dp(pc),a5

		bsr	DoEvent		;handle DP events

		btst	#5,applic_flag2(a6)	;exiting panel?
		bne.s	DDP_1			;loop back if not

		move.l	dp_window2(a6),a0
		CALLINT	ClearPointer

		move.l	dp_window1(a6),a0
		CALLINT	ClearPointer

DoneDP		bsr	DiscPanelOff

ExitDP		rts


* ByeDP(a6)
* a6 = ptr to main program variables
* Exit from Disc Access Panel

* nothing corrupt

ByeDP		bclr	#5,applic_flag2(a6)
		rts


* SortDir(a6) -> (a6)
* a6 = ptr to main program variables

* generate sorted dir list.
* Returns error code in vars list.
* This edited version also checks to see if the
* path supplied is a true directory. If it's a
* file, then it exits and calls ForgetDir()
* without further ado.

* d0-d7/a0-a2 corrupt


SortDir		move.l	dir_name(a6),d1
		move.l	#ACCESS_READ,d2

		CALLDOS	Lock		;get dir lock
		move.l	d0,dir_lock(a6)	;got it?
		bne.s	SDR_1		;yes, continue

		moveq	#1,d0		;else no lock available
		bra	SDR_Error

SDR_1		move.l	#lh_sizeof,d0
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1

		CALLEXEC	AllocMem
		move.l	d0,dir_flist(a6)	;got a list header?
		bne.s	SDR_2

		moveq	#2,d0		;else no memory available
		bra	SDR_Error
		
SDR_2		move.l	#lh_sizeof,d0
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1

		CALLEXEC	AllocMem
		move.l	d0,dir_dlist(a6)	;got a list header?
		bne.s	SDR_3

		moveq	#2,d0		;else no memory available
		bra	SDR_Error

SDR_3		move.l	dir_flist(a6),a0	;perform a NEWLIST
		move.l	a0,(a0)		;function on the list
		addq.l	#4,(a0)		;header struct
		clr.l	4(a0)		;for files list
		move.l	a0,8(a0)
		move.b	#1,12(a0)

		move.l	dir_dlist(a6),a0	;perform a NEWLIST
		move.l	a0,(a0)		;function on the list
		addq.l	#4,(a0)		;header struct
		clr.l	4(a0)		;for dirs list
		move.l	a0,8(a0)
		move.b	#1,12(a0)


* Ok, now we have the list structures. Now allocate some memory for
* the FileInfoBlock.


		move.l	#260,d0
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,dir_iblk(a6)	;got a FileInfoBlock?
		bne.s	SDR_4		;yes-continue

		moveq	#2,d0		;else no memory availble
		bra	SDR_Error


* Now allocate some memory for the list nodes


SDR_4		move.l	#4096,d0			;4K should be enough
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,dir_nodes(a6)		;got node space?
		bne.s	SDR_5			;continue if so

		moveq	#2,d0
		bra	SDR_Error


* Now allocate some memory for the strings


SDR_5		move.l	d0,dir_nodepos(a6)

		move.l	#16384,d0		;16K should be enough
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,dir_strings(a6)	;got string space?
		bne.s	SDR_6			;continue if so

		moveq	#2,d0
		bra	SDR_Error


* Now start reading the directory!


SDR_6		move.l	d0,dir_strpos(a6)

		moveq	#0,d0

		move.w	d0,dir_fcount(a6)	;set up total file &
		move.w	d0,dir_dcount(a6)	;subdirectory counts

		move.l	dir_lock(a6),d1
		move.l	dir_iblk(a6),d2

		CALLDOS	Examine		;get dir name

		tst.l	d0
		bne.s	SDR_6a		;and continue if poss

		moveq	#3,d0		;oops-non-accessible
		bra	SDR_Error

SDR_6a		move.l	dir_iblk(a6),a0	;check path
		tst.l	4(a0)		;is it a directory?
		bpl.s	SDR_7		;skip if so

		bsr	ForgetDir	;else exit NOW
		moveq	#4,d0		;and signal the error
		bra	SDR_Error

SDR_7		move.l	dir_lock(a6),d1
		move.l	dir_iblk(a6),d2

		CALLDOS	ExNext		;get entry

		tst.l	d0		;run out of dir entries?
		beq	SDR_8		;skip if so


* Here prepare for list update. Get d7=entry type (file/dir),
* d6=ptr to list to use, d5=ptr to current string entry in
* string space after the copy, d4=ptr to new node. Prior to
* this, however, check for a .info file and if it is, don't
* include it in the list.


		move.l	dir_iblk(a6),a0	;info block
		lea	8(a0),a0		;point to file/dir name string

SDR_15		tst.b	(a0)+		;find EOS
		bne.s	SDR_15

		subq.l	#1,a0		;point to EOS
		cmp.b	#"o",-(a0)	;last char "o"?
		bne.s	SDR_16		;no
		cmp.b	#"f",-(a0)	;prev "f"?
		bne.s	SDR_16		;no
		cmp.b	#"n",-(a0)	;prev "n"?
		bne.s	SDR_16		;no
		cmp.b	#"i",-(a0)	;prev "i"?
		bne.s	SDR_16		;no
		cmp.b	#".",-(a0)	;prev "."?
		beq.s	SDR_7		;get another if so

SDR_16		move.l	dir_nodepos(a6),d4

		move.l	dir_iblk(a6),a0	;get ptr to info block
		move.l	4(a0),d7		;get entry type
		lea	8(a0),a0		;point to string
		move.l	dir_strpos(a6),d5
		move.l	d5,a1
		bsr	CopyString	;copy to buffer
		move.l	a1,dir_strpos(a6)	;save new end of strings

		move.l	dir_flist(a6),d6	;point to files list
		tst.l	d7		;entry = file?
		bmi.s	SDR_9		;skip if so
		move.l	dir_dlist(a6),d6	;else point to dirs list


* Now check for empty list. If list empty, just append the
* new node to the list.


SDR_9		move.l	d6,a0
		cmp.l	lh_TailPred(a0),a0	;empty list?
		bne.s	SDR_10			;skip if not


* Here, list empty. Create node, append to list.


		move.l	d4,a0		;ptr to new node
		clr.b	ln_Type(a0)	;create node
		clr.b	ln_Pri(a0)
		move.l	d5,ln_Name(a0)	;pop in string

		move.l	d6,a0
		move.l	d4,a1
		sub.l	a2,a2

SDR_11		CALLEXEC	Insert		;and pop it in

		tst.l	d7		;file or dir?
		smi	d0		;set d0 if file
		ext.w	d0
		sub.w	d0,dir_fcount(a6)	;update file count

		tst.l	d7		;file or dir?
		spl	d0		;set d0 if dir
		ext.w	d0
		sub.w	d0,dir_dcount(a6)	;update dir count

		move.l	d4,a0
		add.w	#ln_sizeof,a0
		move.l	a0,dir_nodepos(a6)	;next new node!

		bra	SDR_7		;and back for more


* Here, list non-empty. Create node, compare strings
* with previous nodes, until hit a higher string. If
* hit end of list, put new node on end of list.


SDR_10		move.l	d6,a2		;ptr to list
		move.l	lh_Head(a2),a2	;ptr to 1st node

SDR_12		move.l	d5,a1		;dest string
		move.l	ln_Name(a2),a0	;source string
		bsr	CmpStr		;compare strings
		bcs.s	SDR_14		;found a lower one-skip

		move.l	ln_Succ(a2),d0	;point to next node
		move.l	d6,a0		;point to list
		lea	lh_Tail(a0),a0
		cmp.l	d0,a0		;hit end of list?
		beq.s	SDR_13		;skip if hit end
		move.l	d0,a2		;else point to new node
		bra.s	SDR_12		and resume scan


* Here, we're ready to insert node. Create node & insert.


SDR_14		move.l	ln_Pred(a2),a2	;point to pred if str higher

SDR_13		move.l	d4,a0
		clr.b	ln_Type(a0)	;create node
		clr.b	ln_Pri(a0)
		move.l	d5,ln_Name(a0)	;pop in string
		move.l	d6,a0
		move.l	d4,a1
		bra.s	SDR_11


* Here we've done it. Free the lock on the directory &
* return with "all's well" error code.


SDR_8		move.w	dir_dcount(a6),d0
		add.w	dir_fcount(a6),d0
		move.w	d0,dir_entnum(a6)	;set total entry count

		moveq	#0,d0		;signal all's well

SDR_Error	move.w	d0,dir_error(a6)

		move.l	dir_lock(a6),d1	;got a lock?
		beq.s	SDR_Done		;skip if not
		CALLDOS	UnLock		;else Unlock it!

SDR_Done		rts


* ForgetDir(a6)
* a6 = ptr to main program variables
* Deallocates all memory used by SortDir() &
* thus forgets the sorted directory.

* d0/a1 corrupt


ForgetDir	move.l	dir_strings(a6),d0
		beq.s	FDR_4
		move.l	d0,a1
		move.l	#16384,d0
		CALLEXEC	FreeMem

FDR_4		move.l	dir_nodes(a6),d0
		beq.s	FDR_3
		move.l	d0,a1
		move.l	#4096,d0
		CALLEXEC	FreeMem

FDR_3		move.l	dir_iblk(a6),d0
		beq.s	FDR_2
		move.l	d0,a1
		move.l	#260,d0
		CALLEXEC	FreeMem

FDR_2		move.l	dir_dlist(a6),d0
		beq.s	FDR_1
		move.l	d0,a1
		move.l	#lh_sizeof,d0
		CALLEXEC	FreeMem

FDR_1		move.l	dir_flist(a6),d0
		beq.s	FDR_Done
		move.l	d0,a1
		move.l	#lh_sizeof,d0
		CALLEXEC	FreeMem

FDR_Done		moveq	#0,d0			;ensure that

		move.l	d0,dir_flist(a6)		;all of these
		move.l	d0,dir_dlist(a6)		;variables do not
		move.l	d0,dir_iblk(a6)		;point to valid
		move.l	d0,dir_nodes(a6)		;memory areas!
		move.l	d0,dir_nodepos(a6)
		move.l	d0,dir_strings(a6)
		move.l	d0,dir_strpos(a6)
		move.w	d0,dir_fcount(a6)
		move.w	d0,dir_dcount(a6)

		rts


* SetPath1(a6)
* a6 = ptr to main program variables

* Create path name from the volume & directory
* gadgets. Called by code linked to Load/Save/Delete
* gadgets.

* a0-a1 corrupt


SetPath1		lea	ND_VolName(pc),a0		;ptr to volume name
		move.l	gg_SpecialInfo(a0),a0	;gadget
		move.l	si_Buffer(a0),a0		;here point to string
		tst.b	(a0)			;null string?
		beq.s	SP1_Done
		move.l	dir_name(a6),a1
		bsr	CopyString		;copy to buffer

		subq.l	#1,a1			;point to EOS

		lea	ND_DirName(pc),a0		;ptr to directory name
		move.l	gg_SpecialInfo(a0),a0	;gadget
		move.l	si_Buffer(a0),a0		;here point to string
		tst.b	(a0)			;null string?
		beq.s	SP1_Done
		cmp.b	#"/",(a0)		;initial "/"?
		bne.s	SP1_B1			;skip if not
		addq.l	#1,a0			;else point past it

SP1_B1		bsr	CopyString		;copy to buffer

		subq.l	#1,a1			;point to EOS

;		lea	ND_FileName(pc),a0	;ptr to file name
;		move.l	gg_SpecialInfo(a0),a0	;gadget
;		move.l	si_Buffer(a0),a0		;here point to string
;		tst.b	(a0)			;null string?
;		beq.s	SP1_Done

;		bsr	CopyString		;copy to buffer

SP1_Done		rts


* SetPath2(a6)
* a6 = ptr to main program variables

* Create path name from the volume & directory
* gadgets. Other code called from Rename gadget
* calls this.

* a0-a1 corrupt


SetPath2		lea	ND_VolName(pc),a0		;ptr to volume name
		move.l	gg_SpecialInfo(a0),a0	;gadget
		move.l	si_Buffer(a0),a0		;here point to string
		tst.b	(a0)			;null string?
		beq.s	SP2_Done
		move.l	dir_rename(a6),a1
		bsr	CopyString		;copy to buffer

		subq.l	#1,a1			;point to EOS

		lea	ND_DirName(pc),a0		;ptr to directory name
		move.l	gg_SpecialInfo(a0),a0	;gadget
		move.l	si_Buffer(a0),a0		;here point to string
		tst.b	(a0)			;null string?
		beq.s	SP2_Done
		cmp.b	#"/",(a0)		;initial "/"?
		bne.s	SP2_B1			;skip if not
		addq.l	#1,a0			;else point past it

SP2_B1		bsr	CopyString		;copy to buffer

		subq.l	#1,a1			;point to EOS

;		lea	ND_NewName(pc),a0		;ptr to rename name
;		move.l	gg_SpecialInfo(a0),a0	;gadget
;		move.l	si_Buffer(a0),a0		;here point to string
;		tst.b	(a0)			;null string?
;		beq.s	SP2_Done

;		bsr	CopyString		;copy to buffer

SP2_Done		rts


* SetDirTexts(a6)
* a6 = ptr to main program variables

* Set the IntuiTexts for the directory list to point to
* the directory strings, and then display them.

* d0-d5/a0-a2 corrupt


SetDirTexts	tst.l	dir_dlist(a6)	;list exists?
		beq	SDTX_Done	;exit NOW if not

		tst.l	dir_flist(a6)	;list exists?
		beq	SDTX_Done	;exit NOW if not

		lea	ND_T1(pc),a0	;point to ITexts

		moveq	#3,d3		;colour byte

		moveq	#0,d0		;no of texts processed

		move.w	dir_entpos(a6),d1	;1st entry used
		addq.w	#1,d1


* First use dir_entpos(a6) to find nth entry in list (one we're
* starting with). If we hit end of list before count hits zero,
* change from dirs list to files list.


		move.l	dir_dlist(a6),a1	;ptr to list
		move.l	a1,d4
		lea	lh_Tail(a1),a2
		move.l	a2,d5
		move.l	lh_Head(a1),a1	;point to 1st entry

SDTX_1		move.l	ln_Succ(a1),d2	;got a successor?
		beq.s	SDTX_2		;no, so exit!

		subq.w	#1,d1		;this entry?
		beq.s	SDTX_4		;skip if so

		move.l	d2,a1		;else point to successor
		bra.s	SDTX_1		;and continue scan

SDTX_2		moveq	#1,d3		;change colour!

		move.l	dir_flist(a6),a1
		move.l	a1,d4
		lea	lh_Tail(a1),a2
		move.l	a2,d5
		move.l	lh_Head(a1),a1

SDTX_3		move.l	ln_Succ(a1),d2	;got a successor?
;		beq	SDTX_Done	;no, so finished!
		beq.s	SDTX_8

		subq.w	#1,d1		;this entry?
		beq.s	SDTX_4

		move.l	d2,a1		;else point to successor
		bra.s	SDTX_3		;and continue scan


* Here, we've found the first entry to use. Start inserting the
* list texts into the IText structures.


SDTX_4		move.l	ln_Name(a1),12(a0)	;copy name ptr
		move.b	d3,(a0)			;set FGND colour
		lea	20(a0),a2		;point to next IText

		addq.w	#1,d0			;this many done
		cmp.w	#DIRCOUNT,d0		;done them all?
		beq.s	SDTX_5			;exit if so

		move.l	a2,16(a0)		;continue IText chain
		move.l	a2,a0

SDTX_7		move.l	ln_Succ(a1),d2		;get successor
		cmp.l	d2,d5			;hit list end?
		beq.s	SDTX_6			;skip if none

		move.l	d2,a1
		bra.s	SDTX_4

SDTX_6		cmp.l	dir_dlist(a6),d4		;end of dirs?
		bne.s	SDTX_8			;if not, leave loop

		move.l	dir_flist(a6),a1		;else get files list
		move.l	a1,d4
		lea	lh_Tail(a1),a2
		move.l	a2,d5
;		move.l	lh_Head(a1),a1

		moveq	#1,d3			;and change colour
		bra.s	SDTX_7			;and continue


* Here, we haven't enough text entries in either list. So fill in
* the remaining entries with blanks.


SDTX_8		lea	BlankDT(pc),a1	;ptr to blank string

SDTX_9		move.l	a1,12(a0)	;process IText
		lea	20(a0),a2

		addq.w	#1,d0		;update count
		cmp.w	#DIRCOUNT,d0	;done them all?
		beq.s	SDTX_5

		move.l	a2,a0		;point to next IText
		bra.s	SDTX_9

SDTX_5		clr.l	16(a0)		;end IText list chain		

		move.l	dp_rastport2(a6),a1
		moveq	#4,d0
		CALLGRAF	SetRast

		lea	ND_T1(pc),a1
		moveq	#0,d0
		move.l	d0,d1
		move.l	dp_rastport2(a6),a0

		CALLINT	PrintIText

SDTX_Done	rts


BlankDT		dc.b	"          ",0
		even


* SetDPProp(a6)
* a6 = ptr to main program variables

* Take list entry counts formed by SortDir() & use to
* create Disc Panel Propgadget values.

* d0-d5/a0-a2 corrupt


SetDPProp	lea	ND_VPot(pc),a0
		move.l	dp_window1(a6),a1
		sub.l	a2,a2
		moveq	#1,d5
		move.w	#FREEVERT+PROPBORDERLESS,d0

		move.w	dir_entnum(a6),d2
		cmp.w	#DIRCOUNT,d2	;too few to scroll?
		bhi.s	SDPP_1		;skip if not

		moveq	#1,d4	;else set PropGadget to
		neg.w	d4	;these values
		moveq	#0,d2
		move.l	d2,d1
		move.l	d2,d3
		bra.s	SDPP_2

SDPP_1		sub.w	#DIRCOUNT,d2	;create no of scroll pos'ns
		moveq	#1,d4
		neg.w	d4
		divu	d2,d4
		moveq	#0,d2
		move.l	d2,d1
		move.l	d2,d3

SDPP_2		CALLINT	NewModifyProp

		clr.w	dir_entpos(a6)

		rts


* DoDPProp(a6)
* a6 = ptr to main program variables
* handle the vertical PropGadget on the Disc Panel.

* d0-d2/a0/a5 corrupt


DoDPProp		lea	ND_VPot(pc),a0
		move.l	gg_SpecialInfo(a0),a0
		move.l	a0,a5			;get pot data

DDPP_1		moveq	#0,d0
		move.l	d0,d1
		move.w	pi_VertPot(a5),d0		;get Pot and Body
		move.w	pi_VertBody(a5),d1	;values

		divu	d1,d0			;get entpos value

		move.w	dir_entnum(a6),d2		;get total slider size
		sub.w	#DIRCOUNT,d2		;data
		bpl.s	DDPP_2

		moveq	#0,d2		;use this if too small

DDPP_2		cmp.w	d2,d0		;our value too big?
		bcs.s	DDPP_3		;skip if not

		move.w	d2,d0		;else use this

DDPP_3		cmp.w	dir_entpos(a6),d0	;already at this value?
		beq.s	DDPP_4		;skip if so

		move.w	d0,dir_entpos(a6)	;else set new value

		bsr	SetDirTexts	;and show new texts

DDPP_4		move.w	pi_Flags(a5),d0	;playing with slider knob?
		and.w	#KNOBHIT,d0
		beq.s	DDPP_Done	;exit if not

		btst	#6,$BFE001	;else loop back until mouse
		beq.s	DDPP_1		;button released.

DDPP_Done	rts


* IncDirPos(a6)
* a6 = ptr to main program variables

* Scroll directory listing one entry down when the
* Down gadget is pressed. Checks to see if scrolling
* is possible first, & scolls only if so.

* d0-d5/a0-a2 corrupt


IncDirPos	move.w	dir_entnum(a6),d0	;check no. of dir entries
		cmp.w	#DIRCOUNT,d0	;enough entries?
		bhi.s	IDPS_1		;yes
IDPS_2		rts			;else skip

IDPS_1		move.w	dir_entpos(a6),d0	;get position
		addq.w	#1,d0		;next position

		move.w	d0,d1		;copy new position
		add.w	#DIRCOUNT,d1
		cmp.w	dir_entnum(a6),d1	;overrun?
		bhi.s	IDPS_2		;exit if so
		move.w	d0,dir_entpos(a6)	;set new position


* Now having updated the position, refresh the PropGadget. First
* get its data, then move slider, then refresh the gadget.


		lea	ND_VPot(pc),a0		;ptr to PropGadget
		move.l	gg_SpecialInfo(a0),a1	;get SpecialInfo

		move.w	pi_Flags(a1),d0
		move.w	pi_HorizPot(a1),d1
		move.w	pi_VertPot(a1),d2
		move.w	pi_HorizBody(a1),d3
		move.w	pi_VertBody(a1),d4

		moveq	#1,d5

		add.w	d4,d2

		move.l	dp_window1(a6),a1
		sub.l	a2,a2

		CALLINT	NewModifyProp


* Now redisplay the texts.


		bsr	SetDirTexts

		rts


* DecDirPos(a6)
* a6 = ptr to main program variables

* Scroll directory listing one entry up when the
* Up gadget is pressed. Checks to see if scrolling
* is possible first, & scolls only if so.

* d0-d5/a0-a2 corrupt


DecDirPos	move.w	dir_entnum(a6),d0	;check no. of dir entries
		cmp.w	#DIRCOUNT,d0	;enough entries?
		bhi.s	DDPS_1		;yes
DDPS_2		rts			;else skip

DDPS_1		move.w	dir_entpos(a6),d0	;get position
		beq.s	DDPS_2		;if at top, exit
		subq.w	#1,d0		;next position

		move.w	d0,dir_entpos(a6)	;set new position


* Now having updated the position, refresh the PropGadget. First
* get its data, then move slider, then refresh the gadget.


		lea	ND_VPot(pc),a0		;ptr to PropGadget
		move.l	gg_SpecialInfo(a0),a1	;get SpecialInfo

		move.w	pi_Flags(a1),d0
		move.w	pi_HorizPot(a1),d1
		move.w	pi_VertPot(a1),d2
		move.w	pi_HorizBody(a1),d3
		move.w	pi_VertBody(a1),d4

		moveq	#1,d5

		sub.w	d4,d2

		move.l	dp_window1(a6),a1
		sub.l	a2,a2

		CALLINT	NewModifyProp


* Now redisplay the texts.


		bsr	SetDirTexts

		rts


* GetParent(a6)
* a6 = ptr to main program variables
* if directory name gadget contains a directory
* name, find the parent directory and display the
* contents using SetDirTexts(). If no directory
* name, we're at the root, so exit.

* corrupt


GetParent	lea	ND_DirName(pc),a1		;ptr to gadget
		move.l	a1,-(sp)			;save it
		move.l	dp_window1(a6),a0
		moveq	#1,d0

		CALLINT	RemoveGList		;unlink it

		move.l	(sp)+,a0			;recover it

		move.l	gg_SpecialInfo(a0),a0	;ptr to SpecialInfo
		move.l	si_Buffer(a0),a0		;ptr to dir name

		tst.b	(a0)			;at root dir?
		beq.s	GPT_Done			;exit if so

GPT_1		tst.b	(a0)+		;skip to end of text
		bne.s	GPT_1

		subq.l	#1,a0		;point to EOS

GPT_2		cmp.b	#"/",-(a0)	;found directory separator?
		bne.s	GPT_2

		clr.b	(a0)		;EOS it out!

		lea	ND_DirName(pc),a1
		move.l	dp_window1(a6),a0
		sub.l	a2,a2
		moveq	#15,d0
		moveq	#1,d1

		CALLINT	AddGList		;link gadget back in

		lea	ND_DirName(pc),a0
		move.l	dp_window1(a6),a1
		sub.l	a2,a2
		moveq	#1,d0

		CALLINT	RefreshGList	;and show results

		bra	ShowDir		;now show directory!

GPT_Done		rts


* SetDF0(a6)
* a6 = ptr to main program variables

* Sets the "Volume" string gadget to "DF0:"
* and activates the SortDir() routine. Also
* clears the texts from the DirName and the
* FileName gadgets.


* d0-d1/a0-a2 corrupt


SetDF0		lea	ND_VolName(pc),a1		;unlink the string
		move.l	dp_window1(a6),a0		;gadgets prior to
		moveq	#3,d0			;alteration

		CALLINT	RemoveGList

		lea	ND_VolName(pc),a0		;gadget ptr
		move.l	a0,a1			;keep a copy

		move.l	gg_SpecialInfo(a0),a0	;Now pop in the
		move.w	#4,si_BufferPos(a0)	;text for the
		move.l	si_Buffer(a0),a0		;drive DF0:
		move.l	#"DF0:",(a0)+		;in the volume name
		clr.b	(a0)			;gadget

		move.l	a1,a0			;recover copy

		move.l	(a1),a1		;next gadget (=dir name)

		move.l	gg_SpecialInfo(a1),a2	;now clear the
		clr.w	si_BufferPos(a2)		;directory name
		move.l	si_Buffer(a2),a2		;gadget
		clr.b	(a2)

;		move.l	(a1),a1		;next gadget (=file name)

;		move.l	gg_SpecialInfo(a1),a2	;now clear the
;		clr.w	si_BufferPos(a2)		;file name
;		move.l	si_Buffer(a2),a2		;gadget
;		clr.b	(a2)

		move.l	a0,a1			;these gadgets are
		move.l	dp_window1(a6),a0		;in a window, not a
		sub.l	a2,a2			;requester

		moveq	#14,d0			;now link them
		moveq	#3,d1			;back in

		CALLINT	AddGList

		lea	ND_VolName(pc),a0		;now refresh the
		move.l	dp_window1(a6),a1		;gadget
		sub.l	a2,a2
		moveq	#3,d0

		CALLINT	RefreshGList

ShowDir		bsr	ForgetDir

		lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)

		bsr	SetPath1
		bsr	SortDir
		bsr	SetDPProp

		bsr	SetDirTexts

		rts


* SetDF1(a6)
* a6 = ptr to main program variables

* Sets the "Volume" string gadget to "DF1:"
* and activates the SortDir() routine.


* d0-d1/a0-a2 corrupt


SetDF1		lea	ND_VolName(pc),a1		;unlink the string
		move.l	dp_window1(a6),a0		;gadgets prior to
		moveq	#3,d0			;alteration

		CALLINT	RemoveGList

		lea	ND_VolName(pc),a0		;gadget ptr
		move.l	a0,a1			;keep a copy

		move.l	gg_SpecialInfo(a0),a0	;Now pop in the
		move.w	#4,si_BufferPos(a0)	;text for the
		move.l	si_Buffer(a0),a0		;drive DF1:
		move.l	#"DF1:",(a0)+		;in the volume name
		clr.b	(a0)			;gadget

		move.l	a1,a0			;recover copy

		move.l	(a1),a1		;next gadget (=dir name)

		move.l	gg_SpecialInfo(a1),a2	;now clear the
		clr.w	si_BufferPos(a2)		;directory name
		move.l	si_Buffer(a2),a2		;gadget
		clr.b	(a2)

;		move.l	(a1),a1		;next gadget (=file name)

;		move.l	gg_SpecialInfo(a1),a2	;now clear the
;		clr.w	si_BufferPos(a2)		;file name
;		move.l	si_Buffer(a2),a2		;gadget
;		clr.b	(a2)

		move.l	a0,a1			;these gadgets are
		move.l	dp_window1(a6),a0		;in a window, not a
		sub.l	a2,a2			;requester

		moveq	#14,d0			;now link them
		moveq	#3,d1			;back in

		CALLINT	AddGList

		lea	ND_VolName(pc),a0		;now refresh the
		move.l	dp_window1(a6),a1		;gadget
		sub.l	a2,a2
		moveq	#3,d0

		CALLINT	RefreshGList

		bra	ShowDir


* SetRAM(a6)
* a6 = ptr to main program variables

* Sets the "Volume" string gadget to "RAM:"
* and activates the SortDir() routine.


* d0-d1/a0-a2 corrupt


SetRAM		lea	ND_VolName(pc),a1		;unlink the string
		move.l	dp_window1(a6),a0		;gadgets prior to
		moveq	#3,d0			;alteration

		CALLINT	RemoveGList

		lea	ND_VolName(pc),a0		;gadget ptr
		move.l	a0,a1			;keep a copy

		move.l	gg_SpecialInfo(a0),a0	;Now pop in the
		move.w	#4,si_BufferPos(a0)	;text for the
		move.l	si_Buffer(a0),a0		;drive DF1:
		move.l	#"RAM:",(a0)+		;in the volume name
		clr.b	(a0)			;gadget

		move.l	a1,a0			;recover copy

		move.l	(a1),a1		;next gadget (=dir name)

		move.l	gg_SpecialInfo(a1),a2	;now clear the
		clr.w	si_BufferPos(a2)		;directory name
		move.l	si_Buffer(a2),a2		;gadget
		clr.b	(a2)

;		move.l	(a1),a1		;next gadget (=file name)

;		move.l	gg_SpecialInfo(a1),a2	;now clear the
;		clr.w	si_BufferPos(a2)		;file name
;		move.l	si_Buffer(a2),a2		;gadget
;		clr.b	(a2)

		move.l	a0,a1			;these gadgets are
		move.l	dp_window1(a6),a0		;in a window, not a
		sub.l	a2,a2			;requester

		moveq	#14,d0			;now link them
		moveq	#3,d1			;back in

		CALLINT	AddGList

		lea	ND_VolName(pc),a0		;now refresh the
		move.l	dp_window1(a6),a1		;gadget
		sub.l	a2,a2
		moveq	#3,d0

		CALLINT	RefreshGList

		bra	ShowDir


* SetHardDisc(a6)
* a6 = ptr to main program variables

* Sets the "Volume" string gadget to "DH:"
* and activates the SortDir() routine.


* d0-d1/a0-a2 corrupt


SetHardDisc	lea	ND_VolName(pc),a1		;unlink the string
		move.l	dp_window1(a6),a0		;gadgets prior to
		moveq	#3,d0			;alteration

		CALLINT	RemoveGList

		lea	ND_VolName(pc),a0		;gadget ptr
		move.l	a0,a1			;keep a copy

		move.l	gg_SpecialInfo(a0),a0	;Now pop in the
		move.w	#4,si_BufferPos(a0)	;text for the
		move.l	si_Buffer(a0),a0		;drive DF1:
		move.l	#"DH:",(a0)+		;in the volume name
		clr.b	(a0)			;gadget

		move.l	a1,a0			;recover copy

		move.l	(a1),a1		;next gadget (=dir name)

		move.l	gg_SpecialInfo(a1),a2	;now clear the
		clr.w	si_BufferPos(a2)		;directory name
		move.l	si_Buffer(a2),a2		;gadget
		clr.b	(a2)

;		move.l	(a1),a1		;next gadget (=file name)

;		move.l	gg_SpecialInfo(a1),a2	;now clear the
;		clr.w	si_BufferPos(a2)		;file name
;		move.l	si_Buffer(a2),a2		;gadget
;		clr.b	(a2)

		move.l	a0,a1			;these gadgets are
		move.l	dp_window1(a6),a0		;in a window, not a
		sub.l	a2,a2			;requester

		moveq	#14,d0			;now link them
		moveq	#3,d1			;back in

		CALLINT	AddGList

		lea	ND_VolName(pc),a0		;now refresh the
		move.l	dp_window1(a6),a1		;gadget
		sub.l	a2,a2
		moveq	#3,d0

		CALLINT	RefreshGList

		bra	ShowDir


* CmpStr(a0,a1) -> CCR
* a0=ptr to SOURCE string
* a1=ptr to DESTINATION string

* Uses 68000 CMP instruction convention, namely
* CMP source,destination

* Returns Z set if strings equal, else C set if
* dest<source

* Assumes normal ASCII character set, and ignores
* letter case.

* d0-d1 corrupt


CmpStr		move.b	(a0)+,d0		;get source char
		move.b	(a1)+,d1		;get dest char

		cmp.b	#"a",d0		;lower case letter?
		bcs.s	CPS_1		;no
		cmp.b	#"z",d0
		bhi.s	CPS_1
		and.b	#$DF,d0		;make upper case if so

CPS_1		cmp.b	#"a",d1		;lower case letter?
		bcs.s	CPS_2		;no
		cmp.b	#"z",d1
		bhi.s	CPS_2
		and.b	#$DF,d1		;make upper case if so

CPS_2		cmp.b	d0,d1		;chars equal?
		bne.s	CPS_3
		tst.b	d0		;EOS met?
		bne.s	CmpStr		;back if not

CPS_3		rts			;done!


* CopyString(a0,a1)
* a0 = ptr to string to copy
* a1 = ptr to where to copy it to
* copies ASCIIZ string

* a0/a1 corrupt


CopyString	move.b	(a0)+,(a1)+
		bne.s	CopyString

		rts


* Routines for text selection using the gadgets linked to the
* text listing window of the disc access panel.

* The following routines set D0 equal to the 'gadget number'
* for the given gadget (NOT equal to gg_GadgetID!) and then
* drops through to PickTextItem() below.


EntPick1		moveq	#0,d0
		bra.s	PickTextItem

EntPick2		moveq	#1,d0
		bra.s	PickTextItem

EntPick3		moveq	#2,d0
		bra.s	PickTextItem

EntPick4		moveq	#3,d0
		bra.s	PickTextItem

EntPick5		moveq	#4,d0
		bra.s	PickTextItem

EntPick6		moveq	#5,d0
		bra.s	PickTextItem

EntPick7		moveq	#6,d0
		bra.s	PickTextItem

EntPick8		moveq	#7,d0
		bra.s	PickTextItem

EntPick9		moveq	#8,d0


* PickTextItem(a6,d0)
* a6 = ptr to main program variables
* d0 = gadget number (from 0 to 8-supplied by
* the calling gadget)

* Note:because IText structs have different colours for
* file and dir text items, this is used to differentiate
* them. Far easier than re-scanning the lists.

* d0-d2/a0-a2 corrupt


PickTextItem	mulu	#20,d0		;20 = size of IText struct!
		add.l	#ND_T1,d0	;create pointer
		move.l	d0,a0

		move.b	(a0),d0		;get colour
		cmp.b	#1,d0		;white? (i.e., file)
		beq.s	PTI_1		;skip if so


* Here we simply assume that it's a directory. Get text ptr
* and link into the dir string gadget.


		move.l	12(a0),a0
		move.l	a0,-(sp)		;get ptr to string & save
		lea	BlankDT(pc),a1
		bsr	CmpStr		;blank string?
		beq.s	PTI_Nogo		;skip if so

		lea	ND_DirName(pc),a1
		move.l	dp_window1(a6),a0
		moveq	#1,d0

		CALLINT	RemoveGList

		lea	ND_DirName(pc),a1
		move.l	gg_SpecialInfo(a1),a1
		move.l	si_Buffer(a1),a1		;point to buffer

PTI_2		tst.b	(a1)+		;skip to EOS
		bne.s	PTI_2
		subq.l	#1,a1		;point to EOS proper

		move.l	(sp)+,a0

		move.b	#"/",(a1)+	;put in dir separator
		bsr	CopyString	;and extend path

		lea	ND_DirName(pc),a1
		move.l	dp_window1(a6),a0
		sub.l	a2,a2
		moveq	#15,d0	;position in list
		moveq	#1,d1

		CALLINT	AddGList

		lea	ND_DirName(pc),a0
		move.l	dp_window1(a6),a1
		sub.l	a2,a2
		moveq	#1,d0

		CALLINT	RefreshGList

		bra	ShowDir


* Here, we've clicked upon a blank string, so tidy the stack & kiss
* this routine goodbye.


PTI_Nogo		tst.l	(sp)+
		rts


* Here it's a file name. Pop it into the file name gadget
* but DON'T show the new directory. Keep the directory
* listing as is so that it can still be scrolled to find
* new choices. Signal that a valid filename exists.


PTI_1		move.l	12(a0),a0
		move.l	a0,-(sp)		;get ptr to string & save
		lea	BlankDT(pc),a1
		bsr	CmpStr		;blank string?
		beq.s	PTI_Nogo		;skip if so

		lea	ND_FileName(pc),a1
		move.l	dp_window1(a6),a0
		moveq	#1,d0

		CALLINT	RemoveGList

		lea	ND_FileName(pc),a1
		move.l	gg_SpecialInfo(a1),a1
		move.l	si_Buffer(a1),a1		;point to buffer

		move.l	(sp)+,a0

		bsr	CopyString	;and extend path

		lea	ND_FileName(pc),a1
		move.l	dp_window1(a6),a0
		sub.l	a2,a2
		moveq	#16,d0	;position in list
		moveq	#1,d1

		CALLINT	AddGList

		lea	ND_FileName(pc),a0
		move.l	dp_window1(a6),a1
		sub.l	a2,a2
		moveq	#1,d0

		CALLINT	RefreshGList


* No RTS here, so that routine can fall through to CheckFileName()
* below.



* CheckFileName(a6)
* a6 = ptr to main program variables

* Tests contents of file name gadget to see if a
* filename exists. Not a sophisticated check, but
* if should be enough. Also called by hitting RETURN
* within filename gadget.

* a0 corrupt


CheckFileName	bclr	#7,file_flag2(a6)		;invalid filename for now

		lea	ND_FileName(pc),a0	;ptr to gadget
		move.l	gg_SpecialInfo(a0),a0	;ptr to si_
		move.l	si_Buffer(a0),a0		;ptr to string

		tst.b	(a0)			;any text?
		beq.s	CFN_Done			;skip if so

		bset	#7,file_flag2(a6)		;signal valid filename

CFN_Done		rts


* CheckReName(a6)
* a6 = ptr to main program variables

* Tests contents of rename gadget to see if a
* filename exists. Not a sophisticated check, but
* if should be enough. Also called by hitting RETURN
* within rename gadget.

* a0 corrupt


CheckReName	bclr	#6,file_flag2(a6)		;invalid rename for now

		lea	ND_NewName(pc),a0		;ptr to gadget
		move.l	gg_SpecialInfo(a0),a0	;ptr to si_
		move.l	si_Buffer(a0),a0		;ptr to string

		tst.b	(a0)			;any text?
		beq.s	CRN_Done			;skip if so

		bset	#6,file_flag2(a6)		;signal valid rename

CRN_Done		rts


* SaveFile(a6)
* a6 = ptr to main program variables

* Saves crossword program file. Uses IFF Format!

* ASSUME ALL REGISTERS CORRUPT

* Note:Bug now removed. Previously, if clue list existed but
* text pointers were NULL, then the computation for the IFF
* chunk size was erroneous - added extra 2 bytes per NULL-
* pointer entry. However, when saving, this value was written
* yet the extra 2 bytes per entry weren't. So the FindChunk()
* routine was thrown off track. This has now been corrected
* by changing addq.l #2,d0 to addq.l #1,d0 for reserving a
* word-aligned NULL for a null text entry. Now the word-aligning
* code won't add on the extra 2 bytes.


SaveFile		moveq	#0,d0
		move.l	d0,file_size(a6)
		move.l	d0,file_buffer(a6)
		move.l	d0,file_acs(a6)
		move.l	d0,file_dns(a6)
		st	wantdir(a6)
		moveq	#0,d3


* Find size of proposed ACCL chunk. If it ends up zero, we
* don't write one.


		move.l	clue_list(a6),a0	;ptr to list header
		move.l	clh_AcList(a0),d0	;Across list exists?
		beq.s	Save_F1		;skip if not

		addq.l	#8,d3
		move.w	clh_AcCount(a0),d1	;no of entries
		move.l	d0,a0			;ptr to Across list
		moveq	#0,d0			;total byte count

Save_F2		move.l	cle_Text(a0),d2	;text ptr exists?
		beq.s	Save_F3_1	;skip if not

		move.l	d2,a1		;copy text ptr

Save_F5		tst.b	(a1)		;hit EOS?
		beq.s	Save_F3		;skip if so
		addq.l	#1,d0		;else +1 char count
		addq.l	#1,a1		;and point to next char
		bra.s	Save_F5

Save_F3_1	addq.l	#1,d0		;reserve space for NULLs

;		addq.l	#2,d0		;reserve space for NULLs

Save_F3		addq.l	#8,d0		;add on extra data size
		addq.l	#1,d0		;and EOS byte
		btst	#0,d0		;not aligned?
		beq.s	Save_F4		;skip if word aligned
		addq.l	#1,d0		;else word align

Save_F4		add.w	#cle_sizeof,a0	;next entry
		subq.w	#1,d1		;done them all?
		bne.s	Save_F2		;loop back if not

		move.l	d0,file_acs(a6)	;this is ACCL chunk size


Save_F1		move.l	clue_list(a6),a0	;ptr to list header
		move.l	clh_DnList(a0),d0	;Down list exists?
		beq.s	Save_F6		;skip if not

		addq.l	#8,d3
		move.w	clh_DnCount(a0),d1	;no of entries
		move.l	d0,a0			;ptr to Down list
		moveq	#0,d0			;total byte count

Save_F7		move.l	cle_Text(a0),d2	;text ptr exists?
		beq.s	Save_F8_1	;skip if not

		move.l	d2,a1		;copy text ptr

Save_F10		tst.b	(a1)		;hit EOS?
		beq.s	Save_F8		;skip if so
		addq.l	#1,d0		;else +1 char count
		addq.l	#1,a1		;and point to next char
		bra.s	Save_F10

Save_F8_1	addq.l	#1,d0		;reserve space for NULLs

;		addq.l	#2,d0		;reserve space for NULLs

Save_F8		addq.l	#8,d0		;add on extra data size
		addq.l	#1,d0		;and EOS byte
		btst	#0,d0		;not aligned?
		beq.s	Save_F9		;skip if word aligned
		addq.l	#1,d0		;else word align

Save_F9		add.w	#cle_sizeof,a0	;next entry
		subq.w	#1,d1		;done them all?
		bne.s	Save_F7		;loop back if not

		move.l	d0,file_dns(a6)	;this is DNCL chunk size


* Now compute entire file size.


Save_F6		add.l	file_acs(a6),d0	;total size of 2 chunks

		add.l	grid_bytes(a6),d0

		add.l	#50,d0
		add.l	d3,d0		;this is file size!

		move.l	d0,file_size(a6)	;save it


* Now try to allocate memory for IFF file


		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,file_buffer(a6)	;can we do it?
		bne.s	Save_F6a			;skip if so

		moveq	#-1,d0		;otherwise
		bra	Load_Error	;report the error

;		beq	Save_F11			;skip if not


* Now write the file out as an IFF file to the buffer.


Save_F6a		move.l	d0,a0		;ptr to buffer

		move.l	#"FORM",(a0)+	;write out FORM
		move.l	file_size(a6),d0
		subq.l	#8,d0
		move.l	d0,(a0)+		;form size
		move.l	#"CRWD",(a0)+	;form type = CRWD

		move.l	#"CWHD",(a0)+	;write CWHD chunk name

		moveq	#14,d0
		move.l	d0,(a0)+		;chunk size

		move.w	grid_across(a6),(a0)+
		move.w	grid_down(a6),(a0)+
		move.w	grid_firstx(a6),(a0)+
		move.w	grid_firsty(a6),(a0)+
		move.l	clue_list(a6),a1
		move.w	clh_AcCount(a1),(a0)+
		move.w	clh_DnCount(a1),(a0)+
		moveq	#0,d0
		btst	#6,applic_flag1(a6)	;check cw type

		sne	d0
		neg.b	d0
		move.w	d0,(a0)+

		move.l	file_acs(a6),d0		;got an ACCL chunk?
		beq.s	Save_F12			;skip if not

		move.l	#"ACCL",(a0)+		;create ACCL chunk
		move.l	d0,(a0)+			;save size

		move.l	clue_list(a6),a1
		move.w	clh_AcCount(a1),d1	;no. to do
		move.l	clh_AcList(a1),a1		;ptr to list

Save_F13		move.w	cle_Num(a1),(a0)+		;pop in clue num.
		move.w	cle_AcSq(a1),(a0)+	;across start square
		move.w	cle_DnSq(a1),(a0)+	;down start square
		move.b	cle_Solved(a1),d0
		ext.w	d0
		move.w	d0,(a0)+			;solved status

		move.l	cle_Text(a1),d2		;ptr to text
		bne.s	Save_F13_1		;skip if exists

		clr.w	(a0)+		;else pop in NULLs
		bra.s	Save_F15		;guaranteed aligned!

Save_F13_1	move.l	d2,a2		;ptr to text itself

Save_F14		move.b	(a2)+,(a0)+		;copy text across
		bne.s	Save_F14			;and back until EOS

		move.l	a0,d0			;check alignment
		btst	#0,d0			;odd address?
		beq.s	Save_F15			;skip if even
		clr.b	(a0)+			;else make it even
Save_F15		add.w	#cle_sizeof,a1		;point to next entry
		subq.w	#1,d1			;done them all?
		bne.s	Save_F13


Save_F12		move.l	file_dns(a6),d0		;got a DNCL chunk?
		beq.s	Save_F16			;skip if not

		move.l	#"DNCL",(a0)+		;create DNCL chunk
		move.l	d0,(a0)+			;save size

		move.l	clue_list(a6),a1
		move.w	clh_DnCount(a1),d1	;no. to do
		move.l	clh_DnList(a1),a1		;ptr to list

Save_F17		move.w	cle_Num(a1),(a0)+		;pop in clue num.
		move.w	cle_AcSq(a1),(a0)+	;across start square
		move.w	cle_DnSq(a1),(a0)+	;down start square
		move.b	cle_Solved(a1),d0
		ext.w	d0
		move.w	d0,(a0)+			;solved status

		move.l	cle_Text(a1),d2		;get text ptr
		bne.s	Save_F17_1		;skip if exists

		clr.w	(a0)+		;else pop in NULLs
		bra.s	Save_F19		;guaranteed aligned!

Save_F17_1	move.l	d2,a2		;ptr to text itself

Save_F18		move.b	(a2)+,(a0)+		;copy text across
		bne.s	Save_F18			;and back until EOS

		move.l	a0,d0			;check alignment
		btst	#0,d0			;odd address?
		beq.s	Save_F19			;skip if even
		clr.b	(a0)+			;else make it even
Save_F19		add.w	#cle_sizeof,a1		;point to next entry
		subq.w	#1,d1			;done them all?
		bne.s	Save_F17

Save_F16		move.l	#"GRID",(a0)+		;create GRID chunk

		move.l	grid_bytes(a6),d0
		move.l	d0,(a0)+			;& grid chunk size

		lsr.l	#1,d0
		move.l	grid_array(a6),a1

Save_F20		move.w	(a1)+,(a0)+		;copy grid across
		subq.l	#1,d0			;verbatim
		bne.s	Save_F20


* Now save the IFF file to disc.


		bsr	CheckFileName	;got a valid file name?
		tst.b	file_flag2(a6)
		bmi.s	Save_F20a	;skip if so

		moveq	#1,d0		;else report 'invalid
		bra	Load_Error	;file name' error

;		bpl.s	Save_F22		;skip if not

Save_F20a	lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)
		bsr	SetPath1

		move.l	dir_name(a6),a1

Save_F23		tst.b	(a1)+		;skip to end of
		bne.s	Save_F23		;path name

		lea	ND_FileName(pc),a0	;get file name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	Save_F23a	;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	Save_F23a	;skip if so
		move.b	#"/",(a1)+	;else put it in!

Save_F23a	bsr	CopyString	;append to path name

		move.l	dir_name(a6),d1
		move.l	#MODE_NEW,d2
		CALLDOS	Open		;try opening file

		move.l	d0,file_shand(a6)	;got it?
		bne.s	Save_F23b	;skip if so

		moveq	#6,d0		;else report "can't
		bra	Load_Error	;save file" error

;		beq.s	Save_F22			;skip if not

Save_F23b	move.l	d0,d1
		move.l	file_buffer(a6),d2	;write out the
		move.l	file_size(a6),d3		;file
		CALLDOS	Write

		move.l	file_shand(a6),d1		;and close it
		CALLDOS	Close


* Now deallocate the memory used by the file buffer.


;Save_F22	move.l	file_buffer(a6),d0	;got a buffer?
;		beq.s	Save_F22a		;skip if not
;		move.l	d0,a1
;		move.l	file_size(a6),d0		;get rid of it if so
;		CALLEXEC	FreeMem


* Now display the new disc directory.


Save_F22a	moveq	#0,d0
		bra	Load_Error


;		bra	ShowDir


* Come here if some operation failed.


Save_F11		rts


* LoadFile(a6)
* a6 = ptr to main program variables

* Loads crossword file. Kills off current crossword in
* grid, then reallocates all memory & begins setting up
* all of the data.

* ASSUME ALL REGISTERS CORRUPT


LoadFile		clr.l	file_buffer(a6)
		clr.b	wantdir(a6)	;don't want dir listing!

		bsr	CheckFileName	;got a valid file name?
		tst.b	file_flag2(a6)
		bmi.s	Load_X1		;skip if so

		moveq	#1,d0		;invalid filename
		bra	Load_Error	;signal error

;		bpl	Load_Error	;skip if not

Load_X1		lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)
		bsr	SetPath1

		move.l	dir_name(a6),a1

Load_F1		tst.b	(a1)+		;skip to end of
		bne.s	Load_F1		;path name

		lea	ND_FileName(pc),a0	;get file name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	Load_F1a		;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	Load_F1a		;skip if so
		move.b	#"/",(a1)+	;else put it in!

Load_F1a		bsr	CopyString	;append to path name

		move.l	dir_iblk(a6),d0	;got a file info block?
		bne.s	Load_F2		;skip if so

		move.l	#260,d0
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem

		move.l	d0,dir_iblk(a6)	;got one?
		bne.s	Load_F2

		moveq	#-1,d0		;no memory on tap
		bra	Load_Error

;		beq	Load_Error

Load_F2		move.l	dir_name(a6),d1
		move.l	#ACCESS_READ,d2
		CALLDOS	Lock		;got a file lock?
		move.l	d0,dir_lock(a6)
		bne.s	Load_X2

		moveq	#2,d0		;file nonexistent
		bra	Load_Error

;		beq	Load_Error	;no-file doesn't exist

Load_X2		move.l	d0,d1
		move.l	dir_iblk(a6),d2
		CALLDOS	Examine

		move.l	d0,-(sp)		;save error code
		move.l	dir_lock(a6),d1
		clr.l	dir_lock(a6)
		CALLDOS	UnLock		;surrender the lock

		tst.l	(sp)+		;able to examine?
		bne.s	Load_X3		;skip if so

		moveq	#2,d0		;nonexistent file error
		bra	Load_Error

;		beq	Load_Error	;no-error

Load_X3		move.l	dir_iblk(a6),a0	;get info block
		move.l	124(a0),d0	;get file size
		bne.s	Load_X4		;ok

		moveq	#3,d0		;empty file error
		bra	Load_Error

;		beq	Load_Error	;cock up-empty file!

Load_X4		move.l	d0,file_size(a6)

		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,file_buffer(a6)	;got file buffer?
		bne.s	Load_X5

		moveq	#-1,d0
		bra	Load_Error

;		beq	Load_Error		;no

Load_X5		move.l	dir_name(a6),d1	;try opening file
		move.l	#MODE_OLD,d2
		CALLDOS	Open
		move.l	d0,file_lhand(a6)	;got it?
		bne.s	Load_X6

		moveq	#5,d0		;can't open file
		bra	Load_Error

;		beq	Load_Error	;no

Load_X6		move.l	d0,d1
		move.l	file_buffer(a6),d2	;get file
		move.l	file_size(a6),d3		;contents
		CALLDOS	Read

		move.l	file_lhand(a6),d1		;and close file
		CALLDOS	Close


* Now scan the IFF file for the various chunks, and set up the
* new data.


		move.l	file_buffer(a6),a0
		move.l	#"FORM",d0
		cmp.l	(a0)+,d0		;IFF FORM?
		beq.s	Load_X12

		moveq	#4,d0
		bra	Load_Error	;not an IFF File

Load_X12		move.l	(a0)+,d0
		addq.l	#8,d0
		cmp.l	file_size(a6),d0
		beq.s	Load_X13

		moveq	#4,d0
		bra	Load_Error	;again not an IFF file

Load_X13		move.l	#"CRWD",d0
		cmp.l	(a0)+,d0
		beq.s	Load_X14

		moveq	#4,d0
		bra	Load_Error	;not our IFF file

Load_X14		move.l	#"CWHD",d0		;got a CWHD?
		move.l	file_buffer(a6),a0
		bsr	FindChunk
		move.l	d0,file_cwhd(a6)
		bne.s	Load_X7

		moveq	#7,d0		;missing vital chunk
		bra	Load_Error

;		beq	Load_Error		;exit if not

Load_X7		move.l	#"GRID",d0		;got a GRID?
		move.l	file_buffer(a6),a0
		bsr	FindChunk
		move.l	d0,file_grid(a6)
		bne.s	Load_X8

		moveq	#7,d0		;missing vital chunk
		bra	Load_Error
;		beq	Load_Error		;exit if not

Load_X8		move.l	#"ACCL",d0		;got an ACCL?
		move.l	file_buffer(a6),a0
		bsr	FindChunk		;no error if not!
		move.l	d0,file_accl(a6)

		move.l	#"DNCL",d0		;got a DNCL?
		move.l	file_buffer(a6),a0
		bsr	FindChunk
		move.l	d0,file_dncl(a6)


* Now destroy the old crossword. Also destroy old Undo Array
* (new for 1.2).


		move.l	grid_array(a6),a1
		move.l	grid_bytes(a6),d0
		CALLEXEC	FreeMem

		move.l	undo_array(a6),a1
		move.l	grid_bytes(a6),d0
		CALLEXEC	FreeMem

		bsr	FreeText

		bsr	DisposeClueList


* Now start creating the new crossword. First set up the base
* variables for the crossword.


		move.l	file_cwhd(a6),a0
		addq.l	#8,a0		;point to CWHD vars

		move.w	(a0)+,grid_across(a6)
		move.w	(a0)+,grid_down(a6)
		move.w	(a0)+,grid_firstx(a6)
		move.w	(a0)+,grid_firsty(a6)
		move.w	4(a0),d0
		and.b	#1,d0
		ror.b	#2,d0			;get type bit
		move.b	applic_flag1(a6),d1	;and current flags
		and.b	#$BF,d1
		or.b	d0,d1
		move.b	d1,applic_flag1(a6)	;set CW type

		move.l	file_grid(a6),a0
		addq.l	#4,a0		;point to grid size

		move.l	(a0)+,d0
		move.l	d0,grid_bytes(a6)

		move.l	a0,-(sp)
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1	;get new grid
		CALLEXEC	AllocMem
		move.l	(sp)+,a0

		move.l	d0,grid_array(a6)		;got it?
		bne.s	Load_X9			;continue if so

		moveq	#-1,d0		;no memory
		bra	Load_Error	;so report error


Load_X9		move.l	d0,a1		;a1 points to grid_array

		movem.l	a0-a1,-(sp)	;save pointers
		move.l	grid_bytes(a6),d0
		move.l	#MEMF_PUBLIC+MEMF_CHIP,d1	;get undo array
		CALLEXEC	AllocMem
		movem.l	(sp)+,a0-a1		;recover pointers
		move.l	d0,undo_array(a6)		;got it?
		bne.s	Load_X10			;continue if so

		moveq	#-1,d0		;no memory
		bra	Load_Error	;so report error

Load_X10		move.l	grid_bytes(a6),d0		;size of grid

Load_F3		move.b	(a0)+,(a1)+		;set up the grid
		subq.l	#1,d0			;chars array
		bne.s	Load_F3

		bsr	InitUndo		;initialise UNDO array

		bclr	#4,applic_flag1(a6) ;clear clue list exists flag

		move.l	file_accl(a6),d0	;ACCL chunk exists?
		beq.s	Load_F4		;no, so skip

		bset	#4,applic_flag1(a6) ;else set clue
					  ;list exists flag

		move.l	file_cwhd(a6),a1
		addq.l	#8,a1		;point to CWHD vars
		move.w	8(a1),d0
		mulu	#cle_sizeof,d0

		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	clue_list(a6),a0		;got memory for
		move.l	d0,clh_AcList(a0)		;clue list?
		beq.s	Load_F4			;skip if not

		move.l	file_cwhd(a6),a1
		addq.l	#8,a1		;point to CWHD vars
		move.w	8(a1),d0
		move.w	d0,clh_AcCount(a0)

		move.l	file_accl(a6),a1
		addq.l	#8,a1		;point to ACCL entries

		move.l	clh_AcList(a0),a0	;point to list space

Load_F5		move.w	(a1)+,cle_Num(a0)		;create clue list
		move.w	(a1)+,cle_AcSq(a0)	;entry
		move.w	(a1)+,cle_DnSq(a0)
		move.w	(a1)+,d1
		move.b	d1,cle_Solved(a0)
		clr.l	cle_Text(a0)

Load_F9		tst.b	(a1)+		;skip to end of text
		bne.s	Load_F9
		move.l	a1,d2
		btst	#0,d2
		beq.s	Load_F10

		addq.l	#1,a1

Load_F10		add.w	#cle_sizeof,a0
		subq.w	#1,d0
		bne.s	Load_F5


Load_F4		move.l	file_dncl(a6),d0	;DNCL chunk exists?
		beq.s	Load_F7		;no, so skip

		bset	#4,applic_flag1(a6) ;else set clue
					  ;list exists flag

		move.l	file_cwhd(a6),a1
		addq.l	#8,a1		;point to CWHD vars
		move.w	10(a1),d0
		mulu	#cle_sizeof,d0

		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	clue_list(a6),a0		;got memory for
		move.l	d0,clh_DnList(a0)		;clue list?
		beq.s	Load_F7			;skip if not

		move.l	file_cwhd(a6),a1
		addq.l	#8,a1		;point to CWHD vars
		move.w	10(a1),d0
		move.w	d0,clh_DnCount(a0)

		move.l	file_dncl(a6),a1
		addq.l	#8,a1
		move.l	clh_DnList(a0),a0	;point to list space

Load_F6		move.w	(a1)+,cle_Num(a0)		;create clue list
		move.w	(a1)+,cle_AcSq(a0)	;entry
		move.w	(a1)+,cle_DnSq(a0)
		move.w	(a1)+,d1
		move.b	d1,cle_Solved(a0)
		clr.l	cle_Text(a0)

Load_F11		tst.b	(a1)+		;skip to end of text
		bne.s	Load_F11
		move.l	a1,d2
		btst	#0,d2
		beq.s	Load_F12

		addq.l	#1,a1

Load_F12		add.w	#cle_sizeof,a0
		subq.w	#1,d0
		bne.s	Load_F6

Load_F7		bsr	AllocText	;create text space
		tst.w	d0		;got it?
		beq	Load_F8		;skip if not


* Now pop in the clue texts where they exist.


		move.l	clue_list(a6),a0
		move.l	clh_AcList(a0),d0	;got across clue list?
		beq.s	Load_F17		;oops..

		move.w	clh_AcCount(a0),d1	;no. to do
		move.l	d0,a2			;ptr to list
		move.l	file_accl(a6),a0		;get ACCL chunk
		addq.l	#8,a0			;point to entries
		move.l	clue_endptr(a6),a1

Load_F15		addq.l	#8,a0		;point to text
		tst.w	(a0)		;text exists?
		bne.s	Load_F15_1	;yes, so pop it in

		addq.l	#2,a0		;else skip
		bra.s	Load_F16		;and do next entry

Load_F15_1	move.l	a1,cle_Text(a2)	;pop in pointer
		bsr	CopyString

		move.l	a0,d0		;check if we're
		btst	#0,d0		;already aligned
		beq.s	Load_F16
		addq.l	#1,a0		;and word align if not

Load_F16		add.w	#cle_sizeof,a2	;next list entry
		subq.w	#1,d1		;done them all?
		bne.s	Load_F15		;back if so

		move.l	a1,clue_endptr(a6)

Load_F17		move.l	clue_list(a6),a0
		move.l	clh_DnList(a0),d0	;got across clue list?
		beq.s	Load_F8		;oops..

		move.w	clh_DnCount(a0),d1	;no. to do
		move.l	d0,a2			;ptr to list
		move.l	file_dncl(a6),a0		;get DNCL chunk
		addq.l	#8,a0			;point to entries
		move.l	clue_endptr(a6),a1

Load_F13		addq.l	#8,a0		;point to text
		tst.w	(a0)		;text exists?
		bne.s	Load_F13_1	;skip if so

		addq.l	#2,a0		;else skip
		bra.s	Load_F14		;and do next entry

Load_F13_1	move.l	a1,cle_Text(a2)	;pop in pointer
		bsr	CopyString

		move.l	a0,d0		;check if we're
		btst	#0,d0		;already aligned
		beq.s	Load_F14
		addq.l	#1,a0		;and word align if not

Load_F14		add.w	#cle_sizeof,a2	;next list entry
		subq.w	#1,d1		;done them all?
		bne.s	Load_F13		;back if so

		move.l	a1,clue_endptr(a6)


* Now begin re-displaying the grid.


Load_F8		move.w	#GRID_LEFT,d0	;set new mouse grid
		move.w	d0,grid_hl(a6)	;limits!
		move.w	#SQ_X,d1
		move.w	grid_across(a6),d2
		cmp.w	#MAX_DISPX,d2
		bls.s	Load_F8a
		move.w	#MAX_DISPX,d2	;constrain oversize grid
Load_F8a		mulu	d2,d1
		add.w	d1,d0
		subq.w	#1,d0
		move.w	d0,grid_hu(a6)

		move.w	#GRID_UP,d0
		move.w	d0,grid_vl(a6)
		move.w	#SQ_Y,d1
		move.w	grid_down(a6),d2
		cmp.w	#MAX_DISPY,d2
		bls.s	Load_F8b
		move.w	#MAX_DISPY,d2	;constrain oversize grid
Load_F8b		mulu	d2,d1
		add.w	d1,d0
		subq.w	#1,d0
		move.w	d0,grid_vu(a6)

		move.l	mw_handle(a6),a0		;turn on the "Fill
		move.w	#1+0*32+0*2048+$F800,d0	;Black" menu item
		CALLINT	OnMenu

		btst	#6,applic_flag1(a6)	;Type 2 grid?
		beq.s	Load_F8c			;skip if not

		move.l	mw_handle(a6),a0		;turn off the "Fill
		move.w	#1+0*32+0*2048+$F800,d0	;Black" menu item
		CALLINT	OffMenu

Load_F8c		move.l	mw_rastport(a6),a1	;tmp change
		moveq	#0,d0			;plotting pen
		CALLGRAF	SetAPen

		move.l	mw_rastport(a6),a1	;erase image
		move.w	#GRID_LEFT,d0		;from screen
		move.w	#GRID_UP,d1
		move.w	#GRID_LEFT+MAX_DISP_PX,d2
		move.w	#GRID_UP+MAX_DISP_PY,d3
		CALLGRAF	RectFill

		move.l	mw_rastport(a6),a1	;recover original
		moveq	#4,d0			;detail pen
		CALLGRAF	SetAPen

		move.l	grid_rp(a6),a1
		moveq	#1,d0
		CALLGRAF	SetRast		;get rid of old grid image

		bsr	SetMainHVPots	;set PropGadgets & TLC

		move.l	grid_array(a6),a0

		move.w	grid_down(a6),d6	;outer loop counter

		moveq	#1,d1		;vertical start square
		bra.s	Load_A1

Load_L1		move.w	grid_across(a6),d7	;inner loop counter

		moveq	#1,d0		;horizontal start square

		bra.s	Load_A2

Load_L2		move.w	(a0)+,d2			;get square data
		movem.l	d0-d1/d6-d7/a0,-(sp)	;save this lot
		bsr	SetSquare		;change grid image
		movem.l	(sp)+,d0-d1/d6-d7/a0	;recover this lot
		addq.w	#1,d0			;next horiz. square

Load_A2		dbra	d7,Load_L2		;do this many
		addq.w	#1,d1			;next vert. square

Load_A1		dbra	d6,Load_L1		;do this many

		bsr	DisplayGrid		;show results!

		bsr	InitUndo		;initialise Undo array

		moveq	#0,d0		;signal no error

Load_Error	move.w	d0,disc_error(a6)
		beq.s	Load_Done

		lea	IRT_1(pc),a0
		lea	_DiscErrs(pc),a1
		add.w	d0,d0
		add.w	d0,d0
		add.w	d0,d0
		add.w	d0,a1
		move.l	(a1)+,d0
		beq.s	Load_Done
		move.l	(a1)+,d1
		move.l	a0,irt_itext(a6)
		move.l	d0,irt_tlist(a6)
		move.w	d1,irt_count(a6)

		bsr	ShowDiscInfo


* Don't forget to free up any file transfer buffers used!


Load_Done	move.l	file_buffer(a6),d0	;got a buffer?
		beq.s	Load_Bye			;skip if not
		move.l	d0,a1
		move.l	file_size(a6),d0		;get rid of it if so
		CALLEXEC	FreeMem
		clr.l	file_buffer(a6)	;and make sure it's gone!

Load_Bye		tst.b	wantdir(a6)	;want a fresh dir listing?

		bne	ShowDir		;skip if so

		rts


		dc.l	NoMemOnTap,5	;-1, No memory

_DiscErrs	dc.l	0,0		;0, OK
		dc.l	NoNameBozo,4	;1, No filename in box
		dc.l	NoFileBozo,4	;2, File doesn't exist
		dc.l	FileEmpty,4	;3, Empty file
		dc.l	NotIFF,4		;4, Not IFF File
		dc.l	CantLoad,4	;5, Can't Load file
		dc.l	CantSave,4	;6, Can't Save File
		dc.l	NoChunkBozo,4	;7, Missing vital IFF Chunk
		dc.l	WProtect,6	;8, Disc Write Protected
		dc.l	CantRename,5	;9, Can't Rename
		dc.l	CantDelete,3	;10, Can't Delete
		dc.l	DirExists,6	;11, file/dir already exists
		dc.l	NonEmptyDir,5	;12, nonempty directory
		dc.l	NoPort,4		;13, no port for format
		dc.l	NoIOReq,4	;14, no IOReq for format
		dc.l	NoDev,4		;15, can't open trackdisk


* UserRename(a6)
* a6 = ptr to main program variables

* Prompts for a new name to choose in the Rename gadget,
* then renames file.

* Assume ALL registers corrupt


UserRename	st	wantdir(a6)

		bsr	CheckFileName	;got a valid file name?
		tst.b	file_flag2(a6)
		bmi.s	URN_1		;skip if so

		moveq	#1,d0		;invalid filename
		bra	Load_Error	;signal error

URN_1		bsr	CheckReName	;got a valid new name?
		btst	#6,file_flag2(a6)
		bne.s	URN_2		;skip if so

		lea	IRT_1(pc),a0
		lea	IR_Rename(pc),a1
		moveq	#5,d0

		move.l	a0,irt_itext(a6)	;else pop up InfoReq
		move.l	a1,irt_tlist(a6)	;telling user to provide
		move.w	d0,irt_count(a6)	;a new name

		bsr	ShowDiscInfo

		bra.s	URN_1

URN_2		lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)
		bsr	SetPath1

		move.l	dir_name(a6),a1

URN_3		tst.b	(a1)+		;skip to end of
		bne.s	URN_3		;path name

		lea	ND_FileName(pc),a0	;get file name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	URN_4		;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	URN_4		;skip if so
		move.b	#"/",(a1)+	;else put it in!

URN_4		bsr	CopyString	;append to path name

		move.l	a1,dir_rename(a6)
		bsr	SetPath2

		move.l	dir_rename(a6),a1

URN_5		tst.b	(a1)+		;skip to end of
		bne.s	URN_5		;path name

		lea	ND_NewName(pc),a0		;get new name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	URN_6		;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	URN_6		;skip if so
		move.b	#"/",(a1)+	;else put it in!

URN_6		bsr	CopyString	;append to path name

		move.l	dir_rename(a6),d1
		move.l	#ACCESS_READ,d2
		CALLDOS	Lock		;got a file lock?
		tst.l	d0		;if so, can't rename!
		beq.s	URN_7		;skip if not (rename OK)

		move.l	d0,d1		;else surrender lock
		CALLDOS	UnLock

		moveq	#9,d0		;signal error
		bra	Load_Error	;can't rename-file exists

URN_7		move.l	dir_name(a6),d1
		move.l	dir_rename(a6),d2

		CALLDOS	Rename		;and rename file!

		moveq	#0,d0
		bra	Load_Error

;		bra	ShowDir

		rts


* UserDelete(a6)
* a6 = ptr to main program variables

* Prompts if delete required, then executes delete
* if the delete is confirmed. Then resets the dir
* listing in the window & redisplays.

* Assume ALL registers corrupt


UserDelete	st	wantdir(a6)

		bsr	CheckFileName	;got a valid file name?
		tst.b	file_flag2(a6)
		bmi.s	UDL_1		;skip if so

		moveq	#1,d0		;invalid filename
		bra	Load_Error	;signal error

UDL_1		lea	QR_Delete(pc),a0	;pop up the warning
		lea	QRT_1(pc),a1	;requester!
		moveq	#5,d0

		move.l	a0,irt_tlist(a6)
		move.l	a1,irt_itext(a6)
		move.w	d0,irt_count(a6)

;		bset	#6,applic_flag2(a6)	;force NO gadget

		bsr	DoDiscQuery		;pop up req

		btst	#6,applic_flag2(a6)	;YES gadget hit?
		bne.s	UDL_2			;skip if so

		rts				else do nothing

UDL_2		lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)
		bsr	SetPath1

		move.l	dir_name(a6),a1

UDL_3		tst.b	(a1)+		;skip to end of
		bne.s	UDL_3		;path name

		lea	ND_FileName(pc),a0	;get file name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	UDL_4		;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	UDL_4		;skip if so
		move.b	#"/",(a1)+	;else put it in!

UDL_4		bsr	CopyString	;append to path name

		move.l	dir_name(a6),d1	;check if file
		move.l	#ACCESS_READ,d2	;actually exists

		CALLDOS	Lock

		move.l	d0,d7		;file exists?
		bne.s	UDL_5		;skip if so

		moveq	#2,d0		;else report error
		bra	Load_Error

UDL_5		tst.l	dir_iblk(a6)	;got a FileInfoBlock?
		bne.s	UDL_5a		;use it if so

		move.l	#260,d0
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		CALLEXEC	AllocMem
		move.l	d0,dir_iblk(a6)	;else allocate one
		bne.s	UDL_5a		;and skip if got one

		moveq	#-1,d0		;no memory-ERROR
		bra	Load_Error

UDL_5a		move.l	d7,d1
		move.l	dir_iblk(a6),d2
		CALLDOS	Examine		;get file/dir info

		move.l	dir_iblk(a6),a0
		tst.l	4(a0)		;file or dir?
		bmi.s	UDL_5b		;skip if it's a file

		move.l	d7,d1
		move.l	a0,d2
		CALLDOS	ExNext		;see if dir empty
		beq.s	UDL_5b		;it is, so skip

		move.l	d7,d1		;surrender the lock
		CALLDOS	UnLock

		moveq	#12,d0		;non-empty directory-
		bra	Load_Error	;can't erase.

UDL_5b		move.l	d7,d1		;surrender the lock
		CALLDOS	UnLock

		move.l	dir_name(a6),d1

		CALLDOS	DeleteFile	;and delete file!

		moveq	#0,d0
		bra	Load_Error

;		bsr	ShowDir

		rts


* UserMakeDir(a6)
* a6 = ptr to main program variables

* Create new directory on disc, then re-create the
* dir listing & redisplay it.

* Assume ALL registers corrupt


UserMakeDir	st	wantdir(a6)

		bsr	CheckFileName	;got a valid file name?
		tst.b	file_flag2(a6)
		bmi.s	UMD_1		;skip if so

		moveq	#1,d0		;invalid filename
		bra	Load_Error	;signal error

UMD_1		lea	AcrossBuf(pc),a0
		move.l	a0,dir_name(a6)
		bsr	SetPath1

		move.l	dir_name(a6),a1

UMD_3		tst.b	(a1)+		;skip to end of
		bne.s	UMD_3		;path name

		lea	ND_FileName(pc),a0	;get file name
		move.l	gg_SpecialInfo(a0),a0	;from string
		move.l	si_Buffer(a0),a0		;gadget

		subq.l	#1,a1		;point to EOS
		cmp.b	#":",-1(a1)	;volume separator?
		beq.s	UMD_4		;skip if so
		cmp.b	#"/",-1(a1)	;directory separator?
		beq.s	UMD_4		;skip if so
		move.b	#"/",(a1)+	;else put it in!

UMD_4		bsr	CopyString	;append to path name

		move.l	dir_name(a6),d1	;check if file
		move.l	#ACCESS_READ,d2	;actually exists

		CALLDOS	Lock

		tst.l	d0		;file exists?
		beq.s	UMD_5		;skip if not

		move.l	d0,d1		;surrender the lock
		CALLDOS	UnLock		;if so

		moveq	#11,d0		;and report error
		bra	Load_Error

UMD_5		move.l	dir_name(a6),d1

		CALLDOS	CreateDir	;make new dir

		move.l	d0,d1		;and surrender the lock
		CALLDOS	UnLock		;without further ado!

		moveq	#0,d0
		bra	Load_Error

;		bsr	ShowDir

		rts


* CopyFileName(a6)
* a6 = ptr to main program variables

* copy filename to rename box for editing.

* d0-d1/a0-a2 corrupt


CopyFileName	lea	ND_FileName(pc),a1	;point to box gadgets
		move.l	a1,-(sp)			;save ptr to them

		move.l	dp_window1(a6),a0		;unlink gadgets
		moveq	#2,d0
		CALLINT	RemoveGList

		move.l	(sp),a1			;point to FNameGad
		move.l	gg_NextGadget(a1),a0	;point to RNameGad
		move.l	gg_SpecialInfo(a1),a1
		move.l	si_Buffer(a1),a1
		move.l	gg_SpecialInfo(a0),a0
		move.l	si_Buffer(a0),a0

CFN_1		move.b	(a1)+,(a0)+		;copy chars
		bne.s	CFN_1			;until EOS hit

		move.l	(sp),a1			;pointer
		move.l	dp_window1(a6),a0
		sub.l	a2,a2
		moveq	#16,d0			;16th starting at 0!
		moveq	#2,d1			;2 gadgets
		CALLINT	AddGList			;link back in

		move.l	(sp)+,a0
		move.l	dp_window1(a6),a1
		sub.l	a2,a2
		moveq	#2,d0
		CALLINT	RefreshGList		;refresh them

		rts


* UserFormat(a6)
* a6 = ptr to main program variables

* Allows user to format a disc.
* Prompts for confirmation before doing so.

* Assume ALL registers corrupt!


UserFormat	clr.b	wantdir(a6)

		lea	QR_Format(pc),a0	;pop up the warning
		lea	QRT_1(pc),a1	;requester!
		moveq	#5,d0

		move.l	a0,irt_tlist(a6)
		move.l	a1,irt_itext(a6)
		move.w	d0,irt_count(a6)

		bsr	DoDiscQuery		;pop up req

		btst	#6,applic_flag2(a6)	;YES gadget hit?
		bne.s	UFT_2			;skip if so

		rts				else do nothing

UFT_2		lea	IRT_1(pc),a0
		lea	HowToFormat(pc),a1	;pop up the
		moveq	#5,d0			;instructions!

		move.l	a0,irt_itext(a6)
		move.l	a1,irt_tlist(a6)
		move.w	d0,irt_count(a6)

		bsr	ShowDiscInfo

		bra	DoFormat


* FindChunk(a0,d0) -> d0
* a0 = ptr to IFF FORM
* d0 = 4-letter chunk name

* Returns ptr to chunk in D0 or zero if
* not found.

* d1-d2/a0-a1 corrupt


FindChunk	move.l	4(a0),d1		;get file size
		move.l	a0,a1
		add.l	d1,a1		;ptr to end of FORM

		lea	12(a0),a0	;point to 1st chunk

FChunk_1		move.l	a0,d2		;copy current ptr
		cmp.l	(a0)+,d0		;got chunk?
		beq.s	FChunk_2		;yes, so return

		add.l	(a0)+,a0		;else point to next chunk
;		addq.l	#4,a0
		cmp.l	a1,a0		;hit end of FORM?
		bcs.s	FChunk_1		;back if not

		moveq	#0,d2		;else not found

FChunk_2		move.l	d2,d0

		rts


* WhichDrives(a6)
* a6 = ptr to main program variables
* Scans DOS device lists to find out which
* drives are attached to the system.

* Will also condition the Gadget Enable flags for the
* requisite gadgets.

* d0-d1/d7/a0-a1/a3 corrupt


WhichDrives	moveq	#0,d0
		move.l	d0,drv0(a6)	;clear flags

		move.l	dos_base(a6),a3	;ptr to DOS library
		move.l	34(a3),a3	;pointer to RootNode

		move.l	24(a3),d1	;get BPTR to DosInfo
		lsl.l	#2,d1
		move.l	d1,a3		;get actual ptr

		move.l	4(a3),d1		;get BPTR to DevInfo
		lsl.l	#2,d1
		move.l	d1,a3		;get actual ptr

WDR_1		move.l	4(a3),d1		;get DOS node type
		bne.s	WDR_5		;not a device-skip
		move.l	40(a3),d7	;get BPTR to name
		lsl.l	#2,d7
		addq.l	#1,d7

		move.l	d7,a0		;actual ptr to string
		lea	_N_DRV1(pc),a1	;check for DF0:
		bsr	CmpStr		;this one?
		bne.s	WDR_2		;no

		tst.l	8(a3)		;task assigned to device node?
		beq.s	WDR_2		;no

		st	drv0(a6)		;else drive exists
		bra.s	WDR_5

WDR_2		move.l	d7,a0		;actual ptr to string
		lea	_N_DRV2(pc),a1	;check for DF1:
		bsr	CmpStr		;this one?
		bne.s	WDR_3		;no

		tst.l	8(a3)		;task assigned to device node?
		beq.s	WDR_3		;no

		st	drv1(a6)		;else drive exists
		bra.s	WDR_5

WDR_3		move.l	d7,a0		;actual ptr to string
		lea	_N_DRV3(pc),a1	;check for RAM:
		bsr	CmpStr		;this one?
		bne.s	WDR_4		;no

		tst.l	8(a3)		;task assigned to device node?
		beq.s	WDR_4		;no

		st	drv2(a6)		;else drive exists
		bra.s	WDR_5

WDR_4		move.l	d7,a0		;actual ptr to string
		lea	_N_DRV4(pc),a1	;check for DH:
		bsr	CmpStr		;this one?
		bne.s	WDR_5		;no

		tst.l	8(a3)		;task assigned to device node?
		beq.s	WDR_5		;no

		st	drv3(a6)		;else drive exists

WDR_5		move.l	(a3),d1		;get BPTR to next Device node
		beq.s	WDR_6		;no more-skip
		lsl.l	#2,d1		;else make true ptr
		move.l	d1,a3
		bra.s	WDR_1		;and back for more

* Having established which drives are available,
* disable the gadgets linked to nonexistent drives.

WDR_6		lea	ND_PickDF0(pc),a0
		move.w	gg_Flags(a0),d0
		tst.b	drv0(a6)		;DF0: available?
		bne.s	WDR_7		;yes
		or.w	#GADGDISABLED,d0	;else disable gadget
		move.w	d0,gg_Flags(a0)

WDR_7		lea	ND_PickDF1(pc),a0
		move.w	gg_Flags(a0),d0
		tst.b	drv1(a6)		;DF1: available?
		bne.s	WDR_8		;yes
		or.w	#GADGDISABLED,d0	;else disable gadget
		move.w	d0,gg_Flags(a0)

WDR_8		lea	ND_PickRAM(pc),a0
		move.w	gg_Flags(a0),d0
		tst.b	drv2(a6)		;RAM: available?
		bne.s	WDR_9		;yes
		or.w	#GADGDISABLED,d0	;else disable gadget
		move.w	d0,gg_Flags(a0)

WDR_9		lea	ND_PickDH(pc),a0
		move.w	gg_Flags(a0),d0
		tst.b	drv3(a6)		;DH: available?
		bne.s	WDR_7		;yes
		or.w	#GADGDISABLED,d0	;else disable gadget
		move.w	d0,gg_Flags(a0)

WDR_10		rts


_N_DRV1		dc.b	"DF0",0

_N_DRV2		dc.b	"DF1",0

_N_DRV3		dc.b	"RAM",0

_N_DRV4		dc.b	"DH",0

		even





