Source
stdlib/os/os.cpp
1
// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).2
// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.3
#include "os.hpp"5
#include <algorithm>6
#include <cstdlib>7
#include <stdexcept>8
#include <thread>10
#if defined(_WIN32)11
#include <process.h> // _getpid12
#include <windows.h>13
#include <bcrypt.h> // BCryptGenRandom14
#else15
#include <unistd.h> // getpid16
#include <sys/random.h> // getentropy17
#endif19
// Compiled (non-template) symbols of the os module. Linked into a cheatah20
// executable only when the program `import os`s.21
namespace cheatah::os {23
namespace fs = std::filesystem;25
std::string getcwd() { return fs::current_path().string(); }26
void chdir(const std::string& path) { fs::current_path(path); }28
std::vector<std::string> listdir(const std::string& path) {29
std::vector<std::string> names;30
for (const auto& entry : fs::directory_iterator(path)) {31
names.push_back(entry.path().filename().string());32
}33
return names;34
}36
void mkdir(const std::string& path) { fs::create_directory(path); }37
void makedirs(const std::string& path) { fs::create_directories(path); }38
void rmdir(const std::string& path) { fs::remove(path); }39
bool remove(const std::string& path) { return fs::remove(path); }40
void rename(const std::string& src, const std::string& dst) { fs::rename(src, dst); }42
std::string getenv(const std::string& name, const std::string& fallback) {43
const char* v = std::getenv(name.c_str());44
return (v != nullptr) ? std::string(v) : fallback;45
}46
void setenv(const std::string& name, const std::string& value, bool overwrite) {47
#if defined(_WIN32)48
if (!overwrite && std::getenv(name.c_str()) != nullptr) return; // _putenv_s always overwrites49
::_putenv_s(name.c_str(), value.c_str());50
#else51
::setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0);52
#endif53
}55
#if defined(_WIN32)56
int getpid() { return static_cast<int>(::_getpid()); }57
#else58
int getpid() { return static_cast<int>(::getpid()); }59
#endif60
unsigned cpu_count() { return std::thread::hardware_concurrency(); }61
int system(const std::string& command) { return std::system(command.c_str()); }63
std::string urandom(int n) {64
if (n < 0) throw std::invalid_argument("os.urandom: negative byte count");65
std::string out(static_cast<std::size_t>(n), '\0');66
if (n == 0) return out;67
#if defined(_WIN32)68
if (::BCryptGenRandom(nullptr, reinterpret_cast<PUCHAR>(out.data()),69
static_cast<ULONG>(out.size()),70
BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0)71
throw std::runtime_error("os.urandom: BCryptGenRandom failed");72
#else73
// getentropy is limited to 256 bytes per call; loop for larger requests. A nonzero74
// return means the OS could not supply randomness — fail loudly rather than hand back75
// predictable bytes that a caller might turn into a key.76
std::size_t off = 0;77
while (off < out.size()) {78
const std::size_t chunk = std::min<std::size_t>(out.size() - off, 256);79
if (::getentropy(out.data() + off, chunk) != 0) throw std::runtime_error("os.urandom: getentropy failed");80
off += chunk;81
}82
#endif83
return out;84
}86
std::string module_ext() {87
#if defined(_WIN32)88
return ".dll";89
#elif defined(__APPLE__)90
return ".dylib";91
#else92
return ".so";93
#endif94
}96
namespace path {98
bool exists(const std::string& p) { return fs::exists(p); }99
bool isfile(const std::string& p) { return fs::is_regular_file(p); }100
bool isdir(const std::string& p) { return fs::is_directory(p); }101
std::string basename(const std::string& p) { return fs::path(p).filename().string(); }102
std::string dirname(const std::string& p) { return fs::path(p).parent_path().string(); }103
std::string abspath(const std::string& p) { return fs::absolute(p).string(); }104
std::string normpath(const std::string& p) { return fs::path(p).lexically_normal().string(); }105
std::uintmax_t getsize(const std::string& p) { return fs::file_size(p); }107
std::pair<std::string, std::string> splitext(const std::string& p) {108
const std::string ext = fs::path(p).extension().string();109
if (ext.empty()) {110
return {p, ""};111
}112
return {p.substr(0, p.size() - ext.size()), ext};113
}115
} // namespace path116
} // namespace cheatah::os