cc65/libsrc/common/putenv.s

189 lines
4.4 KiB
ArmAsm

;
; 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 return0
.import ptr1:zp, ptr2:zp, ptr3:zp, tmp1:zp
.include "errno.inc"
.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.
sty tmp1
lda #$00
sta (ptr1),y
; 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.
ldy tmp1
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