NEW
  AUTO 3,1
*/--------------------------------------
* # ExpandStr
* **In:**
*  Y,A = PTR to String to Expand (C-String)
* ## RETURN VALUE
*  X = hMem to Expanded String (C-String)
*  Y,A = PTR to Expanded String 
*\--------------------------------------
				.DUMMY
				.OR ZPDRV
ENV.SearchPath	.BS 2
ENV.BufLen		.BS 1
ENV.bNoExp		.BS 1
ENV.VarLen		.BS 1
ENV.VarName		.BS 16
				.ED
*--------------------------------------
K.ExpandStr		stz .88+1				Reset Intermediate string...

.1				>STYA ZPPtr2
				stz	ENV.BufLen			init Expanded String len=0

				stz .82+1				No var found yet

				stz ENV.bNoExp			Reset no expand flag
				
				ldy #0

.10				stz ENV.VarLen
				stz .23+1				reset In var flag

.11				lda (ZPPtr2),y			End of CSTR?
				beq .8

				iny

				cmp #'''
				bne .21

				lda ENV.bNoExp
				eor #$ff
				sta ENV.bNoExp			toggle flag
				bra	.11

.21				bit ENV.bNoExp
				bpl .23

.22				jsr ENV.AddAToBuf
				bra .11

.23				ldx #$ff				SELF MODIFIED already in a var?
				bne .3					yes...

				cmp #'$'				no, found one ?
				bne .22					no, store...

				sta .82+1				Toggle Expanded flag
				
				sta .23+1				Set In Var flag

				bra .11					skip this char

.3				cmp #'{'				we are in var, "{" after "$"?
				bne .31
				ldx ENV.VarLen			No char in var yet ?
				beq .11					normal, "${" syntax is ok,skip

				bne .5					not allowed char in varname, end of var
				
.31				cmp #'}'				end of var?
				beq .50

				jsr MEM.IsIDValid		_,.,a-z,A-Z,0-9 ?
				bcc .32					yes, add to varname
				
				ldx ENV.VarLen
				bne .5					varname has already chars...end of var
				
				inx						must be a $? or ?x.....go expand
				stx ENV.VarLen
				sta ENV.VarName
				bra .51					go Expand....
				
.32				ldx ENV.VarLen
				cpx #16
				beq .11					varname longer than 15....ignore
				sta ENV.VarName,x
				inx
				stx ENV.VarLen
				bra .11

.5				dey						last char was invalid...move back
				
.50				ldx ENV.VarLen
				beq .52					var name is empty...start over
				
.51				stz ENV.VarName,x
				phy						save current index
				jsr ENV.GetValue
				ply						restore index in string...
.52				jmp .10					reset start flag and continue
				
.8				ldx ENV.VarLen			end of STR,are we in a var?
				beq .80					no...exit...
				
				stz ENV.VarName,x
				jsr ENV.GetValue		yes, expand and add to STR
				
.80				lda .88+1				working from our temp string ?
				beq .81					no...
				
				jsr K.FreeMem			yes, discard....

.81				ldx ENV.BufLen
				stz K.Buf256,x
				
				>LDYAI K.Buf256
				ldx #SYS.StrDup
				jsr K.SYSCALL2.BANK
				bcs .9
				
				stx .88+1				save this as temp string, in case of recurse
.82				ldx #$ff				SELF MODIFIED Did we expand something ?
				beq .88
				jmp .1					Yes, start over with hPStr

.88				ldx #$ff				SELF MODIFIED
* or exit with Y,A from STRDUP
				
.9				rts					
*/--------------------------------------
* # FileSearch
* Search a file in the provided PATH list
* And return, if found, the full path to it.
* ## C
* `int filesearch ( char * filename, char * searchpath, char * fullpath, stat * filestat);`
* ## ASM
* **In:**
* `>PUSHWI filestat`
* `>PUSHWI fullpath`
* `>PUSHWI searchpath`
* `>LDYAI filename`
* ## RETURN VALUE
* CC : success
* DstBuf = FilePath
* DstStat = S.STAT
* CS : not found
*\--------------------------------------
K.FileSearch	pha
				>PULLW ENV.SearchPath
				>PULLW .2+1				DstBuf
				>PULLW .4+1				DstStat
				
				pla						Y,A = filename
				
				jsr ENV.Search.YA
				bcs K.FileSearch.RTS
				
				ldx #$ff
				
