NEW
  AUTO 3,1
*--------------------------------------
XDOS.FindDirOrVol
				jsr XDOS.FindFileOrVol
				bcs .99
				
				lda d_stor
			
				and #$F0
				cmp #$D0
				beq moventry.CLCRTS

.9				lda #MLI.E.UNSUPST
				sec
.99				rts
*--------------------------------------
XDOS.FindFileOrVol
				jsr XDOS.CheckPath
				bcc moventry

				cmp #MLI.E.INVPATH
				bne fnderr
				clc
				rts
				
moventry 		ldy h_entln				Get FileInfo From Directory Block Buffer

.1  			dey
				lda (zpt),y				move entry into storage
				sta d_stor,y
				tya
				bne .1
moventry.CLCRTS
				clc
				rts
*--------------------------------------
XDOS.FindFile	jsr XDOS.CheckPath		see if file exists
				bcc moventry
				rts
*--------------------------------------
XDOS.CheckPath 	jsr XDOS.FindVol
				bcs fnderr.RTS

				bne lookfil0			branch if more than root

				lda /gbuf			 	otherwise, report a bad path error
				sta zpt+1			  	(but 1st create a phantom entry
				lda #$04			 	for open)
				sta zpt

				ldy #$1F				move in id and date info

.1  			lda (zpt),y
				sta d_stor,y
				dey
				cpy #$17
				bne .1

.2		  		lda rootstuf-$10,y
				sta d_stor,y
				dey
				cpy #$0F
				bne .2

				lda #$D0				fake directory file
				sta d_stor
				lda gbuf+2			 	check forward link.
				ora gbuf+3			 	if non-zero, assume full sized directory
				bne .3				 	else assume it's the slot 3 /RAM volume

				lda #$02			 	so reset eof and blocks_used fields
				sta d_eof+1
				lda #$01
				sta d_usage

.3  			lda #MLI.E.INVPATH		bad path (carry set)
				rts
*--------------------------------------
errdir 			lda #MLI.E.BADDIR	 	directory error
fnderr 			sec
fnderr.RTS		rts
*--------------------------------------
lookfil0		stz nofree				reset free entry indicator.

				sec		 				dir to be searched has header in this block.

L37C9  			stz totent			 	reset entry counter.

				jsr XDOS.LookupNameInDirBlk		look for name pointed to by pnptr.
				bcc namfound			if name was found.

				lda entcntl				have we looked at all of the
				sbc totent			 	entries in this directory?
				bcc L37E2			  	maybe, check hi count.
				bne L37EB			  	no, read next directory block.

				lda entcnth				has the last entry been looked at?
				beq errfnf			 	yes, give 'file not found' error

L37E2  			dec entcnth				should be at least one
L37EB  			sta entcntl				keep a running count.
				lda /gbuf			 	reset indirect pointer
				sta zpt+1

				lda gbuf+2			 	get link to next dir block
				bne L37FC			  	(if there is one).

				cmp gbuf+3			 	are both zero, i.e. no link? if so,
				beq errdir			 	then not all entries were acct'd for.

L37FC  			ldx gbuf+3			 	acc has value for block# (low).
				.DO LOWERCASE=1
				jsr XDOS.ReadGBufAXDir
				.ELSE
				jsr XDOS.ReadGBufAX		go read the next linked directory.
				.FIN
				bcc L37C9			  	if no error.
				rts		 				return error in acc.
*--------------------------------------
errfnf 			lda nofree				was any free entry found?
				bne fnf0
				lda gbuf+2			 	test link
				bne L3814
				cmp gbuf+3			 	if both are 0 then give up.
				beq fnf0			 	report 'not found'.

L3814  			sta d_entblk
				lda gbuf+3
				sta d_entblk+1			assume 1st entry of next block
				lda #$01			 	is free for use.
				sta d_entnum			mark as valid (for create)
				sta nofree

fnf0   			jsr nxtpnam1			'file not found' or 'path not found'?
errpath1 		beq .1					if non-zero then 'path not found'

				lda #MLI.E.PNOTFND		path not found
				.HS 2C					BIT ABS

.1   			lda #MLI.E.FNOTFND	 	file not found
				sec
lookfil0.RTS	rts
*--------------------------------------
namfound 		jsr nxtpname			adj index to next name in path.
				beq filfound			branch if that was the last name.

				ldy #$00			 	be sure this is a directory entry.
				lda (zpt),y				high nibble will tell.
				and #$F0
				cmp #$D0			 	is it a subdirectory?
				bne errpath1			error if not.

				ldy #$12			 	get address of 1st subdirectory block
				lda (zpt),y
				sta d_head+1		 	save as file's header block too
				tax
				
				dey
				lda (zpt),y
				sta d_head

				.DO LOWERCASE=1
				jsr XDOS.ReadGBufAXDir
				.ELSE
				jsr XDOS.ReadGBufAX		read subdirectory into gbuf.
				.FIN
				bcs lookfil0.RTS		if error.

				lda gbuf+37				get the # of files contained in this
				sta entcntl				directory.
				lda gbuf+38
				sta entcnth
*--------------------------------------
* Check if $75 at VOL/DIR entry + $14
* (8 bytes reserved)
*--------------------------------------
				.DO LOWERCASE=0
				lda gbuf+20				make sure password is disabled

				ldx #$00
				sec
				rol
L3869  			bcc L386C

				inx
L386C  			asl
				bne L3869

				cpx #$05				is password disabled?
				beq movhead

				lda #MLI.E.INCFF	 	directory is not compatible
				sec
				rts
				.FIN
*--------------------------------------
movhead  		jsr movhed0				move directory info.
				jmp lookfil0			do next local pathname.

movhed0			ldx #9					move this directory info

.1				lda gbuf+$1C,x
				sta h_credt,x
				dex
				bpl .1

				.DO ACL=1
				lda gbuf+$14
				cmp #$57
				bne .20

				ldx #7
				
.2				lda gbuf+$14,x
				sta h_acl,x
				dex
				bpl .2

.20				.FIN

				lda gbuf+4				if this is root, then nothing to do
				and #$F0
				eor #$F0			 	test header type.
				beq .8				  	branch if root

				ldx #$03			 	otherwise, save owner info about

.3  			lda gbuf+$27,x			this header.
				sta own_blk,x
				dex
				bpl .3

.8  			rts
*--------------------------------------
filfound 		lda h_maxent			figure out which entry # this is
				sec
				sbc cntent			 	max entries - count entries + 1
				adc #$00			 	= entry # (carry was set)
				sta d_entnum
				lda bloknml				and indicate block # of this directory
				sta d_entblk
				lda bloknml+1
				sta d_entblk+1
				clc
				rts
*--------------------------------------
XDOS.LookupNameInDirBlk
				lda h_maxent			reset count of files per block
				sta cntent

				lda /gbuf
				sta zpt+1
				lda #$04

L38C1  			sta zpt			  		reset indirect pointer to gbuf
				bcs L38F8				branch if this block contains a header

				ldy #$00
				lda (zpt),y				get length of name in directory.
				bne isname				branch if there is a name.

				lda nofree				test if a free entry has been declared.
				bne L38F8			  	yes, inc to next entry.

				jsr filfound			set address for current entry.

				inc nofree				indicate a free spot has been found.
				bra L38F8

isname 			and #$0F			 	strip byte (is checked by 'filfound')
				inc totent				inc count of valid files found.
				sta namcnt				save name length as counter.

				ldx namptr			 	get index to current path.
				cmp pathbuf,x			are both names the same length?
				bne L38F8			  	no, inc to next entry.

cmpname  		inx		 				(first) next letter index
				iny

				lda (zpt),y				compare names letter by letter	
				cmp pathbuf,x
				bne L38F8

				dec namcnt			 	all letters compared?
				bne cmpname				no, continue.

				clc		 				a match is found.
noname 			rts

L38F8  			dec cntent				checked all entries in this block?
				sec
				beq noname			 	yes, no name match.
				lda h_entln				add entry length to current pointer
				clc
				adc zpt
				bcc L38C1			  	branch if still in 1st page.

				inc zpt+1			  	look on 2nd page.
				clc		 				carry should always be clear before
				bra L38C1			  	looking at next.
*--------------------------------------
XDOS.FindVol	jsr XDOS.FindVolInVCBOrDev
				bcs novolume

				.DO ACL=1
				ldx #$4A
				.ELSE
				ldx #$42				zero out directory temps
				.FIN
				
.1  			stz own_blk,x			and owner info
				dex
				bpl .1

				lda devnum			 	setup device # for this directory
				sta d_dev
				jsr movhed0				setup other header info from directory

				ldy #$01			 	in gbuf and clean up misc info.
				ldx vcbptr
				inx

.2  			lda VCBs+VCB.TBLK,x		misc info includes
				sta h_tblk,y			total # of blocks,
				lda VCBs+VCB.BMAP,x		the address of the 1st bitmap,
				sta h_bmap,y
				lda	bloknml,y			directory's disk address,
				sta d_head,y
				lda h_fcnt,y			and setting up a counter for the # of
				sta entcntl,y			files in this directory.
				dex
				dey
				bpl .2
				
nxtpname 		jsr nxtpnam1			get new namptr in y and namlen in acc.
				sty namptr			 	save new pathname pointer.
				rts		 				(status reg according to accumulator)

nxtpnam1 		ldy namptr			 	inc pathname pointer to next name
				lda pathbuf,y			in the path.
				sec
				adc namptr			 	if this addition results in zero,
				tay		 				then prefixed directory has been moved
				bne L395F			  	to another device. branch if not.

				lda devnum			 	revise devnum for prefixed directory
				sta p_dev

L395F  			lda pathbuf,y			test for end of name.
				clc						no errors
novolume 		rts
*--------------------------------------
XDOS.FindVolInVCBOrDev
				lda #$00
				ldy preflag				use prefix volume name to look up vcb.
				bit prfxflg				is this a prefixed path?
				bpl L396F			 	branch if it is

				tay		 				set ptr to volume name

L396F  			sty vnptr			  	and save.
				sta devnum			 	zero out dev# until vcb located.

				lda #VCB0

L3975 			pha		 				acc now used as vcb lookup index.
				tax		 				index pointer to x.
				lda VCBs,x				get vcb volume name length.
				bne L3987			  	branch if claimed vcb to be tested.

L397C 			ldy vnptr			  	restore pointer to requested vol name.
				pla		 				now adj vcb index to next vcb entry.
				clc
				adc #VCB
				bcc L3975			  	branch if more vcb's to check

				bcs L39D4			  	otherwise go look for unlogged volumes.

L3987  			sta namcnt			 	save length of vol name to be compared.

L398A  			cmp pathbuf,y			is it the same as requested vol name?
				bne L397C			  	branch if not

				inx
				iny		 				next character
				lda VCBs,x
				dec namcnt			 	last character?
				bpl L398A			  	if not.

				plx		 				restore pointer to matching vcb.
				stx vcbptr			 	save it for future reference.
				lda VCBs+VCB.DEV,x		get it's device #
				sta devnum			 	and save it.
				
				lda #$02				assume prefix is not used and
				ldx #$00			 	that root directory is to be used.

				pha
				
				lda vnptr			  	= 0 if no prefix.

L39AC  			tay		 				if prefix then find ptr to prefixed
				sta namptr			 	dir name. save path ptr.
				beq L39C2			  	branch if no prefix.

				sec
				adc pathbuf,y			inc to next dir in prefix path.
				bcc L39AC			  	branch if another dir in prefix.

				pla
				lda p_blok			 	volume verification will occur at
				pha
				ldx p_blok+1			subdirectory level.

* verify volume name

L39C2  			pla

				jsr XDOS.ReadGBufAX		read in directory (or prefix dir)
				bcs L39CC			  	if error then look on other devices.

				.DO LOWERCASE=1
				jsr XDOS.CheckAndUnpackGBuf
				bcs L39CC
				.FIN

				jsr XDOS.CheckVolName	compare dir name with path name.
				bcc L39F0			  	if they match, stop looking.

L39CC  			ldx vcbptr			 	check if current (matched) vcb is active
				lda VCBs+VCB.OFCNT,x	i.e. does it have open files?
				bne L39ED			  	report not found if active.

L39D4  			lda vnptr			  	make path ptr same as volume ptr
				sta namptr
				jsr mvdevnums			copy all device #'s to be examined.
				lda devnum			 	log current device 1st before searching
				bne L39F1			  	others.

L39E2  			ldx DEVCNT				scan look list for devices we need

L39E5  			lda loklst,x			to search for the requested volume.
				bne L39F4			  	branch if we've a device to look at.

				dex
				bpl L39E5			  	look at next one.

L39ED  			lda #MLI.E.VNOTFND	 	no mounted volume
				sec						error
L39F0  			rts

L39F1  			ldx DEVCNT				now remove the device from the list

L39F4  			cmp loklst,x			of prospective devices.
				beq L39FE			  	branch if match.

				dex		 				look until found.
				bpl L39F4			  	always taken (usually) unless

				bmi L39ED			  	if dev was removed from devlst (/RAM).

L39FE  			sta devnum			 	preserve device to be checked next.
				stz loklst,x			mark this one as tested.

				jsr XDOS.FindVCBForDevNum	find vcb that claims this dev (if any).
				bcs L3A29			  	branch if vcb full.

				lda VCBs,x			 	did we find it or return free vcb?
				beq L3A16				if free vcb.

				lda VCBs+VCB.OFCNT,x	is this volume active?
				bne L39E2			  	if so, no need to re-log.

L3A16  			lda #$02			 	go read root dir into gbuf
				ldx #$00
				.DO LOWERCASE=1
				jsr XDOS.ReadGBufAXDir
				.ELSE
				jsr XDOS.ReadGBufAX
				.FIN
				bcs L39E2			  	ignore if unable to read.

				jsr XDOS.VCBMount
				bcs L39E2			  	look at next if non-xdos disk mounted.

				jsr XDOS.CheckVolName	is this the volume ?
				bcs L39E2			  	if not
L3A29  			rts
*--------------------------------------
mvdevnums 		ldx DEVCNT				copy all dev #'s to be checked.

L3A2D  			lda DEVLST,x		   	active device list.
				and #$F0			 	strip device type info.
				sta loklst,x			copy them to a temp workspace
				dex
				bpl L3A2D

				ldx DEVCNT
				rts
*--------------------------------------
XDOS.FindVCBForDevNum
				lda #VCB0				look for vcb for devnum
				ldy #$FF

.1  			tax						new index to next vcb
				lda VCBs+VCB.DEV,x		check all devnums
				cmp devnum				is this the vcb?
				beq .7

				lda VCBs,x				is this a free vcb?
				bne .3					if not

				iny
				bne .3					already found a free one

				stx vcbptr				save first free VCB
				
.3  			txa
				clc						inc index to next vcb
				adc #VCB
				bcc .1

				ldx vcbptr				get found free if any

				tya		 				any free vcb's available?
				bpl .8				  	yes, exit with X = vcbptr

				lda #VCB0			 	look for an entry to kick out

.4  			tax
				lda VCBs+VCB.OFCNT,x	any open files?
				beq .5				  	no, kick this one out.

				txa		 				next vcb
				clc
				adc #VCB
				bcc .4
				
				lda #MLI.E.VCBFULL		all vcb entries have open files
*				sec
				rts
				
.5  			stz VCBs,x				free this entry
				stz VCBs+VCB.DEV,x

.7				stx vcbptr			 	save entry index.
				
.8  			clc		 				no error.
				rts
*--------------------------------------
XDOS.CheckVolName
				ldx #$00			 	index to directory name.
				ldy namptr			 	index to pathname.

				lda gbuf+4			 	get dir name length and type.
				cmp #$E0				is it a directory?
				bcc L3A90			  	if not.

				and #$0F			 	isolate name length and
				sta namcnt			 	save as a counter.
				bne L3A95			  	branch if valid length.

L3A90  			sec		 				indicate not found
				rts

L3A92  			lda gbuf+4,x			next char
				
L3A95  			cmp pathbuf,y
				bne L3A90			  	if not the same.

				inx		 				check next char
				iny
				dec namcnt
				bpl L3A92			  	if more to compare.

				clc		 				match found
XDOS.CheckVolName.RTS
				rts
*--------------------------------------
XDOS.VCBMount	ldx vcbptr			 	previously logged in volume?
				lda VCBs,x				(acc = 0?)
				beq XDOS.VCBMountAtX  	no, go prepare vcb.

				jsr XDOS.VCBCmpGBUF	 	does vcb match vol read?
				bcc XDOS.CheckVolName.RTS			  	yes, do not disturb.

XDOS.VCBMountAtX
				ldy #VCB			 	zero out vcb entry

L3AB2  			stz VCBs,x
				inx
				dey
				bne L3AB2
	
				lda gbuf			 	pointer to previous dir block
				ora gbuf+1			 	must be null
				bne tsterr

				lda gbuf+4			 	test for header
				and #$E0
				cmp #$E0
				bne tsterr

				jsr tstdupvol			does a duplicate with open files
				bcs L3B04			 	already exist? branch if yes.

				lda gbuf+4			 	move volume name to vcb.
				and #$0F			 	strip root marker
				tay
				pha
*				clc
				adc vcbptr
				tax

L3ACE  			lda gbuf+4,y
				sta VCBs,x
				dex
				dey
				bne L3ACE

				pla		 				get length again
				sta VCBs,x				and save.

				lda devnum			 	last device used.
				sta VCBs+VCB.DEV,x		save device # and

				ldy #0
				
.1				lda gbuf+39,y
				sta VCBs+VCB.BMAP,x		copy BMAP+TBLK
				iny
				inx
				cpy #4
				bne .1

L3B04  			clc		 				indicate logged if possible
				rts
				
tsterr 			lda #MLI.E.NOTPRODOS	not tree or dir, unrecognized type
				sec
				rts				
*--------------------------------------
XDOS.VCBCmpGBUF	lda gbuf+4			 	with name in directory.
				and #$0F
				cmp VCBs,x				are they the same length?
				stx xvcbptr				(see rev note #23)
				bne .9				  	if not the same.

				tay
				clc
				adc xvcbptr
				tax

.1  			lda gbuf+4,y
				cmp VCBs,x
				bne .9				  	if not the same.

				dex
				dey
				bne .1

				clc		 				indicate match.
				.HS B0					BCS
.9				sec

				ldx xvcbptr				offset to start of vcb (rev note #23)
				rts
*--------------------------------------
tstdupvol 		lda #VCB0			 	check for other logged in volumes with the same name.

L3B2C  			tax
				jsr XDOS.VCBCmpGBUF
				bcs L3B41			  	if no match.

				lda VCBs+VCB.OFCNT,x	test for any open files.
				bne L3B4B			  	cannot look at this volume.

				stz VCBs,x			 	take duplicate offline if no open files
				stz VCBs+VCB.DEV,x
*				clc					  	ok to log in new volume.
				rts

L3B41  			txa		 				index to next vcb
*				sec
				adc #VCB-1
				bcc L3B2C			  	branch if more to check

				clc
				rts

L3B4B  			sta duplflag			duplicate has been found.
				stx vcbentry			save pointer to conflicting vcb.
				sec		 				error.
				rts
*--------------------------------------
tstfrblk 		ldx vcbptr			 	test if enough free blocks available for request.
				lda VCBs+VCB.FBLK+1,x			check if proper count for this volume.
				ora VCBs+VCB.FBLK,x
				bne L3BAD			  	branch if count is non-zero.

tkfrecnt 		jsr cntbms				get # of bitmaps
				sta bmcnt			  	and save.

				stz scrtch			 	start count at 0
				stz scrtch+1
				lda #$FF			 	mark 'first free' temp as unknown
				sta nofree

				jsr upbmap			 	update volume bitmap.
				bcs L3BC1			  	if error.

				ldx vcbptr			 	get address of 1st bitmap

				lda VCBs+VCB.BMAP,x
				sta bloknml
				lda VCBs+VCB.BMAP+1,x
				sta bloknml+1

L3B81  			jsr XDOS.ReadGBuf		use general buffer for temp space to
				bcs L3BC1			  	count free blocks (bits).

				jsr count
				dec bmcnt			  	was that the last bitmap?
				bmi L3B96			  	if so, go change fcb so not done again.

				inc bloknml
				bne L3B81

				inc bloknml+1
				bra L3B81

L3B96  			ldx vcbptr			 	mark which block had 1st free space
				lda nofree
				bmi L3BBE			 	if no free space was found.

				sta VCBs+VCB.BMAPIDX,x			update the free count.

				lda scrtch+1
				sta VCBs+VCB.FBLK+1,x			update volume control byte.
				lda scrtch
				sta VCBs+VCB.FBLK,x
				
L3BAD  			lda VCBs+VCB.FBLK,x			compare total available free blocks
				sec		 				on this volume.
				sbc reql
				lda VCBs+VCB.FBLK+1,x
				sbc reqh
				bcc L3BBE

				clc
				rts

L3BBE  			lda #MLI.E.VOLFULL
				sec
L3BC1  			rts

count			ldy #$00

L3BC4  			lda gbuf,y				bit pattern.
				beq L3BCC			  	don't count

				jsr cntfree

L3BCC  			lda gbuf+$100,y			do both pages with same loop
				beq L3BD4

				jsr cntfree
				
L3BD4  			iny
				bne L3BC4			  	loop until all 512 bytes counted.

				bit nofree			 	has 1st block w/free space been found?
				bpl L3BEE			  	if yes.

				lda scrtch			 	test to see if any blocks were counted
				ora scrtch+1
				beq L3BEE			  	branch if none counted.

				jsr cntbms			 	get total # of maps.
				sec		 				subtract countdown from total bitmaps
				sbc bmcnt
				sta nofree

L3BEE  			rts

cntfree			asl			  			count the # of bits in this byte
				bcc L3BFA

				inc scrtch
				bne L3BFA

				inc scrtch+1

L3BFA  			ora #$00
				bne cntfree				loop until all bits counted
				rts

cntbms			ldx vcbptr
				ldy VCBs+VCB.TBLK+1,x	return the # of bitmaps
				lda VCBs+VCB.TBLK,x		possible with the total count
				bne L3C0B			  	found in the vcb.

				dey						adj for bitmap block boundary

L3C0B  			tya

				lsr			  			divide by 16. the result is
				lsr			  			the # of bitmaps.
				lsr
				lsr
				rts
*--------------------------------------
MAN
SAVE usr/src/prodos.fx/prodos.s.xdos.b
LOAD usr/src/prodos.fx/prodos.s
ASM
