diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index 72f8f3a2..528611cf 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -50,6 +50,7 @@ start.o \ time.o \ random.o \ abs.o \ +env.o \ integer.o \ c++.o \ memory.o \ diff --git a/libmaxsi/env.cpp b/libmaxsi/env.cpp new file mode 100644 index 00000000..64444b9d --- /dev/null +++ b/libmaxsi/env.cpp @@ -0,0 +1,192 @@ +/******************************************************************************* + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + env.cpp + Environmental variables utilities. + +*******************************************************************************/ + +#include +#include +#include +#include +#include + +/* Since legacy applications rely on being able to modify the environ variable, + we have to keep track of whether it is what we expect and whether we know the + size of it. If it changed, we need to recount, as well as malloc a copy of it + if we wish to make changes. */ +extern "C" { char** environ = NULL; } +static char** environ_malloced = NULL; +static char** environ_counted = NULL; +size_t environlen = 0; +size_t environroom = 0; + +static inline bool environismalloced() +{ + return environ && environ == environ_malloced; +} + +extern "C" const char* const* getenviron(void) +{ + return environ; +} + +extern "C" size_t envlength(void) +{ + if ( !environ ) { return 0; } + if ( environ_counted != environ ) + { + size_t count = 0; + while ( environ[count] ) { count++; } + environ_counted = environ; + environlen = count; + } + return environlen; +} + +extern "C" const char* getenvindexed(size_t index) +{ + if ( envlength() <= index ) { errno = EBOUND; return NULL; } + return environ[index]; +} + +extern "C" const char* sortix_getenv(const char* name) +{ + size_t equalpos = strcspn(name, "="); + if ( name[equalpos] == '=' ) { return NULL; } + size_t namelen = equalpos; + size_t envlen = envlength(); + for ( size_t i = 0; i < envlen; i++ ) + { + if ( strncmp(name, environ[i], namelen) ) { continue; } + if ( environ[i][namelen] != '=' ) { continue; } + return environ[i] + namelen + 1; + } + return NULL; +} + +extern "C" char* getenv(const char* name) +{ + return (char*) sortix_getenv(name); +} + +static bool makeenvironmalloced() +{ + if ( environismalloced() ) { return true; } + size_t envlen = envlength(); + size_t newenvlen = envlen; + size_t newenvsize = sizeof(char*) * (newenvlen+1); + char** newenviron = (char**) malloc(newenvsize); + if ( !newenviron ) { return false; } + size_t sofar = 0; + for ( size_t i = 0; i < envlen; i++ ) + { + newenviron[i] = strdup(environ[i]); + if ( !newenviron[i] ) { goto cleanup; } + sofar = i; + } + newenviron[envlen] = NULL; + environlen = environroom = newenvlen; + environ = environ_malloced = environ_counted = newenviron; + return true; +cleanup: + for ( size_t i = 0; i < sofar; i++ ) { free(newenviron[i]); } + free(newenviron); + return false; +} + +extern "C" int clearenv(void) +{ + if ( !environ ) { return 0; } + if ( environismalloced() ) + { + for ( char** varp = environ; *varp; varp++ ) { free(*varp); } + free(environ); + } + environ = environ_counted = environ_malloced = NULL; + return 0; +} + +static bool doputenv(char* str, char* freeme, bool overwrite) +{ + if ( !makeenvironmalloced() ) { free(freeme); return false; } + size_t strvarnamelen = strcspn(str, "="); + for ( size_t i = 0; i < envlength(); i++ ) + { + char* var = environ[i]; + if ( strncmp(str, var, strvarnamelen) ) { continue; } + if ( !overwrite ) { free(freeme); return true; } + free(var); + environ[i] = str; + return true; + } + if ( environlen == environroom ) + { + size_t newenvironroom = environroom ? 2 * environroom : 16; + size_t newenvironsize = sizeof(char*) * (newenvironroom+1); + char** newenviron = (char**) realloc(environ, newenvironsize); + if ( !newenviron ) { free(freeme); return false; } + environ = environ_malloced = environ_counted = newenviron; + environroom = newenvironroom; + } + environ[environlen++] = str; + environ[environlen] = NULL; + return true; +} + +extern "C" int setenv(const char* name, const char* value, int overwrite) +{ + if ( !name || !name[0] || strchr(name, '=') ) { errno = EINVAL; return -1; } + char* str = (char*) malloc(strlen(name) + 1 + strlen(value) + 1); + if ( !str ) { return -1; } + stpcpy(stpcpy(stpcpy(str, name), "="), value); + if ( !doputenv(str, str, overwrite) ) { return -1; } + return 0; +} + +extern "C" int putenv(char* str) +{ + if ( !strchr(str, '=') ) { errno = EINVAL; return -1; } + if ( !doputenv(str, NULL, true) ) { return -1; } + return 0; +} + +extern "C" int unsetenv(const char* name) +{ + size_t equalpos = strcspn(name, "="); + if ( name[equalpos] == '=' ) { return 0; } + size_t namelen = equalpos; + size_t envlen = envlength(); + for ( size_t i = 0; i < envlen; i++ ) + { + if ( strncmp(name, environ[i], namelen) ) { continue; } + if ( environ[i][namelen] != '=' ) { continue; } + if ( environismalloced() ) + { + char* str = environ[i]; + free(str); + } + if ( i < envlen-1 ) { environ[i] = environ[envlen-1]; } + environ[--environlen] = NULL; + return 0; + } + return 0; +} + diff --git a/libmaxsi/include/stdlib.h b/libmaxsi/include/stdlib.h index f7faea4a..92cfb470 100644 --- a/libmaxsi/include/stdlib.h +++ b/libmaxsi/include/stdlib.h @@ -56,20 +56,39 @@ void* calloc(size_t, size_t); void exit(int); void _Exit(int status); void free(void*); -char* getenv(const char*); long labs(long); long long llabs(long long); void* malloc(size_t); #if !defined(_SORTIX_SOURCE) char* mktemp(char* templ); #endif +int putenv(char*); void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); int rand(void); void* realloc(void*, size_t); +int setenv(const char*, const char*, int); long strtol(const char* restrict, char** restrict, int); unsigned long strtoul(const char* restrict, char** restrict, int); unsigned long long strtoull(const char* restrict, char** restrict, int); long long strtoll(const char* restrict, char** restrict, int); +int unsetenv(const char*); + +#if defined(_SORTIX_SOURCE) || defined(_WANT_SORTIX_ENV) +const char* const* getenviron(void); +size_t envlength(void); +const char* getenvindexed(size_t index); +const char* sortix_getenv(const char* name); +#endif +#if (defined(_SOURCE_SOURCE) && __SORTIX_STDLIB_REDIRECTS) || \ + defined(_WANT_SORTIX_ENV) +const char* getenv(const char* name) asm ("sortix_getenv"); +#else +char* getenv(const char*); +#endif +#if defined(_SORTIX_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) \ + || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int clearenv(void); +#endif /* TODO: These are not implemented in libmaxsi/sortix yet. */ #if defined(__SORTIX_SHOW_UNIMPLEMENTED) @@ -99,11 +118,9 @@ long nrand48(unsigned short[3]); int posix_memalign(void**, size_t, size_t); int posix_openpt(int); char* ptsname(int); -int putenv(char*); long random(void); char* realpath(const char* restrict, char* restrict); unsigned short *seed48(unsigned short [3]); -int setenv(const char*, const char*, int); void setkey(const char*); char* setstate(char*); void srand(unsigned); @@ -114,7 +131,6 @@ float strtof(const char* restrict, char** restrict); long double strtold(const char* restrict, char** restrict); int system(const char*); int unlockpt(int); -int unsetenv(const char*); size_t wcstombs(char* restrict, const wchar_t *restrict, size_t); int wctomb(char*, wchar_t); diff --git a/libmaxsi/process.cpp b/libmaxsi/process.cpp index ab624d41..868ce177 100644 --- a/libmaxsi/process.cpp +++ b/libmaxsi/process.cpp @@ -40,8 +40,6 @@ namespace Maxsi DEFN_SYSCALL0(pid_t, SysGetParentPID, SYSCALL_GETPPID); DEFN_SYSCALL3(pid_t, SysWait, SYSCALL_WAIT, pid_t, int*, int); - extern "C" char** environ = NULL; - void Abort() { // TODO: Send SIGABRT instead! @@ -102,11 +100,6 @@ namespace Maxsi { return waitpid(-1, status, 0); } - - extern "C" char* getenv(const char* name) - { - return NULL; - } } }