| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// Internal utilities for environment variable management. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIBC_SRC_STDLIB_ENVIRON_INTERNAL_H | |
| #define LLVM_LIBC_SRC_STDLIB_ENVIRON_INTERNAL_H | |
| #include "hdr/types/size_t.h" | |
| #include "src/__support/CPP/optional.h" | |
| #include "src/__support/CPP/string_view.h" | |
| #include "src/__support/macros/attributes.h" | |
| #include "src/__support/macros/config.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| namespace internal { | |
| // Ownership information for environment strings. | |
| // We need to track ownership because environment strings come from three | |
| // sources: | |
| // 1. Startup environment (from program loader) - we don't own these | |
| // 2. putenv() calls where caller provides the string - we don't own these | |
| // 3. setenv() calls where we allocate the string - we DO own these | |
| // Only strings we allocated can be freed when replaced or removed. | |
| struct EnvStringOwnership { | |
| bool allocated_by_us; // True if we allocated this string (must delete). | |
| // False for startup environ or putenv strings (don't | |
| // free). | |
| // Default: not owned by us (startup or putenv - don't free). | |
| LIBC_INLINE EnvStringOwnership() : allocated_by_us(false) {} | |
| // Returns true if this string can be safely freed. | |
| LIBC_INLINE bool can_free() const { return allocated_by_us; } | |
| }; | |
| // Centralized manager for environment variable operations. | |
| // This class encapsulates all state and operations related to environment | |
| // management, including memory management and tracking of string ownership. | |
| // | |
| // The manager provides iterator support, allowing callers to iterate over | |
| // the current environment entries using standard begin()/end() semantics. | |
| class EnvironmentManager { | |
| // Our allocated environ array (nullptr if using startup environ) | |
| char **storage = nullptr; | |
| // Parallel array tracking ownership of each environ string. | |
| // Allocated with the same capacity as storage. | |
| EnvStringOwnership *ownership = nullptr; | |
| // Allocated capacity of storage | |
| size_t capacity = 0; | |
| // Current number of variables in environ | |
| size_t count = 0; | |
| // True if we have initialized from the startup environment | |
| bool initialized = false; | |
| // True if we allocated storage (and are responsible for freeing it) | |
| bool is_ours = false; | |
| EnvironmentManager() = default; | |
| ~EnvironmentManager() = default; | |
| // Lazily initialize from the startup environment. | |
| // Called internally by get_instance(); idempotent. | |
| void init_once(); | |
| // Get a pointer to the current environ array. | |
| // This may be app.env_ptr (startup environ) or storage (our copy). | |
| char **get_array(); | |
| // Search for a variable by name in the current environ array. | |
| // Returns the index if found, or nullopt if not found. | |
| cpp::optional<size_t> find_var(cpp::string_view name); | |
| // Ensure environ has capacity for at least `needed` entries (plus null | |
| // terminator). May allocate or reallocate storage. Returns true on | |
| // success, false on allocation failure. | |
| bool ensure_capacity(size_t needed); | |
| // Result of a successful environment storage allocation. | |
| struct AllocResult { | |
| char **storage; | |
| EnvStringOwnership *ownership; | |
| }; | |
| // Helper: allocate new storage and ownership arrays of the given capacity, | |
| // copy the first `copy_count` entries from old_storage/old_ownership, and | |
| // initialize the remaining ownership slots to default (not-owned). | |
| // Returns nullopt on allocation failure; the old arrays are untouched. | |
| cpp::optional<AllocResult> alloc_and_copy(size_t new_capacity, | |
| char **old_storage, | |
| EnvStringOwnership *old_ownership, | |
| size_t copy_count); | |
| public: | |
| // Get the singleton instance of the environment manager. | |
| static EnvironmentManager &get_instance(); | |
| // Delete copy and move operations to enforce singleton pattern. | |
| EnvironmentManager(const EnvironmentManager &) = delete; | |
| EnvironmentManager &operator=(const EnvironmentManager &) = delete; | |
| EnvironmentManager(EnvironmentManager &&) = delete; | |
| EnvironmentManager &operator=(EnvironmentManager &&) = delete; | |
| // Iterator support for traversing environment entries. | |
| using iterator = char **; | |
| iterator begin(); | |
| iterator end(); | |
| size_t size() const; | |
| // Look up a variable by name. Returns a pointer to the value string | |
| // (after the '='), or nullptr if not found. | |
| char *get(cpp::string_view name); | |
| // Set or update an environment variable. Builds a "name=value" string, | |
| // manages ownership, and updates the environ array. If `overwrite` is | |
| // false and the variable already exists, does nothing and returns 0. | |
| // Returns 0 on success, -1 on allocation failure (caller should set | |
| // errno to ENOMEM). | |
| int set(cpp::string_view name, cpp::string_view value, bool overwrite); | |
| // Insert a caller-provided "name=value" string into the environment. | |
| // The caller retains ownership of the string; the manager will not | |
| // free it. If string contains no '=', the named variable is removed | |
| // (POSIX behavior). Returns 0 on success, -1 on failure. | |
| int put(char *string); | |
| // Remove a variable by name. Frees the string if we own it, then | |
| // compacts the array. Returns 0 on success (including if the variable | |
| // was not found), -1 on allocation failure during array transition. | |
| int unset(cpp::string_view name); | |
| }; | |
| } // namespace internal | |
| } // namespace LIBC_NAMESPACE_DECL | |
| #endif // LLVM_LIBC_SRC_STDLIB_ENVIRON_INTERNAL_H |