196 lines
5.0 KiB
C
196 lines
5.0 KiB
C
// 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 <stdlib.h>
|
|
#include <unistd.h>
|
|
#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();
|
|
}
|