blob: e5ccb45535d294f4759ecf923296e94a48ada969 [file] [log] [blame] [raw]
/* 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();
}