// Copyright (c) 2025, Zak Fenton // Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this // software according to the terms and conditions of the Mulan PSL v2. // You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of // any kind, either express or implied, including but not limited to // non-infringement, merchantability or fit for a particular purpose. // See the Mulan PSL v2 for more details. #include #include #include "internal.h" /* DESIGN NOTE: At program entry the environment variables are just an * array of "key=value" strings allocated on/near the stack by the * kernel. When actively modifying environment variables the structure * needs to be reallocated, so the system initially just uses the * preallocated copy but keeps a _libc_env_reallocated flag to tell it * if it's using a malloc'd copy so it can be freed properly. This means * the system is optimised for programs that don't use environment * variables much so it doesn't rely on memory allocation in those * cases but may be slightly inefficient in cases where you do make * heavy use of them (copying the whole table on every change instead of * just using an optimised structure from the start). */ const char** _libc_env_variable; int _libc_env_count; int _libc_env_reallocated; void _libc_env_init(const char** envv) { _libc_env_variable = envv; _libc_env_count = 0; _libc_env_reallocated = 0; while (envv != NULL && envv[_libc_env_count] != NULL) { _libc_env_count++; } } const char* _libc_env_match(const char* env, const char* key) { int i; for (i = 0; key[i] != 0; i++) { if (env[i] != key[i]) { return 0; // false, env doesn't match given key } } if (env[i] != '=') { return 0; // false, env key is longer than given key } return env+i+1; // true, env string starts with key followed by "=" } char* getenv(const char* key) { for (int i = 0; i < _libc_env_count; i++) { const char* tmp; if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) { return tmp; } } return NULL; } int setenv(const char* key, const char* value, int overwrite) { int exists = -1; int i; for (i = 0; i < _libc_env_count; i++) { const char* tmp; if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) { if (overwrite) { exists = i; break; } else { return 0; } } } int newsize; newsize = _libc_env_count + (exists >= 0 ? 1 : 0); char* newentry = malloc(strlen(key)+strlen(value)+2); sprintf(newentry, "%s=%s", key, value); const char** oldptr = _libc_env_variable; const char** newptr = malloc(newsize * sizeof(char*)); for (i = 0; i < _libc_env_count; i++) { const char* tmp; if (i == exists) { newptr[i] = newentry; } else { newptr[i] = strdup(oldptr[i]); } if (_libc_env_reallocated) { free(oldptr[i]); } } if (i < newsize) { newptr[i] = newentry; } _libc_env_variable = newptr; if (_libc_env_reallocated) { free(oldptr); } _libc_env_reallocated = 1; return 0; } int unsetenv(const char* key) { int exists = -1; int i; for (i = 0; i < _libc_env_count; i++) { const char* tmp; if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) { exists = i; break; } } if (exists < 0) { return 0; // Nothing to do, env var already doesn't exist } int newsize = _libc_env_count - 1; const char** oldptr = _libc_env_variable; const char** newptr = malloc(newsize * sizeof(char*)); for (i = 0; i < _libc_env_count; i++) { const char* tmp; if (i >= exists) { newptr[i] = strdup(oldptr[i-1]); } else { newptr[i] = strdup(oldptr[i]); } if (_libc_env_reallocated) { free(oldptr[i]); } } _libc_env_variable = newptr; if (_libc_env_reallocated) { free(oldptr); } _libc_env_reallocated = 1; return 0; } int system(const char* cmd) { UNIMPLEMENTED(); } void abort() { UNIMPLEMENTED(); } double atof(const char* str) { UNIMPLEMENTED(); } int _libc_charnum(char c, int base) { int n; if (c >= '0' && c <= '9') { n = c - '0'; } else if (c >= 'A' && c <= 'F') { n = 10 + c - 'A'; } else if (c >= 'a' && c <= 'f') { n = 10 + c - 'a'; } else { return -1; } if (n < base) { return n; } else { return -1; } } long strtol(const char* str, char**endvar, int base) { UNIMPLEMENTED(); } long long strtoll(const char* str, char**endvar, int base) { UNIMPLEMENTED(); } unsigned long strtoul(const char* str, char**endvar, int base) { return strtoull(str, endvar, base); } unsigned long long strtoull(const char* str, char**endvar, int base) { UNIMPLEMENTED(); } float strtof(const char* str, char**endvar) { UNIMPLEMENTED(); } double strtod(const char* str, char**endvar) { UNIMPLEMENTED(); } long double strtold(const char* str, char**endvar) { UNIMPLEMENTED(); }