# From assembly source-files
S_OBJS = _cwd.o \
+ _environ.o \
_fdesc.o \
_file.o \
_fopen.o \
fwrite.o \
getcpu.o \
getcwd.o \
+ getenv.o \
isalnum.o \
isalpha.o \
isblank.o \
oserrcheck.o \
printf.o \
putchar.o \
+ putenv.o \
rand.o \
raise.o \
remove.o \
rename.o \
scanf.o \
+ searchenv.o \
setjmp.o \
signal.o \
sigtable.o \
--- /dev/null
+;
+; Ullrich von Bassewitz, 2005-04-21
+;
+; extern char** _environ;
+;
+;
+; __environ is a pointer to the environment.
+; __envcount is the number of entries in the environment.
+; __envsize is the size of the allocated array.
+;
+; The maximum number of environment entries is 64. putenv() will set errno
+; to ENOMEM when trying to increase the number beyond this limit.
+;
+
+ .export __environ, __envcount, __envsize
+ .import initenv
+ .constructor env_init
+
+ env_init := initenv
+
+.bss
+
+__environ:
+ .addr 0
+__envcount:
+ .byte 0
+__envsize:
+ .byte 0
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 2005-04-21
+;
+; char* __fastcall__ getenv (const char* name);
+;
+; Beware: putenv() knows about zero page usage in this module!
+;
+
+ .export _getenv
+ .import __environ, __envcount
+ .import searchenv
+ .import return0
+ .import ptr1:zp, ptr3:zp, tmp1:zp
+
+.code
+
+;----------------------------------------------------------------------------
+; getenv()
+
+.proc _getenv
+
+ sta ptr1
+ stx ptr1+1 ; Save name
+
+; Search for the string in the environment. searchenv will set the N flag if
+; the string is not found, otherwise X contains the index of the entry, ptr3
+; contains the entry and Y the offset of the '=' in the string.
+
+ jsr searchenv
+ bpl found
+ jmp return0 ; Not found, return NULL
+
+; Found the entry. Calculate the pointer to the right side of the environment
+; variable. Because we want to skip the '=', we will set the carry.
+
+found: ldx ptr3+1 ; High byte of result
+ tya
+ sec
+ adc ptr3
+ bcc @L9
+ inx
+@L9: rts
+
+.endproc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 2005-04-21
+;
+; int putenv (char* s);
+;
+; Note: The function will place s into the environment, *not* a copy!
+;
+
+ .export _putenv
+ .import _malloc, _free
+ .import searchenv, copyenvptr
+ .import __environ, __envcount, __envsize
+ .import seterrno, return0
+ .import ptr1:zp, ptr2:zp, ptr3:zp, tmp1:zp
+
+ .include "errno.inc"
+
+ .macpack cpu
+
+.code
+
+;----------------------------------------------------------------------------
+; putenv()
+
+.proc _putenv
+
+ sta ptr1
+ sta name
+ stx ptr1+1 ; Save name
+ stx name+1
+
+; Loop over the name to find the '='. If there is no '=', set errno to EINVAL
+; and return an error.
+
+ ldy #$FF
+@L0: iny
+ lda (ptr1),y
+ bne @L1
+ lda #EINVAL
+ jmp error ; End of string without '=' found
+@L1: cmp #'='
+ bne @L0
+
+; Remember the offset of the equal sign and replace it by a zero.
+
+.if (.cpu .bitand ::CPU_ISET_65SC02)
+ phy
+ stz (ptr1),y
+.else
+ sty tmp1
+ lda #$00
+ sta (ptr1),y
+.endif
+
+; Search for the string in the environment. searchenv will set the N flag if
+; the string is not found, otherwise X contains the index of the entry, ptr2
+; contains the entry and Y the offset of the '=' in the string. ptr3 will
+; point to the environment.
+
+ jsr searchenv
+
+; Before doing anything else, restore the old environment string.
+
+.if (.cpu .bitand ::CPU_ISET_65SC02)
+ ply
+.else
+ ldy tmp1
+.endif
+ lda #'='
+ sta (ptr1),y
+
+; Check the result of searchenv
+
+ txa ; Did we find the entry?
+ bpl addentry ; Jump if yes
+
+; We didn't find the entry, so we have to add a new one. Before doing so, we
+; must check if the size of the _environ array must be increased.
+; Note: There must be one additional slot for the final NULL entry.
+
+ ldx __envcount
+ inx
+ cpx __envsize
+ bcc addnewentry ; Jump if space enough
+
+; We need to increase the size of the environ array. Calculate the new size.
+; We will not support a size larger than 64 entries, double the size with
+; each overflow, and the starting size is 8 entries.
+
+ lda __envsize
+ bne @L2
+ lda #4 ; Start with 4*2 entries
+@L2: asl a ; Double current size
+ bmi nomem ; Bail out if > 64
+ sta newsize ; Remember the new size
+
+; Call malloc() and store the result in ptr2
+
+ asl a ; Make words
+ ldx #$00
+ jsr _malloc
+ sta ptr2
+ stx ptr2+1
+
+; Check the result of malloc
+
+ ora ptr2+1
+ beq nomem
+
+; Copy the old environment pointer to ptr3, and the new one to __environ.
+
+ ldx #1
+@L3: lda __environ,x
+ sta ptr3,x
+ lda ptr2,x
+ sta __environ,x
+ dex
+ bpl @L3
+
+; Use the new size.
+
+ lda newsize
+ sta __envsize
+
+; Copy the old environment data into the new space.
+
+ lda __envcount
+ asl a
+ tay
+ jmp @L5
+@L4: lda (ptr3),y
+ sta (ptr2),y
+@L5: dey
+ bpl @L4
+
+; Free the old environment space
+
+ lda ptr3
+ ldx ptr3+1
+ jsr _free
+
+; Since free() has destroyed ptr2, we need another copy ...
+
+ jsr copyenvptr ; Copy __environ to ptr2
+
+; Bump the environment count and remember it in X. Add the final NULL entry.
+
+addnewentry:
+ inc __envcount
+ ldx __envcount
+ txa
+ asl a
+ tay
+ lda #$00
+ sta (ptr2),y
+ iny
+ sta (ptr2),y
+
+; The index of the new entry is the old environment count.
+
+ dex
+ txa
+
+; Add the new entry to the slot with index in X. The pointer to the environment
+; is already in ptr2, either by a call to searchenv, or by above code.
+
+addentry:
+ asl a
+ tay
+ lda name
+ sta (ptr2),y
+ iny
+ lda name+1
+ sta (ptr2),y
+
+; Done
+
+ jmp return0
+
+; Error entries
+
+nomem: lda #ENOMEM
+error: jsr seterrno
+ lda #$FF ; Return -1
+ tax
+ rts
+
+.endproc
+
+
+;----------------------------------------------------------------------------
+; data
+
+.bss
+
+name: .addr 0 ; Pointer to name
+newsize: .byte 0 ; New environment size
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 2005-04-21
+;
+; Search the environment for a string.
+;
+
+ .export searchenv, copyenvptr
+ .import __environ, __envcount
+ .import ptr1:zp, ptr2:zp, ptr3:zp
+
+.code
+
+;----------------------------------------------------------------------------
+; searchenv:
+;
+; ptr1 must contain the string to search for. On exit, the N flag will tell
+; if the entry was found, and X will contain the index of the environment
+; string in the environment (a negative value if the entry was not found).
+; On success, ptr3 will contain the entry and Y the offset of the '=' within
+; the string.
+
+.proc searchenv
+
+; Copy the pointer to the environment to the zero page
+
+ jsr copyenvptr
+
+; Loop over all environment entries trying to find the requested one.
+
+ ldx __envcount
+@L0: dex
+ bmi @L9 ; Out of entries
+
+; Since the maximum number of entries is 64, the index can only be 63, so
+; the following shift cannot overflow and the carry is clear.
+
+ txa
+ asl a ; Mul by two for word access
+ tay
+ lda (ptr2),y
+ sta ptr3
+ iny
+ lda (ptr2),y
+ sta ptr3+1
+
+; ptr1 points to name, ptr3 points to the next environment entry. Compare the
+; two. The following loop limits the length of name to 255 bytes.
+
+ ldy #$00
+@L1: lda (ptr1),y
+ beq @L2 ; Jump on end of name
+ cmp (ptr3),y
+ bne @L0 ; Next environment entry
+ iny
+ bne @L1
+
+; End of name reached, check if the environment entry contains a '=' char
+
+@L2: lda (ptr3),y
+ cmp #'='
+ bne @L0 ; Next environment entry
+
+; Done. The function result is in X and the N flag is set correctly.
+
+@L9: rts
+
+.endproc
+
+
+;----------------------------------------------------------------------------
+; copyenvptr: Copy _environ to ptr2
+;
+
+.proc copyenvptr
+
+ lda __environ
+ sta ptr2
+ lda __environ+1
+ sta ptr2+1
+ rts
+
+.endproc
+
+