Viewing: environ.c
📄 environ.c (Read Only) ⬅ To go back
#include "stdlib.h"
#include "string.h"
#include "errno.h"
#include <stddef.h>

extern char** __environ;

static char* _env_storage[128];
static int _env_owned = 0;

static void _ensure_own_environ(void) {
    if (_env_owned) return;
    int count = 0;
    if (__environ) {
        for (; __environ[count]; count++) {
            if (count >= 126) break;
            _env_storage[count] = __environ[count];
        }
    }
    _env_storage[count] = (char*)0;
    __environ = _env_storage;
    _env_owned = 1;
}

int setenv(const char* name, const char* value, int overwrite) {
    if (!name || !*name || strchr(name, '=')) {
        errno = EINVAL;
        return -1;
    }

    _ensure_own_environ();

    size_t nlen = strlen(name);
    /* Check if already exists */
    for (int i = 0; __environ[i]; i++) {
        if (strncmp(__environ[i], name, nlen) == 0 && __environ[i][nlen] == '=') {
            if (!overwrite) return 0;
            /* Replace in-place */
            size_t vlen = strlen(value);
            char* buf = malloc(nlen + 1 + vlen + 1);
            if (!buf) { errno = ENOMEM; return -1; }
            memcpy(buf, name, nlen);
            buf[nlen] = '=';
            memcpy(buf + nlen + 1, value, vlen + 1);
            __environ[i] = buf;
            return 0;
        }
    }

    /* Count entries */
    int count = 0;
    while (__environ[count]) count++;
    if (count >= 126) { errno = ENOMEM; return -1; }

    size_t vlen = strlen(value);
    char* buf = malloc(nlen + 1 + vlen + 1);
    if (!buf) { errno = ENOMEM; return -1; }
    memcpy(buf, name, nlen);
    buf[nlen] = '=';
    memcpy(buf + nlen + 1, value, vlen + 1);

    __environ[count] = buf;
    __environ[count + 1] = (char*)0;
    return 0;
}

int unsetenv(const char* name) {
    if (!name || !*name || strchr(name, '=')) {
        errno = EINVAL;
        return -1;
    }

    _ensure_own_environ();

    size_t nlen = strlen(name);
    for (int i = 0; __environ[i]; i++) {
        if (strncmp(__environ[i], name, nlen) == 0 && __environ[i][nlen] == '=') {
            /* Shift remaining entries down */
            for (int j = i; __environ[j]; j++)
                __environ[j] = __environ[j + 1];
            return 0;
        }
    }
    return 0;
}

int putenv(char* string) {
    if (!string) { errno = EINVAL; return -1; }

    _ensure_own_environ();

    char* eq = strchr(string, '=');
    if (!eq) return unsetenv(string);

    size_t nlen = (size_t)(eq - string);

    /* Replace existing or append */
    for (int i = 0; __environ[i]; i++) {
        if (strncmp(__environ[i], string, nlen + 1) == 0) {
            __environ[i] = string;
            return 0;
        }
    }

    int count = 0;
    while (__environ[count]) count++;
    if (count >= 126) { errno = ENOMEM; return -1; }
    __environ[count] = string;
    __environ[count + 1] = (char*)0;
    return 0;
}