diff --git a/racket/src/rktio/demo.c b/racket/src/rktio/demo.c index ae2653a31a..ca143f57ac 100644 --- a/racket/src/rktio/demo.c +++ b/racket/src/rktio/demo.c @@ -723,13 +723,13 @@ int main() rktio_status_t *status; rktio_process_result_t *result; char *argv[1] = { "/bin/cat" }; - rktio_envvars_t *envvars = NULL; + rktio_envvars_t *envvars = rktio_envvars(rktio); rktio_fd_t *err_fd = rktio_system_fd(rktio, 2, RKTIO_OPEN_WRITE); int i; - result = rktio_process(rktio, "/bin/cat", 1, argv, + result = rktio_process(rktio, argv[0], 1, argv, NULL, NULL, err_fd, - rktio_get_current_directory(rktio), envvars, + pwd, envvars, 0, NULL); check_valid(result); @@ -757,13 +757,11 @@ int main() rktio_process_forget(rktio, result->process); free(result); - check_valid(rktio_close(rktio, err_fd)); - - /* Run and then break or kill "/bin/cat" */ + /* Run and then break or kill `cat` */ for (i = 0; i < 2; i++) { - result = rktio_process(rktio, "/bin/cat", 1, argv, + result = rktio_process(rktio, argv[0], 1, argv, NULL, NULL, err_fd, - rktio_get_current_directory(rktio), envvars, + pwd, envvars, 0, NULL); check_valid(result); @@ -802,7 +800,49 @@ int main() rktio_process_forget(rktio, result->process); free(result); } + + { + char *argv[2] = { "/usr/bin/printenv", "RKTIO_EXAMPLE" }; + + check_valid(!rktio_envvars_get(rktio, envvars, "RKTIO_EXAMPLE")); + rktio_envvars_set(rktio, envvars, "RKTIO_EXAMPLE", "howdy"); + s = rktio_envvars_get(rktio, envvars, "RKTIO_EXAMPLE"); + check_valid(s); + check_valid(!strcmp(s, "howdy")); + free(s); + + result = rktio_process(rktio, argv[0], 2, argv, + NULL, NULL, err_fd, + pwd, envvars, + 0, + NULL); + check_valid(result); + + /* Assume that a pipe can buffer the minimal output from `printenv`: */ + pause_for_process(rktio, result->process); + wait_read(rktio, result->stdout_fd); + + { + char buffer[32]; + intptr_t amt; + amt = rktio_read(rktio, result->stdout_fd, buffer, sizeof(buffer)); + check_valid(amt == 6); + check_valid(!strncmp(buffer, "howdy\n", 6)); + } + + check_valid(rktio_close(rktio, result->stdin_fd)); + check_valid(rktio_close(rktio, result->stdout_fd)); + + rktio_process_forget(rktio, result->process); + free(result); + } + + rktio_ennvars_free(rktio, envvars); + + rktio_forget(rktio, err_fd); } + + free(pwd); return 0; } diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index eae5df2e4f..74138c0de5 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -145,6 +145,21 @@ int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd, typedef struct rktio_envvars_t rktio_envvars_t; +char *rktio_getenv(rktio_t *rktio, char *name); +int rktio_setenv(rktio_t *rktio, const char *name, const char *val); + +rktio_envvars_t *rktio_envvars(rktio_t *rktio); +rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio); +rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars); +void rktio_ennvars_free(rktio_t *rktio, rktio_envvars_t *envvars); + +char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, char *name); +void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, char *name, char *value); + +intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars); +char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); +char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); + /*************************************************/ /* Processes */ diff --git a/racket/src/rktio/rktio_envvars.c b/racket/src/rktio/rktio_envvars.c index f5999f7830..f3ec263e33 100644 --- a/racket/src/rktio/rktio_envvars.c +++ b/racket/src/rktio/rktio_envvars.c @@ -3,10 +3,360 @@ #include #include +struct rktio_envvars_t { + intptr_t count, size; + char **names; + char **vals; +}; + +#if defined(OS_X) && !TARGET_OS_IPHONE +# include +# define GET_ENVIRON_ARRAY *_NSGetEnviron() +#endif + +#if defined(RKTIO_SYSTEM_UNIX) && !defined(GET_ENVIRON_ARRAY) +extern char **environ; +# define GET_ENVIRON_ARRAY environ +#endif + +char *rktio_getenv(rktio_t *rktio, char *name) +{ +#ifdef RKTIO_SYSTEM_UNIX + char *s; + s = getenv(name); + if (s) + return strdup(s); + else + return NULL; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + intptr_t value_size; + value_size = GetEnvironmentVariableW(WIDE_PATH_temp(name), NULL, 0); + if (value_size) { + wchar_t *value_w; + char *value; + intptr_t got; + value_w = malloc(sizeof(wchar_t) * value_size); + got = GetEnvironmentVariableW(WIDE_PATH_temp(name), value_w, value_size); + if (got < value_size) + value_w[got] = 0; + value = NARROW_PATH_copy(value_w); + free(value_w); + return value; + } + return NULL; +#endif +} + +int rktio_setenv(rktio_t *rktio, const char *name, const char *val) +{ +#ifdef RKTIO_SYSTEM_UNIX + if (val) { + char *buffer; + intptr_t total_length, r, varlen, vallen; + + varlen = strlen(name); + vallen = strlen(val); + total_length = varlen + vallen + 2; + + buffer = malloc(total_length); + + memcpy(buffer, name, varlen); + buffer[varlen] = '='; + memcpy(buffer + varlen + 1, val, vallen + 1); + + r = putenv(buffer); + if (r) + get_posix_error(); + + free(buffer); + + return (r ? 0 : 1); + } else { + /* on some platforms, unsetenv() returns void */ + unsetenv(name); + return 1; + } +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + int rc; + char *val_w; + + if (val) + val_w = WIDE_PATH_copy(val); + else + val_w = NULL; + + rc = SetEnvironmentVariableW(WIDE_PATH_temp(var), val_w); + + if (val_w) + free(val_w); + + if (rc) + return 1; + + set_windows_error(); + return 0; +#endif +} + +rktio_envvars_t *rktio_envvars(rktio_t *rktio) +{ +#ifdef RKTIO_SYSTEM_WINDOWS + { + char *p; + wchar_t *e; + intptr_t i, start, j, count; + rktio_envvars_t *envvars; + + e = GetEnvironmentStringsW(); + if (!e) { + get_windows_error(); + return NULL; + } + + count = 0; + while (e[i]) { + count++; + for (i = 0; e[i]; ) { + } + i++; + } + + ennvars = malloc(sizeof(rktio_envvars_t)); + envvars->size = count; + envvars->count = count; + envvars->names = malloc(count * sizeof(char *)); + envvars->vals = malloc(count * sizeof(char *)); + + count = 0; + for (i = 0; e[i]; ) { + start = i; + while (e[i]) { i++; } + p = NARROW_PATH_copy(e + start); + for (j = 0; p[j] && p[j] != '='; j++) { + } + p[j] = 0; + envvars->names[count] = strdup(p); + envvars->vals[count] = strdup(p+j+1); + free(p); + i++; + } + + FreeEnvironmentStringsW(e); + + return envvars; + } +#else + { + intptr_t i, j; + char **ea, *p; + rktio_envvars_t *envvars; + + ea = GET_ENVIRON_ARRAY; + + for (i = 0; ea[i]; i++) { + } + + envvars = malloc(sizeof(rktio_envvars_t)); + envvars->size = i; + envvars->count = i; + envvars->names = malloc(i * sizeof(char *)); + envvars->vals = malloc(i * sizeof(char *)); + + for (i = 0; ea[i]; i++) { + p = ea[i]; + for (j = 0; p[j] && p[j] != '='; j++) { + } + envvars->names[i] = strndup(p, j); + envvars->vals[i] = strdup(p+j+1); + } + + return envvars; + } +#endif +} + +rktio_envvars_t *rktio_empty_envvars(rktio_t *rktio) +{ + rktio_envvars_t *envvars; + + envvars = malloc(sizeof(rktio_envvars_t)); + envvars->size = 2; + envvars->count = 0; + envvars->names = malloc(envvars->size * sizeof(char *)); + envvars->vals = malloc(envvars->size * sizeof(char *)); + + return envvars; +} + +rktio_envvars_t *rktio_envvars_copy(rktio_t *rktio, rktio_envvars_t *envvars) +{ + rktio_envvars_t *new_envvars; + intptr_t i; + + new_envvars = malloc(sizeof(rktio_envvars_t)); + new_envvars->size = envvars->count; + new_envvars->count = envvars->count; + new_envvars->names = malloc(envvars->count * sizeof(char *)); + new_envvars->vals = malloc(envvars->count * sizeof(char *)); + + for (i = 0; i < envvars->count; i++) { + new_envvars->names[i] = strdup(envvars->names[i]); + new_envvars->vals[i] = strdup(envvars->vals[i]); + } + + return new_envvars; +} + +void rktio_ennvars_free(rktio_t *rktio, rktio_envvars_t *envvars) +{ + free(envvars->names); + free(envvars->vals); + free(envvars); +} + +static void envvars_resize(rktio_envvars_t *envvars, intptr_t new_size) +{ + char **new_names; + char **new_vals; + + new_names = malloc(sizeof(char *) * new_size); + new_vals = malloc(sizeof(char *) * new_size); + + memcpy(new_names, envvars->names, sizeof(char*) * envvars->count); + memcpy(new_vals, envvars->vals, sizeof(char*) * envvars->count); + + free(envvars->names); + free(envvars->vals); + + envvars->names = new_names; + envvars->vals = new_vals; +} + +intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars) +{ + return envvars->count; +} + +char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i) +{ + return strdup(envvars->names[i]); +} + +char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i) +{ + return strdup(envvars->vals[i]); +} + +char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, char *name) +{ + intptr_t i; + + for (i = 0; i < envvars->count; i++) { + if (!strcmp(envvars->names[i], name)) + return strdup(envvars->vals[i]); + } + + return NULL; +} + +void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, char *name, char *value) +{ + intptr_t i, j; + + for (i = 0; i < envvars->count; i++) { + if (!strcmp(envvars->names[i], name)) { + if (value) { + free(envvars->vals[i]); + envvars->vals[i] = strdup(value); + } else { + free(envvars->names[i]); + free(envvars->vals[i]); + for (j = i + 1; j < envvars->count; j++) { + envvars->names[j-1] = envvars->names[j]; + envvars->vals[j-1] = envvars->vals[j]; + } + if ((envvars->size > 4) + && (envvars->count <= (envvars->size >> 2))) { + envvars_resize(envvars, envvars->size >> 1); + } + return; + } + } + } + + if (!value) + return; + + if (envvars->count == envvars->size) + envvars_resize(envvars, envvars->size * 2); + + envvars->names[envvars->count] = name; + envvars->vals[envvars->count] = value; + envvars->count++; +} + void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars) { - void *p; - p = malloc(sizeof(char *)); - *(char **)p = NULL; - return p; +#ifdef RKTIO_SYSTEM_UNIX + char **r, *s; + intptr_t i; + intptr_t len = 0, slen, c; + + for (i = 0; i < envvars->count; i++) { + len += strlen(envvars->names[i]); + len += strlen(envvars->vals[i]); + len += 2; + } + + r = (char **)malloc((envvars->count+1) * sizeof(char*) + len); + s = (char *)(r + (envvars->count+1)); + c = 0; + for (i = 0; i < envvars->count; i++) { + r[c++] = s; + slen = strlen(envvars->names[i]); + memcpy(s, envvars->names[i], slen); + s[slen] = '='; + s = s + (slen + 1); + slen = strlen(envvars->vals[i]); + memcpy(s, envvars->vals[i], slen); + s[slen] = 0; + s = s + (slen + 1); + } + r[c] = NULL; + + return r; +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + intptr_t i; + intptr_t len = 0, slen; + wchar_t *r, *s; + +for (i = 0; i < envvars->count; i++) { + len += wc_strlen(WIDE_PATH_temp(envvars->names[i])); + len += wc_strlen(WIDE_PATH_temp(envvars->vals[i])); + len += 2; + } + + r = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + + len = 0; + + for (i = 0; i < envvars->count; i++) { + s = WIDE_PATH_temp(envvars->names[i]); + slen = wc_strlen(s); + memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t)); + len += slen; + r[len++] = '='; + s = WIDE_PATH(envvars->vals[i]); + slen = wc_strlen(s); + memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t)); + len += slen; + r[len++] = 0; + } + r[len] = 0; + + return r; +#endif }