add `make-environment-variables'

Swap order of argument for `environment-variables-get'
and `environment-variables-set!', so that the environment
variables come first --- which follows the usual order.
This change means that the parameter isn't used to get
the default environment variables, but that seems ok; the
convenient interface is `getenv' and `putenv'.

On Windows, case-normalized environment variable names.

Also, change the implementation to use an immutable hash
internally.
This commit is contained in:
Matthew Flatt 2013-04-10 10:25:10 -06:00
parent cfe9f447c8
commit 6ea9a2b3e3
13 changed files with 861 additions and 775 deletions

View File

@ -203,7 +203,8 @@
(define (getenv s) (define (getenv s)
(unless (string-environment-variable-name? s) (unless (string-environment-variable-name? s)
(raise-argument-error 'getenv "string-environment-variable-name?" s)) (raise-argument-error 'getenv "string-environment-variable-name?" s))
(let ([v (environment-variables-get (string->bytes/locale s (char->integer #\?)))]) (let ([v (environment-variables-get (current-environment-variables)
(string->bytes/locale s (char->integer #\?)))])
(and v (and v
(bytes->string/locale v #\?)))) (bytes->string/locale v #\?))))
@ -213,9 +214,9 @@
(unless (string-no-nuls? t) (unless (string-no-nuls? t)
(raise-argument-error 'putenv "string-no-nuls?" 1 s t)) (raise-argument-error 'putenv "string-no-nuls?" 1 s t))
(and (and
(environment-variables-set! (string->bytes/locale s (char->integer #\?)) (environment-variables-set! (current-environment-variables)
(string->bytes/locale s (char->integer #\?))
(string->bytes/locale t (char->integer #\?)) (string->bytes/locale t (char->integer #\?))
(current-environment-variables)
(lambda () #f)) (lambda () #f))
#t)) #t))

View File

@ -9,6 +9,12 @@ from byte strings to bytes strings. A Racket process's initial
environment variables: accesses or changes to the set read or change environment variables: accesses or changes to the set read or change
operating-system environment variables for the Racket process. operating-system environment variables for the Racket process.
Since Windows environment variables are case-insensitive, and
@tech{environment variable set}'s key byte strings on Windows are
case-folded. More precisely, key byte strings are coerced to a UTF-8
encoding of characters that are converted to lowercase via
@racket[string-locale-downcase].
The current @tech{environment variable set}, which is determined by The current @tech{environment variable set}, which is determined by
the @racket[current-environment-variables] parameter, is propagated to the @racket[current-environment-variables] parameter, is propagated to
a @tech{subprocess} when the @tech{subprocess} is created. a @tech{subprocess} when the @tech{subprocess} is created.
@ -24,8 +30,7 @@ set}, @racket[#f] otherwise.}
A @tech{parameter} that determines the @tech{environment variable set} A @tech{parameter} that determines the @tech{environment variable set}
that is propagated to a @tech{subprocess} and that is used as the that is propagated to a @tech{subprocess} and that is used as the
default set for functions such as @racket[environment-variables-get] or default set for @racket[getenv] and @racket[putenv].}
@racket[getenv].}
@defproc[(bytes-environment-variable-name? [v any/c]) boolean?]{ @defproc[(bytes-environment-variable-name? [v any/c]) boolean?]{
@ -37,9 +42,17 @@ contain no bytes with the value @racket[0] or @racket[61], where
environment variable name also must have a non-zero length.} environment variable name also must have a non-zero length.}
@defproc[(environment-variables-get [name bytes-environment-variable-name?] @defproc[(make-environment-variables [name bytes-environment-variable-name?]
[env environment-variables? [val bytes-no-nuls?]
(current-environment-variables)]) ... ...)
environment-variables?]{
Creates a fresh @tech{environment variable set} that is initialized
with the given @racket[name] to @racket[val] mappings.}
@defproc[(environment-variables-get [env environment-variables?]
[name bytes-environment-variable-name?])
(or/c #f (and/c bytes-no-nuls? immutable?))]{ (or/c #f (and/c bytes-no-nuls? immutable?))]{
Returns the mapping for @racket[name] in @racket[env], returning Returns the mapping for @racket[name] in @racket[env], returning
@ -47,14 +60,12 @@ Returns the mapping for @racket[name] in @racket[env], returning
Normally, @racket[name] should be a byte-string encoding of a string Normally, @racket[name] should be a byte-string encoding of a string
using the default encoding of the current @tech{locale}. On Windows, using the default encoding of the current @tech{locale}. On Windows,
@racket[name] is coerced to a UTF-8 encoding if @racket[env] is the @racket[name] is coerced to a UTF-8 encoding and case-normalized.}
initial @tech{environment variable set} of the Racket process.}
@defproc[(environment-variables-set! [name bytes-environment-variable-name?] @defproc[(environment-variables-set! [env environment-variables?]
[name bytes-environment-variable-name?]
[maybe-bstr (or/c bytes-no-nuls? #f)] [maybe-bstr (or/c bytes-no-nuls? #f)]
[env environment-variables?
(current-environment-variables)]
[fail (-> any) [fail (-> any)
(lambda () (lambda ()
(raise (make-exn:fail ....)))]) (raise (make-exn:fail ....)))])
@ -68,8 +79,9 @@ for @racket[name] is removed.
Normally, @racket[name] and @racket[maybe-bstr] should be a Normally, @racket[name] and @racket[maybe-bstr] should be a
byte-string encoding of a string using the default encoding of the byte-string encoding of a string using the default encoding of the
current @tech{locale}. On Windows, @racket[name] and current @tech{locale}. On Windows, @racket[name] is
@racket[maybe-bstr] are coerced to a UTF-8 encoding if @racket[env] is coerced to a UTF-8 encoding and case-normalized, and
@racket[maybe-bstr] is coerced to a UTF-8 encoding if @racket[env] is
the initial @tech{environment variable set} of the Racket process. the initial @tech{environment variable set} of the Racket process.
On success, the result of @racket[environment-variables-set!] is On success, the result of @racket[environment-variables-set!] is

View File

@ -1261,6 +1261,8 @@
(test #t environment-variables? (current-environment-variables)) (test #t environment-variables? (current-environment-variables))
(test #f environment-variables? 10) (test #f environment-variables? 10)
(test #t environment-variables? (environment-variables-copy (current-environment-variables))) (test #t environment-variables? (environment-variables-copy (current-environment-variables)))
(test #t environment-variables? (make-environment-variables))
(test #t environment-variables? (make-environment-variables #"A" #"1"))
(test #t list? (environment-variables-keys (current-environment-variables))) (test #t list? (environment-variables-keys (current-environment-variables)))
(test #t andmap bytes? (environment-variables-keys (current-environment-variables))) (test #t andmap bytes? (environment-variables-keys (current-environment-variables)))
(test #t = (test #t =
@ -1274,6 +1276,11 @@
(test #f string-environment-variable-name? "x\0") (test #f string-environment-variable-name? "x\0")
(test (not (eq? 'windows (system-type))) string-environment-variable-name? "") (test (not (eq? 'windows (system-type))) string-environment-variable-name? "")
(test #"1" environment-variables-get (make-environment-variables #"a" #"1" #"b" #"two") #"a")
(test #"two" environment-variables-get (make-environment-variables #"a" #"1" #"b" #"two") #"b")
(test #f environment-variables-get (make-environment-variables #"a" #"1" #"b" #"two") #"c")
(test #f environment-variables-get (make-environment-variables) #"a")
(define (env-var-tests) (define (env-var-tests)
(define success-1? (putenv "APPLE" "AnApple")) (define success-1? (putenv "APPLE" "AnApple"))
(define success-2? (putenv "BANANA" "AnotherApple")) (define success-2? (putenv "BANANA" "AnotherApple"))
@ -1290,19 +1297,22 @@
(test "AnotherApple" getenv "BANANA") (test "AnotherApple" getenv "BANANA")
(test #f getenv "AnUndefinedEnvironmentVariable") (test #f getenv "AnUndefinedEnvironmentVariable")
(test #"AnApple" environment-variables-get #"APPLE") (define env (current-environment-variables))
(err/rt-test (environment-variables-get #"=AP=PLE=")) (test #"AnApple" environment-variables-get env #"APPLE")
(test (void) environment-variables-set! #"APPLE" #"=x=") (err/rt-test (environment-variables-get env #"=AP=PLE="))
(test #"=x=" environment-variables-get #"APPLE") (test (void) environment-variables-set! env #"APPLE" #"=x=")
(test #"AnotherApple" environment-variables-get #"BANANA") (test #"=x=" environment-variables-get env #"APPLE")
(test (void) environment-variables-set! #"BANANA" #f) (test #"AnotherApple" environment-variables-get env #"BANANA")
(test #f environment-variables-get #"BANANA") (test (void) environment-variables-set! env #"BANANA" #f)
(test #f environment-variables-get env #"BANANA")
(test #f getenv "BANANA") (test #f getenv "BANANA")
(test #"APPLE" car (member #"APPLE" (environment-variables-keys (let ([apple (if (eq? 'windows (system-type))
(current-environment-variables)))) #"apple"
(test #f member #"BANANA" (environment-variables-keys #"APPLE")])
(current-environment-variables)))) (test apple car (member apple (environment-variables-keys env))))
(test #f member #"BANANA" (environment-variables-keys env))
(test #f member #"banana" (environment-variables-keys env)))
(parameterize ([current-environment-variables (parameterize ([current-environment-variables
(environment-variables-copy (environment-variables-copy

View File

@ -470,7 +470,7 @@
[current-environment-variables [current-environment-variables
(environment-variables-copy (environment-variables-copy
(current-environment-variables))]) (current-environment-variables))])
(environment-variables-set! #"Hola" #"hi, there") (environment-variables-set! (current-environment-variables) #"Hola" #"hi, there")
(system* self "-e" "(getenv \"Hola\")")) (system* self "-e" "(getenv \"Hola\")"))
(test "\"hi, there\"\n" get-output-string out)) (test "\"hi, there\"\n" get-output-string out))

View File

@ -1,3 +1,6 @@
Version 5.3.4.3
Added make-environment-variables
Version 5.3.4.2 Version 5.3.4.2
Added current-environment-variables, environment-variables-get, Added current-environment-variables, environment-variables-get,
environment-variables-set!, environment-variables-keys, environment-variables-set!, environment-variables-keys,

View File

@ -104,7 +104,8 @@
["libpangocairo-1.0-0.dll" 94625] ["libpangocairo-1.0-0.dll" 94625]
["libpangowin32-1.0-0.dll" 143647] ["libpangowin32-1.0-0.dll" 143647]
["libpangoft2-1.0-0.dll" 679322]] ["libpangoft2-1.0-0.dll" 679322]]
(if (environment-variables-get #"PLT_WIN_GTK") (if (environment-variables-get (current-environment-variables)
#"PLT_WIN_GTK")
'(["libatk-1.0-0.dll" 153763] '(["libatk-1.0-0.dll" 153763]
["libgtk-win32-2.0-0.dll" 4740156] ["libgtk-win32-2.0-0.dll" 4740156]
["libgdk-win32-2.0-0.dll" 827670] ["libgdk-win32-2.0-0.dll" 827670]
@ -195,7 +196,8 @@
(define-values (path-size/show) (define-values (path-size/show)
(lambda (path) (lambda (path)
(let-values ([(sz) (path-size path)]) (let-values ([(sz) (path-size path)])
(if (environment-variables-get #"PLT_SHOW_PATH_SIZES") (if (environment-variables-get (current-environment-variables)
#"PLT_SHOW_PATH_SIZES")
(printf "~s ~s\n" path sz) (printf "~s ~s\n" path sz)
(void)) (void))
sz))) sz)))

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
#define USE_COMPILED_STARTUP 1 #define USE_COMPILED_STARTUP 1
#define EXPECTED_PRIM_COUNT 1092 #define EXPECTED_PRIM_COUNT 1093
#define EXPECTED_UNSAFE_COUNT 100 #define EXPECTED_UNSAFE_COUNT 100
#define EXPECTED_FLFXNUM_COUNT 69 #define EXPECTED_FLFXNUM_COUNT 69
#define EXPECTED_EXTFL_COUNT 45 #define EXPECTED_EXTFL_COUNT 45

View File

@ -4000,8 +4000,7 @@ void scheme_unused_intptr(intptr_t);
intptr_t scheme_check_overflow(intptr_t n, intptr_t m, intptr_t a); intptr_t scheme_check_overflow(intptr_t n, intptr_t m, intptr_t a);
Scheme_Object *scheme_make_environment_variables(Scheme_Hash_Table *ht); Scheme_Object *scheme_make_environment_variables(Scheme_Hash_Tree *ht);
# define SCHEME_ENVVARS_TABLE(ev) ((Scheme_Hash_Table *)SCHEME_PTR_VAL(ev))
void *scheme_environment_variables_to_block(Scheme_Object *env, int *_need_free); void *scheme_environment_variables_to_block(Scheme_Object *env, int *_need_free);
/*========================================================================*/ /*========================================================================*/

View File

@ -13,12 +13,12 @@
consistently.) consistently.)
*/ */
#define MZSCHEME_VERSION "5.3.4.2" #define MZSCHEME_VERSION "5.3.4.3"
#define MZSCHEME_VERSION_X 5 #define MZSCHEME_VERSION_X 5
#define MZSCHEME_VERSION_Y 3 #define MZSCHEME_VERSION_Y 3
#define MZSCHEME_VERSION_Z 4 #define MZSCHEME_VERSION_Z 4
#define MZSCHEME_VERSION_W 2 #define MZSCHEME_VERSION_W 3
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -261,7 +261,8 @@
"(if(and(relative-path? program)" "(if(and(relative-path? program)"
"(let-values(((base name dir?)(split-path program)))" "(let-values(((base name dir?)(split-path program)))"
"(eq? base 'relative)))" "(eq? base 'relative)))"
" (let ((paths-str (environment-variables-get #\"PATH\"))" "(let((paths-str(environment-variables-get(current-environment-variables)"
" #\"PATH\"))"
"(win-add(lambda(s)(if(eq?(system-type) 'windows) " "(win-add(lambda(s)(if(eq?(system-type) 'windows) "
" (cons (bytes->path #\".\") s) " " (cons (bytes->path #\".\") s) "
" s))))" " s))))"
@ -635,7 +636,8 @@
"(cons-if(lambda(f r)(if f(cons f r) r))))" "(cons-if(lambda(f r)(if f(cons f r) r))))"
"(path-list-string->path-list" "(path-list-string->path-list"
"(if user-too?" "(if user-too?"
" (let ((c (environment-variables-get #\"PLTCOLLECTS\")))" "(let((c(environment-variables-get(current-environment-variables)"
" #\"PLTCOLLECTS\")))"
"(if c" "(if c"
"(bytes->string/locale c #\\?)" "(bytes->string/locale c #\\?)"
" \"\"))" " \"\"))"

View File

@ -316,7 +316,8 @@
(if (and (relative-path? program) (if (and (relative-path? program)
(let-values ([(base name dir?) (split-path program)]) (let-values ([(base name dir?) (split-path program)])
(eq? base 'relative))) (eq? base 'relative)))
(let ([paths-str (environment-variables-get #"PATH")] (let ([paths-str (environment-variables-get (current-environment-variables)
#"PATH")]
[win-add (lambda (s) (if (eq? (system-type) 'windows) [win-add (lambda (s) (if (eq? (system-type) 'windows)
(cons (bytes->path #".") s) (cons (bytes->path #".") s)
s))]) s))])
@ -731,7 +732,8 @@
[cons-if (lambda (f r) (if f (cons f r) r))]) [cons-if (lambda (f r) (if f (cons f r) r))])
(path-list-string->path-list (path-list-string->path-list
(if user-too? (if user-too?
(let ([c (environment-variables-get #"PLTCOLLECTS")]) (let ([c (environment-variables-get (current-environment-variables)
#"PLTCOLLECTS")])
(if c (if c
(bytes->string/locale c #\?) (bytes->string/locale c #\?)
"")) ""))

View File

@ -306,6 +306,7 @@ static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[]);
static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[]); static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[]);
static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[]); static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[]);
static Scheme_Object *env_copy(int argc, Scheme_Object *argv[]); static Scheme_Object *env_copy(int argc, Scheme_Object *argv[]);
static Scheme_Object *env_make(int argc, Scheme_Object *argv[]);
static Scheme_Object *current_environment_variables(int argc, Scheme_Object *argv[]); static Scheme_Object *current_environment_variables(int argc, Scheme_Object *argv[]);
static Scheme_Object *system_type(int argc, Scheme_Object *argv[]); static Scheme_Object *system_type(int argc, Scheme_Object *argv[]);
static Scheme_Object *system_library_subpath(int argc, Scheme_Object *argv[]); static Scheme_Object *system_library_subpath(int argc, Scheme_Object *argv[]);
@ -870,13 +871,13 @@ scheme_init_string (Scheme_Env *env)
scheme_add_global_constant("environment-variables-get", scheme_add_global_constant("environment-variables-get",
scheme_make_immed_prim(sch_getenv, scheme_make_immed_prim(sch_getenv,
"environment-variables-get", "environment-variables-get",
1, 2), 2, 2),
env); env);
scheme_add_global_constant("environment-variables-set!", scheme_add_global_constant("environment-variables-set!",
scheme_make_prim_w_arity(sch_putenv, scheme_make_prim_w_arity(sch_putenv,
"environment-variables-set!", "environment-variables-set!",
2, 4), 3, 4),
env); env);
scheme_add_global_constant("environment-variables-keys", scheme_add_global_constant("environment-variables-keys",
@ -891,6 +892,12 @@ scheme_init_string (Scheme_Env *env)
1, 1), 1, 1),
env); env);
scheme_add_global_constant("make-environment-variables",
scheme_make_immed_prim(env_make,
"make-environment-variables",
0, -1),
env);
/* Don't make these folding, since they're platform-specific: */ /* Don't make these folding, since they're platform-specific: */
scheme_add_global_constant("system-type", scheme_add_global_constant("system-type",
@ -2093,7 +2100,9 @@ extern char **environ;
# define GET_ENVIRON_ARRAY environ # define GET_ENVIRON_ARRAY environ
#endif #endif
Scheme_Object *scheme_make_environment_variables(Scheme_Hash_Table *ht) #define SCHEME_ENVVARS_TABLE(ev) ((Scheme_Hash_Tree *)SCHEME_PTR_VAL(ev))
Scheme_Object *scheme_make_environment_variables(Scheme_Hash_Tree *ht)
{ {
Scheme_Object *ev; Scheme_Object *ev;
@ -2238,25 +2247,32 @@ int byte_string_ok_name(Scheme_Object *o)
return 1; return 1;
} }
static Scheme_Object *normalize_env_case(Scheme_Object *bs)
{
#ifdef DOS_FILE_SYSTEM
bs = scheme_byte_string_to_char_string(bs);
bs = string_locale_downcase(1, &bs);
bs = scheme_char_string_to_byte_string(bs);
#endif
return bs;
}
static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[]) static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[])
{ {
char *name; char *name;
char *value; char *value;
Scheme_Object *bs, *ev, *val; Scheme_Object *bs, *ev, *val;
Scheme_Hash_Table *ht; Scheme_Hash_Tree *ht;
bs = argv[0]; if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
scheme_wrong_contract("environment-variables-get", "environment-variables?", 0, argc, argv);
bs = argv[1];
if (!SCHEME_BYTE_STRINGP(bs) if (!SCHEME_BYTE_STRINGP(bs)
|| !byte_string_ok_name(bs)) || !byte_string_ok_name(bs))
scheme_wrong_contract("environment-variables-get", "bytes-environment-variable-name?", 0, argc, argv); scheme_wrong_contract("environment-variables-get", "bytes-environment-variable-name?", 1, argc, argv);
if ((argc > 1)
&& !SAME_TYPE(SCHEME_TYPE(argv[1]), scheme_environment_variables_type))
scheme_wrong_contract("environment-variables-get", "environment-variables?", 1, argc, argv);
if (argc > 1) ev = argv[0];
ev = argv[1];
else
ev = scheme_get_param(scheme_current_config(), MZCONFIG_CURRENT_ENV_VARS);
ht = SCHEME_ENVVARS_TABLE(ev); ht = SCHEME_ENVVARS_TABLE(ev);
if (!ht) { if (!ht) {
@ -2270,7 +2286,8 @@ static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[])
return value ? scheme_make_byte_string(value) : scheme_false; return value ? scheme_make_byte_string(value) : scheme_false;
} else { } else {
val = scheme_hash_get_atomic(ht, bs); bs = normalize_env_case(bs);
val = scheme_hash_tree_get(ht, bs);
return val ? val : scheme_false; return val ? val : scheme_false;
} }
} }
@ -2320,41 +2337,43 @@ static int sch_unix_putenv(const char *var, const char *val, const intptr_t varl
static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[]) static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[])
{ {
Scheme_Object *varbs, *valbs, *ev; Scheme_Object *varbs, *valbs, *ev;
Scheme_Hash_Table *ht; Scheme_Hash_Tree *ht;
char *var; char *var;
char *val; char *val;
int rc = 0, errid = 0; int rc = 0, errid = 0;
varbs = argv[0]; if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
scheme_wrong_contract("environment-variables-set!", "environment-variables?", 0, argc, argv);
varbs = argv[1];
if (!SCHEME_BYTE_STRINGP(varbs) if (!SCHEME_BYTE_STRINGP(varbs)
|| !byte_string_ok_name(varbs)) || !byte_string_ok_name(varbs))
scheme_wrong_contract("environment-variables-set!", "bytes-environment-variable-name?", 0, argc, argv); scheme_wrong_contract("environment-variables-set!", "bytes-environment-variable-name?", 1, argc, argv);
valbs = argv[1];
valbs = argv[2];
if (!SCHEME_FALSEP(valbs) if (!SCHEME_FALSEP(valbs)
&& (!SCHEME_BYTE_STRINGP(valbs) && (!SCHEME_BYTE_STRINGP(valbs)
|| scheme_byte_string_has_null(valbs))) || scheme_byte_string_has_null(valbs)))
scheme_wrong_contract("environment-variables-set!", "(or/c bytes-no-nuls? #f)", 1, argc, argv); scheme_wrong_contract("environment-variables-set!", "(or/c bytes-no-nuls? #f)", 2, argc, argv);
if ((argc > 2)
&& !SAME_TYPE(SCHEME_TYPE(argv[2]), scheme_environment_variables_type))
scheme_wrong_contract("environment-variables-set!", "environment-variables?", 1, argc, argv);
if (argc > 3) if (argc > 3)
scheme_check_proc_arity("environment-variables-set!", 0, 3, argc, argv); scheme_check_proc_arity("environment-variables-set!", 0, 3, argc, argv);
if (argc > 2) ev = argv[0];
ev = argv[2];
else
ev = scheme_get_param(scheme_current_config(), MZCONFIG_CURRENT_ENV_VARS);
ht = SCHEME_ENVVARS_TABLE(ev); ht = SCHEME_ENVVARS_TABLE(ev);
if (ht) { if (ht) {
varbs = normalize_env_case(varbs);
if (SCHEME_FALSEP(valbs)) { if (SCHEME_FALSEP(valbs)) {
scheme_hash_set_atomic(ht, varbs, NULL); ht = scheme_hash_tree_set(ht, varbs, NULL);
} else { } else {
varbs = byte_string_to_immutable(1, &varbs); varbs = byte_string_to_immutable(1, &varbs);
valbs = byte_string_to_immutable(1, &valbs); valbs = byte_string_to_immutable(1, &valbs);
scheme_hash_set_atomic(ht, varbs, valbs); ht = scheme_hash_tree_set(ht, varbs, valbs);
} }
SCHEME_PTR_VAL(ev) = (Scheme_Object *)ht;
return scheme_void; return scheme_void;
} else { } else {
var = SCHEME_BYTE_STR_VAL(varbs); var = SCHEME_BYTE_STR_VAL(varbs);
@ -2391,22 +2410,22 @@ static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[])
static Scheme_Object *env_copy(int argc, Scheme_Object *argv[]) static Scheme_Object *env_copy(int argc, Scheme_Object *argv[])
{ {
Scheme_Hash_Table *ht; Scheme_Hash_Tree *ht;
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type)) if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
scheme_wrong_contract("environment-variables-copy", "environment-variables?", 0, argc, argv); scheme_wrong_contract("environment-variables-copy", "environment-variables?", 0, argc, argv);
ht = SCHEME_ENVVARS_TABLE(argv[0]); ht = SCHEME_ENVVARS_TABLE(argv[0]);
if (ht) if (ht)
return scheme_make_environment_variables(scheme_clone_hash_table(ht)); return scheme_make_environment_variables(ht);
/* copy system environment variables into a hash table: */ /* copy system environment variables into a hash table: */
ht = scheme_make_hash_table_equal(); ht = scheme_make_hash_tree(1);
#ifdef DOS_FILE_SYSTEM #ifdef DOS_FILE_SYSTEM
{ {
char *p; char *p;
wchar_t *e; GC_CAN_IGNORE wchar_t *e;
int i, start, j; int i, start, j;
Scheme_Object *var, *val; Scheme_Object *var, *val;
@ -2414,16 +2433,15 @@ static Scheme_Object *env_copy(int argc, Scheme_Object *argv[])
for (i = 0; e[i]; ) { for (i = 0; e[i]; ) {
start = i; start = i;
while (e[i]) { while (e[i]) { i++; }
i++;
}
p = NARROW_PATH(e XFORM_OK_PLUS start); p = NARROW_PATH(e XFORM_OK_PLUS start);
for (j = 0; p[j] && p[j] != '='; j++) { for (j = 0; p[j] && p[j] != '='; j++) {
} }
if (p[j]) { if (j && p[j]) {
var = scheme_make_immutable_sized_byte_string(p, j, 1); var = scheme_make_immutable_sized_byte_string(p, j, 1);
val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1); val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1);
scheme_hash_set(ht, var, val); var = normalize_env_case(var);
ht = scheme_hash_tree_set(ht, var, val);
} }
i++; i++;
} }
@ -2445,7 +2463,7 @@ static Scheme_Object *env_copy(int argc, Scheme_Object *argv[])
if (p[j]) { if (p[j]) {
var = scheme_make_immutable_sized_byte_string(p, j, 1); var = scheme_make_immutable_sized_byte_string(p, j, 1);
val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1); val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1);
scheme_hash_set(ht, var, val); ht = scheme_hash_tree_set(ht, var, val);
} }
} }
} }
@ -2454,10 +2472,48 @@ static Scheme_Object *env_copy(int argc, Scheme_Object *argv[])
return scheme_make_environment_variables(ht); return scheme_make_environment_variables(ht);
} }
static Scheme_Object *env_make(int argc, Scheme_Object *argv[])
{
Scheme_Hash_Tree *ht;
Scheme_Object *varbs, *valbs;
int i;
ht = scheme_make_hash_tree(1);
for (i = 0; i < argc; i += 2) {
varbs = argv[i];
if (!SCHEME_BYTE_STRINGP(varbs)
|| !byte_string_ok_name(varbs))
scheme_wrong_contract("make-environment-variables", "bytes-environment-variable-name?", i, argc, argv);
if (i+1 >= argc) {
scheme_contract_error("make-environment-variables",
"key does not have a value (i.e., an odd number of arguments were provided)",
"key", 1, argv[i],
NULL);
return NULL;
}
valbs = argv[i+1];
if (!SCHEME_FALSEP(valbs)
&& (!SCHEME_BYTE_STRINGP(valbs)
|| scheme_byte_string_has_null(valbs)))
scheme_wrong_contract("make-environment-variables", "(or/c bytes-no-nuls? #f)", i+1, argc, argv);
varbs = normalize_env_case(varbs);
varbs = byte_string_to_immutable(1, &varbs);
valbs = byte_string_to_immutable(1, &valbs);
ht = scheme_hash_tree_set(ht, varbs, valbs);
}
return scheme_make_environment_variables(ht);
}
static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[]) static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[])
{ {
Scheme_Object *ev, *r = scheme_null; Scheme_Object *ev, *r = scheme_null, *key, *val;
Scheme_Hash_Table *ht; Scheme_Hash_Tree *ht;
int i; int i;
ev = argv[0]; ev = argv[0];
@ -2470,10 +2526,9 @@ static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[])
ht = SCHEME_ENVVARS_TABLE(ev); ht = SCHEME_ENVVARS_TABLE(ev);
} }
for (i = ht->size; i--; ) { for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
if (ht->vals[i]) { scheme_hash_tree_index(ht, i, &key, &val);
r = scheme_make_pair(ht->keys[i], r); r = scheme_make_pair(key, r);
}
} }
return r; return r;
@ -2490,7 +2545,8 @@ static int wc_strlen(const wchar_t *ws)
void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free) void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free)
{ {
Scheme_Hash_Table *ht; Scheme_Hash_Tree *ht;
Scheme_Object *key, *val;
ht = SCHEME_ENVVARS_TABLE(ev); ht = SCHEME_ENVVARS_TABLE(ev);
if (!ht) { if (!ht) {
@ -2510,32 +2566,30 @@ void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free)
int len = 0, slen; int len = 0, slen;
GC_CAN_IGNORE wchar_t *r, *s; GC_CAN_IGNORE wchar_t *r, *s;
for (i = ht->size; i--; ) { for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
if (ht->vals[i]) { scheme_hash_tree_index(ht, i, &key, &val);
len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(ht->keys[i]))); len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(key)));
len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(ht->vals[i]))); len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(val)));
len += 2; len += 2;
} }
}
r = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); r = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
len = 0; len = 0;
for (i = ht->size; i--; ) { for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
if (ht->vals[i]) { scheme_hash_tree_index(ht, i, &key, &val);
s = WIDE_PATH(SCHEME_BYTE_STR_VAL(ht->keys[i])); s = WIDE_PATH(SCHEME_BYTE_STR_VAL(key));
slen = wc_strlen(s); slen = wc_strlen(s);
memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t)); memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t));
len += slen; len += slen;
r[len++] = '='; r[len++] = '=';
s = WIDE_PATH(SCHEME_BYTE_STR_VAL(ht->vals[i])); s = WIDE_PATH(SCHEME_BYTE_STR_VAL(val));
slen = wc_strlen(s); slen = wc_strlen(s);
memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t)); memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t));
len += slen; len += slen;
r[len++] = 0; r[len++] = 0;
} }
}
r[len] = 0; r[len] = 0;
return r; return r;
@ -2545,29 +2599,29 @@ void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free)
GC_CAN_IGNORE char **r, *s; GC_CAN_IGNORE char **r, *s;
intptr_t i, len = 0, slen, c; intptr_t i, len = 0, slen, c;
for (i = ht->size; i--; ) { for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
if (ht->vals[i]) { scheme_hash_tree_index(ht, i, &key, &val);
len += SCHEME_BYTE_STRLEN_VAL(ht->keys[i]); len += SCHEME_BYTE_STRLEN_VAL(key);
len += SCHEME_BYTE_STRLEN_VAL(ht->vals[i]); len += SCHEME_BYTE_STRLEN_VAL(val);
len += 2; len += 2;
} }
}
r = (char **)malloc((ht->count+1) * sizeof(char*) + len); r = (char **)malloc((ht->count+1) * sizeof(char*) + len);
s = (char *)(r + (ht->count+1)); s = (char *)(r + (ht->count+1));
for (i = ht->size, c = 0; i--; ) { c = 0;
if (ht->vals[i]) { for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
scheme_hash_tree_index(ht, i, &key, &val);
r[c++] = s; r[c++] = s;
slen = SCHEME_BYTE_STRLEN_VAL(ht->keys[i]); slen = SCHEME_BYTE_STRLEN_VAL(key);
memcpy(s, SCHEME_BYTE_STR_VAL(ht->keys[i]), slen); memcpy(s, SCHEME_BYTE_STR_VAL(key), slen);
s[slen] = '='; s[slen] = '=';
s = s XFORM_OK_PLUS (slen + 1); s = s XFORM_OK_PLUS (slen + 1);
slen = SCHEME_BYTE_STRLEN_VAL(ht->vals[i]); slen = SCHEME_BYTE_STRLEN_VAL(val);
memcpy(s, SCHEME_BYTE_STR_VAL(ht->vals[i]), slen); memcpy(s, SCHEME_BYTE_STR_VAL(val), slen);
s[slen] = 0; s[slen] = 0;
s = s XFORM_OK_PLUS (slen + 1); s = s XFORM_OK_PLUS (slen + 1);
} }
} r[c] = NULL;
return r; return r;
} }