sllibc/stdlib.c

196 lines
5.0 KiB
C
Raw Permalink Normal View History

2025-06-04 01:22:53 +10:00
// 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();
}