.1				inx
				lda K.Buf256,x
.2				sta $ffff,x				Self Modified
				bne .1
				
				ldx #S.STAT-1
				
.3				lda K.S.STAT,x				
.4				sta $ffff,x				Self Modified
				dex
				bpl .3
K.FileSearch.RTS
				rts
*--------------------------------------
ENV.Search.LIB	ldx #0
				.HS 2C					BIT ABS
ENV.Search.DRV	ldx #2
				.HS 2C					BIT ABS
ENV.Search.PATH	ldx #4

				>STYA ZPPtr2
				
				>LDYA ENV.VARS,x
				
				jsr K.GetEnv			get value for Search Path
				bcs K.FileSearch.RTS
				
				>STYA ENV.SearchPath

				>LDYA ZPPtr2
				
ENV.Search.YA	>STYA .4+1

				>LDYA ENV.SearchPath
				jsr K.ExpandStr			Y,A = Search Path, Expand it
				bcs .99

				stx .98+1
				>STYA .2+1				expanded search list ;
				
				stz .1+1
			
.1				ldy #$0					Self Modified Index in Search list string
				
				ldx #$0
				
.2				lda $ffff,y				Self Modified, Search list string
				beq .3					end of string, try it....
				iny
				cmp #':'
				beq .3
				sta K.Buf256,x
				inx
				bra .2
				
.3				txa
				beq .98						String is empty....nothing to try

				sty .1+1					save current index
				
				ldy #$0
				
.4				lda $ffff,y					Self Modified, Append Filename...
				sta K.Buf256,x
				beq .5
				iny
				inx
				bra .4
				
.5				>PUSHWI K.S.STAT
				>LDYAI K.Buf256
				ldx #SYS.stat
				jsr K.SYSCALL2.BANK
				bcs .1						Failed...retry next path...
				
				lda K.S.STAT+S.STAT.P.TYPE
				cmp #S.FI.T.DIR				Dir ?
				beq .1
				
				jsr .98						Discard Expanded hSrch list

				clc
.99				rts

.98				lda #$ff					SELF MODIFIED : Discard Expanded hSrch list
				jsr K.FreeMem
				lda #MLI.E.FNOTFND
				sec
				rts
*/--------------------------------------
* # PutEnv
* Change or add an environment variable, string is 'NAME=VALUE'
* ## C
* `int putenv(char *string);`
* ## ASM
* **In:**
* `>LDYA string`
* `>SYSCALL putenv`
* ## RETURN VALUE
*\--------------------------------------
K.PutEnv		>STYA ZPPtr1		NAME=VALUE

				ldy #0
				
.1				lda (ZPPtr1),y		copy STR to K.Buf256
				beq .9
				
				cmp #'='
				beq .2
				
				sta K.Buf256,y
				iny
				bne .1
				
.2				lda #0
				sta K.Buf256,y

				tya
				sec
				adc ZPPtr1
				sta ZPPtr2
				lda ZPPtr1+1
				adc #0
				sta ZPPtr2+1

				>LDYAI K.Buf256
				>STYA ZPPtr1
				bra K.SetEnv.I

.9				sec
				rts
*/--------------------------------------
* # SetEnv
* Change or add an environment variable
* ## C
* `int setenv(const char *name, const char *value);`
* ## ASM
* **In:**
* `>PUSHW value`
* `>LDYA name`
* `>SYSCALL setenv`
* ## RETURN VALUE
*\--------------------------------------
K.SetEnv		jsr MEM.SPtr1PPtr2
				
K.SetEnv.I		jsr K.UnsetEnv.I

.1				jsr ENV.InitEnvP3		ZPPtr3 -> Env

				lda #1
				sta ZPPtr4
				stz ZPPtr4+1			ZPPtr4 = ENVSIZE = 1
				
.10				lda (ZPPtr3)			End of ENV
				beq .15
				
				jsr ENV.GetP3LenY
				
				jsr ENV.NextEnvP3Y
				jsr ENV.NextEnvP4Y
				bra .10

.15				ldy #$ff
				
