]> git.sur5r.net Git - cc65/commitdiff
Added environment routines
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 21 Apr 2005 21:26:15 +0000 (21:26 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 21 Apr 2005 21:26:15 +0000 (21:26 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3483 b7a2c559-68d2-44c3-8de9-860c34a00d81

libsrc/common/Makefile
libsrc/common/_environ.s [new file with mode: 0644]
libsrc/common/getenv.s [new file with mode: 0644]
libsrc/common/putenv.s [new file with mode: 0644]
libsrc/common/searchenv.s [new file with mode: 0644]

index d3ea1d5c2c56f9707fe4781b1c37d4c9dad05905..151a0e339a9a10d318d3d9d10af824134aa39d7f 100644 (file)
@@ -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 (file)
index 0000000..3df9cb7
--- /dev/null
@@ -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 (file)
index 0000000..349f5ce
--- /dev/null
@@ -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 (file)
index 0000000..aec6d1b
--- /dev/null
@@ -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 (file)
index 0000000..5851333
--- /dev/null
@@ -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
+
+