# 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
+
+