From 4f90f084918ddb5ef79c10b77450a673bc73c170 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Wed, 11 Sep 2024 22:56:53 +0300 Subject: [PATCH] reimplement glib functions --- include/env.h | 10 ++++ sway/commands/env.c | 4 +- sway/commands/exec_always.c | 1 - sway/env.c | 110 ++++++++++++++++++++++++++++++++++++ sway/main.c | 6 +- sway/meson.build | 1 + 6 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 include/env.h create mode 100644 sway/env.c diff --git a/include/env.h b/include/env.h new file mode 100644 index 000000000..2d6e996f8 --- /dev/null +++ b/include/env.h @@ -0,0 +1,10 @@ +#ifndef _SWAY_ENV_H +#define _SWAY_ENV_H + +void env_free(char **envp); + +char **env_get_envp(); + +char **env_setenv(char **envp, char *name, char *value); + +#endif diff --git a/sway/commands/env.c b/sway/commands/env.c index a382cb382..93e45be0d 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -1,7 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include -#include #include "sway/commands.h" +#include "env.h" extern char **child_envp; @@ -13,7 +13,7 @@ struct cmd_results *cmd_env(int argc, char **argv) { // g_environ_setenv never returns NULL // https://github.com/GNOME/glib/blob/8810cf7a/glib/genviron.c#L129 - child_envp = g_environ_setenv(child_envp, argv[0], argv[1], 1); + child_envp = env_setenv(child_envp, argv[0], argv[1]); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 2773238bf..502beeb30 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "sway/commands.h" #include "sway/config.h" #include "sway/server.h" diff --git a/sway/env.c b/sway/env.c new file mode 100644 index 000000000..75e1d3f2f --- /dev/null +++ b/sway/env.c @@ -0,0 +1,110 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include + +extern char **environ; + +int _env_var_name_eq(char *env_name, char *cmp) { + size_t i = 0; + int reached_eq; + while (1) { + char current_char = env_name[i]; + char cmp_char = cmp[i]; + + int is_eq = current_char == '='; + int is_null = current_char == '\0'; + + if (is_eq) reached_eq = 1; + if (is_null && !reached_eq) return 0; + if (is_eq && cmp_char == '\0') return 1; + if (is_eq || cmp_char == '\0') return 0; + if (current_char != cmp_char) return 0; + + i++; + } +} + +typedef struct { + char *ptr; + size_t idx; +} _env_info; + +_env_info _env_get(char **envp, char *name) { + char *strp; + size_t i = 0; + while ((strp = envp[i]) != NULL) { + if (_env_var_name_eq(strp, name)) return (_env_info){strp, i}; + i++; + } + + return (_env_info){NULL, 0}; +} + +size_t _env_len(char **envp) { + char *strp; + size_t i = 0; + + while ((strp = envp[i]) != NULL) { + i++; + } + + return i; +} + +char **_env_clone(char **envp, size_t reserve) { + char **new_envp = calloc(_env_len(envp) + 1 + reserve, sizeof(char *)); + + char *strp; + size_t i = 0; + + while ((strp = envp[i]) != NULL) { + size_t n = strlen(strp) + 1; + char *new_strp = malloc(n); + memcpy(new_strp, strp, n); + new_envp[i] = new_strp; + i++; + } + + return new_envp; +} + +void env_free(char **envp) { + char *strp; + size_t i = 0; + while ((strp = envp[i]) != NULL) { + free(strp); + i++; + } + + free(envp); +} + +// copy the global environment array into a newly-allocated one +// you are responsible for deallocating it after use +char **env_get_envp() { return _env_clone(environ, 0); } + +// use env_get_envp() to acquire an envp +// might clone and deallocate the given envp +char **env_setenv(char **envp, char *name, char *value) { + size_t name_len = strlen(name); + size_t value_len = strlen(value); + char *newp = malloc(name_len + value_len + 2); + memcpy(newp, name, name_len); + memcpy(newp + name_len + 1, value, value_len); + newp[name_len] = '='; + newp[name_len + value_len + 1] = '\0'; + + _env_info existing = _env_get(envp, name); + if (existing.ptr != NULL) { + free(existing.ptr); + envp[existing.idx] = newp; + return envp; + } else { + char **new_envp = _env_clone(envp, 1); + new_envp[_env_len(envp)] = newp; + env_free(envp); + return new_envp; + } +} diff --git a/sway/main.c b/sway/main.c index d855de5b5..51c012e9f 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include "log.h" #include "stringop.h" #include "util.h" +#include "env.h" static bool terminate_request = false; static int exit_value = 0; @@ -350,8 +350,8 @@ int main(int argc, char **argv) { ipc_init(&server); setenv("WAYLAND_DISPLAY", server.socket, true); - // g_get_environ creates a newly-allocated environment buffer - child_envp = g_get_environ(); + // env_get_envp creates a newly-allocated environment buffer + child_envp = env_get_envp(); if (!load_main_config(config_path, false, false)) { sway_terminate(EXIT_FAILURE); goto shutdown; diff --git a/sway/meson.build b/sway/meson.build index ea03e2ef0..75c2410ab 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -3,6 +3,7 @@ sway_sources = files( 'config.c', 'criteria.c', 'decoration.c', + 'env.c', 'ipc-json.c', 'ipc-server.c', 'lock.c',