.16				iny
				lda (ZPPtr1),y
				bne .16
				
				jsr ENV.NextEnvP4Y		ZPPtr4 = ENVSIZE + VAR

				ldy #$ff

.19				iny
				lda (ZPPtr2),y
				bne .19
				
				jsr ENV.NextEnvP4Y		ZPPtr4 = ENVSIZE + VALUE
				
				lda ZPPtr4
				beq .20
				inc ZPPtr4+1
				
.20				ldy #S.PS.ENVPAGECNT
				lda (pPs),y
				cmp ZPPtr4+1
				bcs .22				env is large enough

				lda ZPPtr4+1
				jsr ENV.Dup.A
				bcs .9
				
				pha
				
				ldy #S.PS.hENV
				lda (pPs),y
				jsr K.Freemem
				
				pla
				ldy #S.PS.hENV
				sta (pPs),y
				txa
				dey					S.PS.ENVPAGECNT
				sta (pPs),y
				bra .1				Start over
				
.22				ldy #$ff
				
.23				iny
				lda (ZPPtr1),y
				sta (ZPPtr3),y
				bne .23
				
				jsr ENV.NextEnvP3Y
				
				ldy #$ff

.24				iny
				lda (ZPPtr2),y
				sta (ZPPtr3),y
				bne .24

				iny
				
				sta (ZPPtr3),y			don't forget array ending 0
				clc
.9				rts
*/--------------------------------------
* # GetEnv
* searches the environment list to find the environment variable name, 
* and returns a pointer to the corresponding value string.
* ## C
* `char *getenv(const char *name);`
* ## ASM
* **In:**
* `>LDYA name`
* `>SYSCALL getenv`
* ## RETURN VALUE
*  CC : Y,A = PTR to VALUE (C-String)
*  CS : not found
*\--------------------------------------
K.GetEnv		>STYA ZPPtr1
				jsr ENV.FindVarP1
				bcs .9
				
				jsr ENV.NextEnvP3		Skip NAME
				clc						just in case ADC in NextEnvPtr3 disturb CC
				
.9				>LDYA ZPPtr3
				rts
*/--------------------------------------
* # UnsetEnv
* Remove an environment variable
* ## C
* `int unsetenv(const char *name);`
* ## ASM
* **In:**
* `>LDYA name`
* `>SYSCALL unsetenv`
* ## RETURN VALUE
*\--------------------------------------
K.UnsetEnv		>STYA ZPPtr1			Store VAR Name
K.UnsetEnv.I	jsr ENV.FindVarP1
				bcs K.UnsetEnv.I.8		not found, quit

				jsr ENV.DelVarP3		Ptr3 -> ENVNAME
				
K.UnsetEnv.I.8	clc
K.UnsetEnv.I.9	rts
*--------------------------------------
*               PRIVATE
*--------------------------------------
ENV.GetValue	jsr ENV.ExpandSysVar
				bcc K.UnsetEnv.I.9

				>LDYAI ENV.VarName
				jsr K.GetEnv
				bcs K.UnsetEnv.I.9			
*--------------------------------------
ENV.AddYAToBuf	>STYA ZPPtr3			
*--------------------------------------
ENV.AddP3ToBuf	ldx ENV.BufLen
				ldy #$ff
				dex
				
.1				iny
				inx
				lda (ZPPtr3),y
				sta K.Buf256,x
				bne .1
				
				stx ENV.BufLen
				rts
*--------------------------------------
* ENV.ExpandSysVar
*  In:
*	 ENV.VarLen,ENV.VarName
*  Out:
*   CC: Found
*	 Append VALUE to K.Buf256
*	CS: Not Found
*--------------------------------------
ENV.ExpandSysVar
				ldx ENV.VarLen
				cpx #1					is name 1 char?
				bne .4

				lda ENV.VarName
				jsr MEM.IsDigit			$0...$9 ??
				bcs .1

				and #$0F

				jsr K.ArgV
				bcs K.UnsetEnv.I.8		Arg# is undefined, do not append anything
				
				jmp ENV.AddYAToBuf
				
.1				ldx #ENV.SysVars.Cnt-1

.2				cmp ENV.SysVars,x
				beq .3
				dex
				bpl .2
				
.9				sec
				rts
				
.3				txa
				asl
				tax
				jmp (ENV.SysVarsJmp,x)
				
