| /* This file is part of celibc |
| Copyright 2007-2014 PC GO Ld. |
| msl0000023508@gmail.com |
| Published under GNU GPL 2. |
| |
| based on celib's code from keuchel@netwave.de |
| */ |
| |
| #include "shared.h" |
| #include "reent.h" |
| #include "lock.h" |
| #include <windows.h> |
| |
| #if 1 |
| void bcopy(const void *, void *, size_t); |
| char *index(const char *, int); |
| void tzset(void); |
| #endif |
| |
| #define ERROR_NO_MORE_ITEMS 259L |
| |
| static char *initial_env[] = { 0 }; |
| char **environ = initial_env; |
| static char ***p_environ = &environ; |
| extern char *_findenv(/*struct _reent *, */const char *, int *); |
| //static int __env_lock_object = 0; |
| |
| static void __env_lock (/*struct _reent *ptr*/) |
| { |
| #ifndef __SINGLE_THREAD__ |
| __lock_acquire_recursive(__env_lock_object); |
| #endif |
| } |
| |
| static void __env_unlock (/*struct _reent *ptr*/) |
| { |
| #ifndef __SINGLE_THREAD__ |
| __lock_release_recursive(__env_lock_object); |
| #endif |
| } |
| |
| char *_findenv(/*struct _reent *reent_ptr, */register const char *name, int *offset) |
| { |
| register int len; |
| register char **p; |
| const char *c; |
| |
| __env_lock(/*reent_ptr*/); |
| |
| /* In some embedded systems, this does not get set. This protects |
| newlib from dereferencing a bad pointer. */ |
| if (!*p_environ){ |
| __env_unlock; |
| return NULL; |
| } |
| |
| c = name; |
| len = 0; |
| while (*c && *c != '='){ |
| c++; |
| len++; |
| } |
| |
| for (p = *p_environ; *p; ++p) if (!strncmp (*p, name, len)) if (*(c = *p + len) == '=') |
| { |
| *offset = p - *p_environ; |
| __env_unlock; |
| return (char *) (++c); |
| } |
| __env_unlock; |
| return NULL; |
| } |
| |
| char *getenv(const char *name) |
| { |
| int offset; |
| char *_findenv(); |
| |
| return _findenv(/*_REENT, */name, &offset); |
| } |
| |
| void unsetenv(/*struct _reent *reent_ptr, */const char *name) |
| { |
| register char **P; |
| int offset; |
| |
| __env_lock(/*reent_ptr*/); |
| |
| while (_findenv(/*reent_ptr, */name, &offset)) /* if set multiple times */ |
| for (P = &(*p_environ)[offset];; ++P) if (!(*P = *(P + 1))) break; |
| |
| __env_unlock(/*reent_ptr*/); |
| } |
| |
| int setenv(/*struct _reent *reent_ptr, */const char *name, const char *value, int rewrite) |
| { |
| static int alloced; /* if allocated space before */ |
| register char *C; |
| int l_value, offset; |
| |
| __env_lock(/*reent_ptr*/); |
| |
| if (*value == '=') /* no `=' in value */ |
| ++value; |
| l_value = strlen (value); |
| if ((C = _findenv(/*reent_ptr, */name, &offset))){ /* find if already exists */ |
| if (!rewrite){ |
| __env_unlock(/*reent_ptr*/); |
| return 0; |
| } |
| if (strlen (C) >= l_value){ /* old larger; copy over */ |
| while ((*C++ = *value++) != 0); |
| __env_unlock(/*reent_ptr*/); |
| |
| /* if we are changing the TZ environment variable, update timezone info */ |
| if (strcmp (name, "TZ") == 0) tzset (); |
| return 0; |
| } |
| }else{ /* create new slot */ |
| register int cnt; |
| register char **P; |
| |
| for (P = *p_environ, cnt = 0; *P; ++P, ++cnt); |
| if (alloced){ /* just increase size */ |
| *p_environ = (char **) realloc((char *) environ, (size_t) (sizeof (char *) * (cnt + 2))); |
| if (!*p_environ){ |
| __env_unlock(/*reent_ptr*/); |
| return -1; |
| } |
| }else{ /* get new space */ |
| alloced = 1; /* copy old entries into it */ |
| P = (char **)malloc(sizeof (char *) * (cnt + 2)); |
| if (!P){ |
| __env_unlock(/*reent_ptr*/); |
| return (-1); |
| } |
| bcopy ((char *) *p_environ, (char *) P, cnt * sizeof (char *)); |
| *p_environ = P; |
| } |
| (*p_environ)[cnt + 1] = NULL; |
| offset = cnt; |
| } |
| for (C = (char *) name; *C && *C != '='; ++C); /* no `=' in name */ |
| if (!((*p_environ)[offset] = /* name + `=' + value */ |
| malloc((int)(C - name) + l_value + 2))){ |
| __env_unlock(/*reent_ptr*/); |
| return -1; |
| } |
| for (C = (*p_environ)[offset]; (*C = *name++) && *C != '='; ++C); |
| for (*C++ = '='; (*C++ = *value++) != 0;); |
| |
| __env_unlock(/*reent_ptr*/); |
| |
| /* if we are setting the TZ environment variable, update timezone info */ |
| if (strncmp ((*p_environ)[offset], "TZ=", 3) == 0) tzset (); |
| |
| return 0; |
| } |
| |
| int putenv(const char *str) |
| { |
| register char *p, *equal; |
| int rval; |
| |
| p = strdup(str); |
| |
| if (!p) return 1; |
| |
| if (!(equal = index(p, '='))){ |
| free(p); |
| return 1; |
| } |
| |
| *equal = '\0'; |
| rval = setenv(/*_REENT, */p, equal + 1, 1); |
| free(p); |
| |
| return rval; |
| } |
| |
| static int getenvironblk(_SHMBLK shmblk, char **env) |
| { |
| char *s; |
| int i, len; |
| |
| if (shmblk == NULL) { |
| return 0; |
| } |
| |
| for (i = 0, s = shmblk->pginfo.environ; *s; i++) { |
| s += strlen(s) + 1; |
| } |
| |
| if (i) { |
| len = s - shmblk->pginfo.environ + 1; |
| *env = malloc(len); |
| if (*env == NULL) { |
| //WCETRACE(WCE_IO, "_shared_getenvironblk: FATAL ERROR malloc failed for %d more bytes", len); |
| exit(1); |
| } |
| |
| memcpy(*env, shmblk->pginfo.environ, len); |
| } |
| |
| return i; |
| } |
| |
| void _initenv_from_reg() |
| { |
| int res; |
| //char valname[126]; |
| //char data[1024]; |
| wchar_t wvalname[256]; |
| wchar_t wdata[1024]; |
| char buf[1024]; |
| HKEY hKey; |
| DWORD dwValSize; |
| DWORD dwDataSize; |
| DWORD dwType; |
| int idx = 0; |
| //char *p; |
| |
| static int initted = 0; |
| if (initted) return; |
| initted = 1; |
| |
| if((res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Environment", 0, KEY_READ, &hKey)) != 0){ |
| // use defaults |
| //putenv("UNIXROOTDIR=/"); |
| putenv("PATH=.:/:/Windows"); |
| putenv("HOME=/"); |
| putenv("TEMP=/Temp"); |
| putenv("OS=Windows_CE"); |
| return; |
| } |
| |
| size_t len1; |
| size_t len2; |
| while(1) { |
| dwValSize = 1024; |
| dwDataSize = 4096; |
| //res = XCERegEnumValueA(hKey, idx++, valname, &dwValSize, NULL, &dwType, data, &dwDataSize); |
| res = RegEnumValueW(hKey, idx++, wvalname, &dwValSize, NULL, &dwType, (unsigned char *)wdata, &dwDataSize); |
| if(res != 0){ |
| //if(res != ERROR_NO_MORE_ITEMS) XCEShowMessageA("RegEnumValue: %d", res); |
| break; |
| } |
| len1 = wcslen(wvalname) * 2 - 1; |
| len2 = wcslen(wdata) * 2 - 1; |
| //char *valname = (char *)malloc(len1 * sizeof(char)); |
| //char *data = (char *)malloc(len2 * sizeof(char)); |
| char valname[len1]; |
| char data[len2]; |
| wcstombs(valname, wvalname, len1); |
| wcstombs(data, wdata, len2); |
| if(dwType != REG_SZ) continue; |
| sprintf(buf, "%s=%s", valname, data); |
| putenv(buf); |
| } |
| |
| RegCloseKey(hKey); |
| } |
| |
| void _initenv_from_envblock(char *buf) |
| { |
| char *s; |
| for(s = buf; *s;) { |
| putenv(s); |
| s += strlen(s) + 1; |
| } |
| } |
| |
| void _initenv(_SHMBLK shmblk) |
| { |
| if(shmblk) { |
| char *buf; |
| int no; |
| |
| /* We are being initialized from a cegcc app. Only use the |
| registry environment if there are no environment variables in |
| the shared block. */ |
| |
| no = getenvironblk(shmblk, &buf); |
| |
| if(no) { |
| _initenv_from_envblock(buf); |
| free(buf); |
| } else _initenv_from_reg(); |
| } else _initenv_from_reg(); |
| } |