diff --git a/libsrc/common/Makefile b/libsrc/common/Makefile index d3ea1d5c2..151a0e339 100644 --- a/libsrc/common/Makefile +++ b/libsrc/common/Makefile @@ -79,6 +79,7 @@ C_OBJS = _afailed.o \ # From assembly source-files S_OBJS = _cwd.o \ + _environ.o \ _fdesc.o \ _file.o \ _fopen.o \ @@ -112,6 +113,7 @@ S_OBJS = _cwd.o \ fwrite.o \ getcpu.o \ getcwd.o \ + getenv.o \ isalnum.o \ isalpha.o \ isblank.o \ @@ -140,11 +142,13 @@ S_OBJS = _cwd.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 \ diff --git a/libsrc/common/_environ.s b/libsrc/common/_environ.s new file mode 100644 index 000000000..3df9cb7ef --- /dev/null +++ b/libsrc/common/_environ.s @@ -0,0 +1,30 @@ +; +; 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 + + diff --git a/libsrc/common/getenv.s b/libsrc/common/getenv.s new file mode 100644 index 000000000..349f5ce7d --- /dev/null +++ b/libsrc/common/getenv.s @@ -0,0 +1,46 @@ +; +; 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 + + diff --git a/libsrc/common/putenv.s b/libsrc/common/putenv.s new file mode 100644 index 000000000..aec6d1b34 --- /dev/null +++ b/libsrc/common/putenv.s @@ -0,0 +1,198 @@ +; +; 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 + diff --git a/libsrc/common/searchenv.s b/libsrc/common/searchenv.s new file mode 100644 index 000000000..585133386 --- /dev/null +++ b/libsrc/common/searchenv.s @@ -0,0 +1,84 @@ +; +; 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 + +