.4				>LDYAI ENV.StrVars
				>STYA ZPPtr3
				
				ldx #0

.5				lda (ZPPtr3)
				beq .9
				
				cmp ENV.VarLen
				bne .7
				
				tay
				
.6				lda (ZPPtr3),y
				dey
				cmp ENV.VarName,y
				bne .7
				tya
				bne .6
				jmp (ENV.StrVarsJmp,x)
				
.7				inx
				inx
				
				lda (ZPPtr3)
				sec
				adc ZPPtr3
				sta ZPPtr3
				bcc .5
				inc ZPPtr3+1
				bra .5
*--------------------------------------
ENV.SysVars		.AS "*#?@$!"
ENV.SysVars.Cnt	.EQ *-ENV.SysVars
*--------------------------------------
ENV.SysVarsJmp	.DA ENV.SysVarsArgs
				.DA ENV.SysVarsArgC
				.DA ENV.SysVarsRC
				.DA ENV.SysVarsPPID
				.DA ENV.SysVarsPID
				.DA ENV.SysVarsCPID
*--------------------------------------
ENV.StrVars		>PSTR "LOGNAME"
				>PSTR "GECOS"
				>PSTR "HOME"
				>PSTR "SHELL"
				>PSTR "PWD"
				>PSTR "UID"
				>PSTR "GID"
				.DA #0
*--------------------------------------
ENV.StrVarsJmp	.DA ENV.StrVarsSession
				.DA ENV.StrVarsSession
				.DA ENV.StrVarsSession
				.DA ENV.StrVarsSession
				.DA ENV.StrVarsPWD
				.DA ENV.StrVarsUID
				.DA ENV.StrVarsGID
*--------------------------------------
ENV.StrVarsPWD	ldy #S.PS.hPREFIX
				lda (pPS),y
				jsr K.GetMemPtr
				jmp ENV.AddYAToBuf
*--------------------------------------
ENV.StrVarsUID	ldy #S.SESSION.UID
				.HS 2C
ENV.StrVarsGID	ldy #S.SESSION.GID
				lda (pSession),y
				bra ENV.SysVarsNum
ENV.StrVarsSession
				lda pSession
				clc
				adc #S.SESSION.NAME
				sta ZPPtr3
				lda pSession+1
				adc /S.SESSION.NAME
				sta ZPPtr3+1

.1				dex
				dex
				bmi .3
				
				ldy #$ff
				
.2				iny
				lda (ZPPtr3),y
				bne .2
				
				tya
				sec
				adc ZPPtr3
				sta ZPPtr3
				bcc .1
				inc ZPPtr3+1
				bra .1
				
.3				jmp ENV.AddP3ToBuf
*--------------------------------------
ENV.SysVarsArgC ldy #S.PS.ARGC
				.HS 2C
ENV.SysVarsRC	ldy #S.PS.RC
				.HS 2C
ENV.SysVarsPPID	ldy #S.PS.PPID
				.HS 2C
ENV.SysVarsPID	ldy #S.PS.PID
				.HS 2C
ENV.SysVarsCPID ldy #S.PS.CPID
				lda (pPS),y

ENV.SysVarsNum	stz .2+1
				stz .3+1
				
				ldx #8
				sed
				
.1				asl
				pha
.2				lda #$ff				Self Modified
				adc .2+1
				sta .2+1
				
.3				lda #$ff				Self Modified
				adc .3+1
				sta .3+1
				
				pla
				dex
				bne .1
				
				cld

				lda .3+1
				beq .4
				
				jsr ENV.AddAToBuf30
				
.4				lda .2+1
				pha
				lsr
				lsr
				lsr
				lsr
				beq .5
				
				jsr ENV.AddAToBuf30
				
.5				pla

				and #$0f
				
.8				jsr ENV.AddAToBuf30

				clc
				rts
*--------------------------------------
ENV.SysVarsArgs	lda #1
				jsr K.ArgV
				bcs .8
				
				>STYA ZPPtr3
				
.1				lda (ZPPtr3)
				beq .8

.2				jsr ENV.AddP3ToBuf
				
				jsr ENV.NextEnvP3
				lda (ZPPtr3)
				beq .8
				
				lda #' '
				jsr ENV.AddAToBuf
				
				bra .2
				
