blob: 0ab75e200b968f94f3a153489305c5ed20b1adc9 [file]
//===----------------------------------------------------------------------===//
//
// 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);
};
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDLIB_ENVIRON_INTERNAL_H