aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/win32/sys_env.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys/win32/sys_env.c')
-rw-r--r--erts/emulator/sys/win32/sys_env.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/erts/emulator/sys/win32/sys_env.c b/erts/emulator/sys/win32/sys_env.c
new file mode 100644
index 0000000000..ac4be3f316
--- /dev/null
+++ b/erts/emulator/sys/win32/sys_env.c
@@ -0,0 +1,261 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2002-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "erl_sys_driver.h"
+#include "erl_alloc.h"
+
+static char* merge_environment(char *current, char *add);
+static char* arg_to_env(char **arg);
+static char** env_to_arg(char *env);
+static char** find_arg(char **arg, char *str);
+static int compare(const void *a, const void *b);
+
+static erts_smp_rwmtx_t environ_rwmtx;
+
+void
+erts_sys_env_init(void)
+{
+ erts_smp_rwmtx_init(&environ_rwmtx, "environ");
+}
+
+int
+erts_sys_putenv(char *key_value, int sep_ix)
+{
+ int res;
+ char sep = key_value[sep_ix];
+ ASSERT(sep == '=');
+ key_value[sep_ix] = '\0';
+ erts_smp_rwmtx_rwlock(&environ_rwmtx);
+ res = (SetEnvironmentVariable((LPCTSTR) key_value,
+ (LPCTSTR) &key_value[sep_ix+1]) ? 0 : 1);
+ erts_smp_rwmtx_rwunlock(&environ_rwmtx);
+ key_value[sep_ix] = sep;
+ return res;
+}
+
+int
+erts_sys_getenv(char *key, char *value, size_t *size)
+{
+ size_t req_size = 0;
+ int res = 0;
+ DWORD new_size;
+
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ SetLastError(0);
+ new_size = GetEnvironmentVariable((LPCTSTR) key,
+ (LPTSTR) value,
+ (DWORD) *size);
+ res = !new_size && GetLastError() == ERROR_ENVVAR_NOT_FOUND ? -1 : 0;
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+ if (res < 0)
+ return res;
+ res = new_size > *size ? 1 : 0;
+ *size = new_size;
+ return res;
+}
+
+struct win32_getenv_state {
+ char *env;
+ char *next;
+};
+
+
+void init_getenv_state(GETENV_STATE *state)
+{
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ state->environment_strings = (char *) GetEnvironmentStrings();
+ state->next_string = state->environment_strings;
+}
+
+char *getenv_string(GETENV_STATE *state)
+{
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&environ_rwmtx));
+ if (state->next_string[0] == '\0')
+ return NULL;
+ else {
+ char *res = state->next_string;
+ state->next_string += sys_strlen(res) + 1;
+ return res;
+ }
+}
+
+void fini_getenv_state(GETENV_STATE *state)
+{
+ FreeEnvironmentStrings(state->environment_strings);
+ state->environment_strings = state->next_string = NULL;
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+}
+
+char*
+win_build_environment(char* new_env)
+{
+ if (new_env == NULL) {
+ return NULL;
+ } else {
+ char *tmp, *merged;
+
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ tmp = GetEnvironmentStrings();
+ merged = merge_environment(tmp, new_env);
+
+ FreeEnvironmentStrings(tmp);
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+ return merged;
+ }
+}
+
+static char*
+merge_environment(char *old, char *add)
+{
+ char **a_arg = env_to_arg(add);
+ char **c_arg = env_to_arg(old);
+ char *ret;
+ int i, j;
+
+ for(i = 0; c_arg[i] != NULL; ++i)
+ ;
+
+ for(j = 0; a_arg[j] != NULL; ++j)
+ ;
+
+ c_arg = erts_realloc(ERTS_ALC_T_TMP,
+ c_arg, (i+j+1) * sizeof(char *));
+
+ for(j = 0; a_arg[j] != NULL; ++j){
+ char **tmp;
+ char *current = a_arg[j];
+
+ if ((tmp = find_arg(c_arg, current)) != NULL) {
+ if (current[strlen(current)-1] != '=') {
+ *tmp = current;
+ } else {
+ *tmp = c_arg[--i];
+ c_arg[i] = NULL;
+ }
+ } else if (current[strlen(current)-1] != '=') {
+ c_arg[i++] = current;
+ c_arg[i] = NULL;
+ }
+ }
+ ret = arg_to_env(c_arg);
+ erts_free(ERTS_ALC_T_TMP, c_arg);
+ erts_free(ERTS_ALC_T_TMP, a_arg);
+ return ret;
+}
+
+static char**
+find_arg(char **arg, char *str)
+{
+ char *tmp;
+ int len;
+
+ if ((tmp = strchr(str, '=')) != NULL) {
+ tmp++;
+ len = tmp - str;
+ while (*arg != NULL){
+ if (_strnicmp(*arg, str, len) == 0){
+ return arg;
+ }
+ ++arg;
+ }
+ }
+ return NULL;
+}
+
+static int
+compare(const void *a, const void *b)
+{
+ char *s1 = *((char **) a);
+ char *s2 = *((char **) b);
+ char *e1 = strchr(s1,'=');
+ char *e2 = strchr(s2,'=');
+ int ret;
+ int len;
+
+ if(!e1)
+ e1 = s1 + strlen(s1);
+ if(!e2)
+ e2 = s2 + strlen(s2);
+
+ if((e1 - s1) > (e2 - s2))
+ len = (e2 - s2);
+ else
+ len = (e1 - s1);
+
+ ret = _strnicmp(s1,s2,len);
+ if (ret == 0)
+ return ((e1 - s1) - (e2 - s2));
+ else
+ return ret;
+}
+
+static char**
+env_to_arg(char *env)
+{
+ char **ret;
+ char *tmp;
+ int i;
+ int num_strings = 0;
+
+ for(tmp = env; *tmp != '\0'; tmp += strlen(tmp)+1) {
+ ++num_strings;
+ }
+ ret = erts_alloc(ERTS_ALC_T_TMP, sizeof(char *) * (num_strings + 1));
+ i = 0;
+ for(tmp = env; *tmp != '\0'; tmp += strlen(tmp)+1){
+ ret[i++] = tmp;
+ }
+ ret[i] = NULL;
+ return ret;
+}
+
+static char*
+arg_to_env(char **arg)
+{
+ char *block;
+ char *ptr;
+ int i;
+ int totlen = 1; /* extra '\0' */
+
+ for(i = 0; arg[i] != NULL; ++i) {
+ totlen += strlen(arg[i])+1;
+ }
+
+ /* sort the environment vector */
+ qsort(arg, i, sizeof(char *), &compare);
+
+ if (totlen == 1){
+ block = erts_alloc(ERTS_ALC_T_ENVIRONMENT, 2);
+ block[0] = block[1] = '\0';
+ } else {
+ block = erts_alloc(ERTS_ALC_T_ENVIRONMENT, totlen);
+ ptr = block;
+ for(i=0; arg[i] != NULL; ++i){
+ strcpy(ptr, arg[i]);
+ ptr += strlen(ptr)+1;
+ }
+ *ptr = '\0';
+ }
+ return block;
+}