; ; 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