.8				clc
				rts
*--------------------------------------
* ENV.FindVarP1
*  In:
*	 ZPPtr1 -> NAME
*  Out:
*   CC: Found
*	 ZPPtr1 -> NAME
*	 ZPPtr3 -> ENV.NAME
*	CS: Not Found
*	 ZPPtr1 -> NAME
*	 ZPPtr3 -> PTR to Ending 0
*--------------------------------------
ENV.FindVarP1	jsr ENV.InitEnvP3		Store ENV

.1				lda (ZPPtr3)
				beq .9					end of ENV
				
				ldy #$ff

.2				iny
				lda (ZPPtr1),y
				cmp	(ZPPtr3),y
				bne .3

				ora #0
				bne .2
				
.8				clc
				rts

.3				jsr ENV.NextEnvP3x2		Skip NAME & VALUE
				bra .1

.9				sec
				rts	
*--------------------------------------
* ENV.DelVarP3
*  In:
*	ZPPtr3 -> ENV.NAME to Discard
*--------------------------------------
ENV.DelVarP3	>LDYA ZPPtr3			save actual Ptr
				>STYA ZPPtr4
				jsr ENV.NextEnvP3x2		Skip NAME & VALUE

.1				ldy #$ff

.2				iny
				lda (ZPPtr3),y			Move back CSTRs...
				sta (ZPPtr4),y
				bne .2
				
				tya
				beq .8					we moved back ending \0
				
				jsr ENV.NextEnvP3Y
				jsr ENV.NextEnvP4Y
				bra .1

.8				rts
*--------------------------------------
ENV.InitEnvP3	ldy #S.PS.hENV
				lda (pPs),y
				jsr K.GetMemPtr
				>STYA ZPPtr3			Store ENV
				rts
*--------------------------------------
ENV.NextEnvP3x2	jsr ENV.NextEnvP3
*--------------------------------------
ENV.NextEnvP3	jsr ENV.GetP3LenY
*--------------------------------------
ENV.NextEnvP3Y	tya
				sec
				adc ZPPtr3
				sta ZPPtr3
				bcc .8
				inc ZPPtr3+1
.8				rts
*--------------------------------------
ENV.GetP3LenY	ldy #$ff
				
.1				iny
				lda (ZPPtr3),y
				bne .1
				rts
*--------------------------------------			
ENV.NextEnvP4Y	tya
				sec
				adc ZPPtr4
				sta ZPPtr4
				bcc .8
				inc ZPPtr4+1
.8				rts
*--------------------------------------
ENV.AddAToBuf30	ora #$30

ENV.AddAToBuf	ldx ENV.BufLen
				sta K.Buf256,x
				inc ENV.BufLen
				rts
*--------------------------------------
* ENV.Dup
*  In:
*   A = ENV hMem To Duplicate
*  Out:
*   A = hMem to new ENV
*   X = Page Count
*--------------------------------------
ENV.Dup			ldy #S.PS.ENVPAGECNT
				lda (pPs),y
				
ENV.Dup.A		sta .8+1				Store target page Count	
				ldy #0
				
				jsr K.GetMem
				bcs .9
				
				>STYA .2+1				Target Buffer
				phx						save hMem
				
				jsr PS.SetMemOwner		Set Ownership
				
				ldy #S.PS.hENV
				lda (pPs),y
				jsr K.GetMemPtr
				>STYA .1+1
				
				ldy #S.PS.ENVPAGECNT	get SOURCE page count
				lda (pPs),y
				
				tax
				ldy #0
				
.1				lda $ffff,y				SELF MODIFIED
.2				sta $ffff,y				SELF MODIFIED
				iny
				bne .1
				inc .1+2
				inc .2+2
				dex
				bne .1

.8				ldx #$ff				SELF MODIFIED Target Page Count
				pla						hMem
				
				clc
.9				rts
*--------------------------------------
ENV.VARS		.DA .1
				.DA .2
				.DA .3
.1				.AZ "LIB"
.2				.AZ "DRV"
.3				.AZ "PATH"
*--------------------------------------
MAN
SAVE USR/SRC/SYS/KERNEL.S.ENV
LOAD USR/SRC/SYS/KERNEL.S
ASM
