Klammertext runs natively on Windows; a Windows source-install guide; the bundled sh for @eval :shell

Assembled from klammertext-dev f344a37d0f6e. The commands, the library,
the Standard Klammer Set, the reflection klammerset and the Python
binding build and run natively on Windows (MSYS2 UCRT64 gcc, python.org
Python), and both test tiers pass there. doc/install/windows_source_install.md
is the fifth install guide: a source install parallel to the Linux and
macOS ones, verified by following it on a pristine Windows 11.

Behaviour on every system: paths Klammertext prints use forward slashes;
output is LF; the command line is UTF-8 on Windows; @eval :shell is a
POSIX shell command everywhere -- on Windows it runs the sh Klammertext
ships, BusyBox for Windows (win/busybox/, GPLv2, with its licence and the
source pointer). KLAMMERTEXT_FONTS and KLAMMERTEXT_KLAMMERSETS are lists in
the system's PATH convention (';' on Windows). On Linux and macOS nothing
observable changes.
This commit is contained in:
ack committed 2026-09-25 00:32:55 +02:00
1 parent f9af1ff869
commit fe475e774a
55 files changed
+1182 -153

No files matched your search

+71 -6
View File
@@ -33,7 +33,7 @@ std::string absolute_pathname(const std::string& filename, const std::string& ba
{
fs::path p(filename);
if (filename.empty()) {
return fs::current_path().string();
return fs::current_path().generic_string();
}
if (!base.empty()) {
// Resolve filename relative to base's directory
@@ -41,7 +41,7 @@ std::string absolute_pathname(const std::string& filename, const std::string& ba
fs::path base_dir = fs::is_directory(b) ? b : b.parent_path();
p = base_dir / p;
}
return fs::absolute(p).string();
return fs::absolute(p).generic_string();
}
std::string relative_pathname(const std::string& filename)
@@ -70,6 +70,66 @@ size_t count_substrings(const std::string& text, const std::string& substring) {
return count;
}
std::string home_directory()
{
if (const char* home = std::getenv("HOME"); home && *home) {
return home;
}
#ifdef _WIN32
if (const char* profile = std::getenv("USERPROFILE"); profile && *profile) {
return profile;
}
#endif
return {};
}
std::string find_in_path(const std::string& program)
{
const char* path = std::getenv("PATH");
if (path == nullptr) {
return {};
}
std::stringstream ss(path);
std::string dir;
while (std::getline(ss, dir, path_list_separator)) {
if (dir.empty()) {
continue;
}
fs::path candidate = fs::path(dir) / program;
std::error_code ec {};
if (fs::is_regular_file(candidate, ec)) {
return candidate.generic_string();
}
#ifdef _WIN32
fs::path exe = candidate;
exe += ".exe";
if (fs::is_regular_file(exe, ec)) {
return exe.generic_string();
}
#endif
}
return {};
}
std::vector<std::string> directory_list(const char* variable, const std::string& default_subdir)
{
std::string paths {};
if (const char* env = std::getenv(variable); env && *env) {
paths = env;
} else if (std::string home = home_directory(); !home.empty()) {
paths = home + "/" + default_subdir;
}
std::vector<std::string> result {};
std::stringstream ss(paths);
std::string dir;
while (std::getline(ss, dir, path_list_separator)) {
if (!dir.empty()) {
result.push_back(dir);
}
}
return result;
}
fs::path relative_to_cwd(const fs::path& input)
{
const auto base = fs::current_path();
@@ -289,8 +349,10 @@ std::string string_from_file(const std::string& pathname, bool strip_surrounding
void string_to_file(const std::string& pathname, std::string contents)
{
fs::create_directories(file_directory(fs::absolute(pathname)));
std::ofstream out(pathname);
fs::create_directories(file_directory(fs::absolute(pathname).string()));
// Binary: the text Klammertext writes ends its lines with LF on every
// system; Windows' text mode would turn each into CRLF.
std::ofstream out(pathname, std::ios::binary);
if (!out) {
throw File_error("Could not write file " + pathname);
}
@@ -319,7 +381,7 @@ strings_t get_files_in_directory(const std::string& dir)
for (const auto& entry : fs::directory_iterator(dir)) {
if (entry.is_regular_file()) {
// std::cout << entry.path().filename() << std::endl;
result.push_back(entry.path().filename());
result.push_back(entry.path().filename().string());
}
}
} catch (const fs::filesystem_error& ex) {
@@ -456,8 +518,11 @@ strings_t get_sks_directories(const std::string& s, bool include_argument)
std::string symbolic_klammertext_filename(std::string filename)
{
// Both in the generic spelling: a Windows KLAMMERTEXT_HOME may be written
// with either separator, and a path Klammertext prints uses '/'.
return string_replace(
filename, get_env_var("KLAMMERTEXT_HOME"), "$KLAMMERTEXT_HOME");
fs::path(filename).generic_string(),
fs::path(get_env_var("KLAMMERTEXT_HOME")).generic_string(), "$KLAMMERTEXT_HOME");
}