diff --git a/LibC/stdlib.cpp b/LibC/stdlib.cpp index 2a7fe67e30..ccd8c3c1fd 100644 --- a/LibC/stdlib.cpp +++ b/LibC/stdlib.cpp @@ -62,13 +62,40 @@ char* getenv(const char* name) return nullptr; } +int unsetenv(char* name) +{ + auto new_var_len = strlen(name); + size_t environ_size = 0; + size_t skip = -1; + + for (; environ[environ_size]; ++environ_size) { + char* old_var = environ[environ_size]; + char* old_eq = strchr(old_var, '='); + ASSERT(old_eq); + auto old_var_len = old_eq - old_var; + + if (new_var_len != old_var_len) + continue; // can't match + + if (strncmp(name, old_var, new_var_len) == 0) + skip = environ_size; + } + + if (skip == -1) + return 0; // not found: no failure. + + // Shuffle the existing array down by one. + memmove(&environ[skip], &environ[skip+1], ((environ_size-1)-skip) * sizeof(environ[0])); + environ[environ_size-1] = nullptr; + return 0; +} + int putenv(char* new_var) { char* new_eq = strchr(new_var, '='); - // FIXME: should remove the var from the environment. if (!new_eq) - return 0; + return unsetenv(new_var); auto new_var_len = new_eq - new_var; size_t environ_size = 0; diff --git a/LibC/stdlib.h b/LibC/stdlib.h index 0b4f0dea9a..0bfdf0663a 100644 --- a/LibC/stdlib.h +++ b/LibC/stdlib.h @@ -16,6 +16,7 @@ void free(void*); void* realloc(void *ptr, size_t); char* getenv(const char* name); int putenv(char*); +int unsetenv(char*); int atoi(const char*); long atol(const char*); long long atoll(const char*); diff --git a/Shell/main.cpp b/Shell/main.cpp index 96f1eab7dc..5c019f4826 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -80,6 +80,17 @@ static int sh_export(int argc, char** argv) return 0; } +static int sh_unset(int argc, char** argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: unset variable\n"); + return 1; + } + + unsetenv(argv[1]); + return 0; +} + static int sh_cd(int argc, char** argv) { char pathbuf[PATH_MAX]; @@ -167,6 +178,10 @@ static bool handle_builtin(int argc, char** argv, int& retval) retval = sh_export(argc, argv); return true; } + if (!strcmp(argv[0], "unset")) { + retval = sh_unset(argc, argv); + return true; + } if (!strcmp(argv[0], "history")) { retval = sh_history(argc, argv); return true;