Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# mkn::kul — C++ API Reference

**mkn::kul** (`Make Know Utility Library`) is a modern C++20 utility library providing cross-platform abstractions for threading, I/O, processes, logging, containers, and more.

All public symbols live under the `mkn::kul` namespace (or sub-namespaces noted per section).

---

## Table of Contents

1. [Core Definitions (`defs.hpp`)](#1-core-definitions-defshpp)
2. [Exception Handling (`except.hpp`)](doc/mkn/kul/except.md)
3. [Assertions (`assert.hpp`)](doc/mkn/kul/assert.md)
4. [Type Trait Helpers (`decltype.hpp`)](#4-type-trait-helpers-decltypehpp)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the broken Table of Contents fragment.

Line 14 links to #4-type-trait-helpers-decltypehpp, but API.md has no matching heading. Add the missing section or point this entry to the actual decltype documentation page.

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 14-14: Link fragments should be valid

(MD051, link-fragments)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@API.md` at line 14, Fix the Table of Contents entry for Type Trait Helpers by
either adding the missing matching heading in API.md or updating the link to the
existing decltype documentation section, ensuring the fragment resolves
correctly.

Source: Linters/SAST tools

5. [Span Containers (`span.hpp`)](doc/mkn/kul/span.md)
6. [Custom Allocators (`alloc.hpp`)](doc/mkn/kul/alloc.md)
7. [Vectors with Custom Allocators (`vector.hpp`)](doc/mkn/kul/vector.md)
8. [Byte Utilities (`byte.hpp`)](doc/mkn/kul/byte.md)
9. [String Utilities (`string.hpp`)](doc/mkn/kul/string.md)
10. [Wide String Utilities (`wstring.hpp`)](doc/mkn/kul/wstring.md)
11. [Floating-Point Utilities (`float.hpp`)](doc/mkn/kul/float.md)
12. [Hashing (`hash.hpp`)](doc/mkn/kul/hash.md)
13. [Hash Maps and Sets (`map.hpp`)](doc/mkn/kul/map.md)
14. [Time and Date (`time.hpp`)](doc/mkn/kul/time.md)
15. [Logging (`log.hpp`)](doc/mkn/kul/log.md)
16. [Threading (`threads.hpp`)](doc/mkn/kul/threads.md)
17. [File I/O (`io.hpp`)](doc/mkn/kul/io.md)
18. [Environment Variables (`env.hpp`)](doc/mkn/kul/env.md)
19. [Filesystem Abstractions (`os.hpp`)](doc/mkn/kul/os.md)
20. [Process Management (`proc.hpp`)](doc/mkn/kul/proc.md)
21. [Signal Handling (`signal.hpp`)](doc/mkn/kul/signal.md)
22. [Command-Line Interface (`cli.hpp`)](doc/mkn/kul/cli.md)
23. [Debugging and Stack Traces (`dbg.hpp`)](doc/mkn/kul/dbg.md)
24. [Compile-Time Iteration (`for.hpp`)](doc/mkn/kul/for.md)
25. [Tuple Utilities (`tuple.hpp`)](doc/mkn/kul/tuple.md)
26. [Aggregate Comparison (`all.hpp`)](doc/mkn/kul/all.md)
27. [Zip Iterator (`zip.hpp`)](doc/mkn/kul/zip.md)
28. [Math Utilities (`math.hpp`)](doc/mkn/kul/math.md)
29. [YAML Parsing (`yaml.hpp`)](doc/mkn/kul/yaml.md)
30. [Better Object Notation (`bon.hpp`)](doc/mkn/kul/bon.md)
31. [Source Control Management (`scm.hpp`)](doc/mkn/kul/scm.md)
32. [CPU Utilities (`cpu.hpp`)](doc/mkn/kul/cpu.md)
33. [Inter-Process Communication (`ipc.hpp`)](doc/mkn/kul/ipc.md)
34. [System Utilities (`sys.hpp`)](doc/mkn/kul/sys.md)

---

## 1. Core Definitions (`defs.hpp`)

Platform detection and utility macros.

### Macros

| Macro | Description |
|-------|-------------|
| `MKN_KUL_STR(x)` | Stringify `x` |
| `MKN_KUL_STR_CAT(x, y)` | Token-paste `x` and `y` |
| `MKN_KUL_PUBLISH` | Mark a symbol for DLL export / `visibility("default")` |
| `MKN_KUL_PRIVATE` | Mark a symbol as `visibility("hidden")` |
| `MKN_KUL_IS_WIN` | `1` on Windows, `0` otherwise |
| `MKN_KUL_IS_NIX` | `1` on Linux, `0` otherwise |
| `MKN_KUL_IS_BSD` | `1` on BSD, `0` otherwise |
| `MKN_KUL_DEBUG_DO(...)` | Expands to `__VA_ARGS__` in debug builds; empty in release |
| `MKN_KUL_DEBUG_DO_ELSE(...)` | Inverse of `MKN_KUL_DEBUG_DO` |

---

## Environment Variables

| Variable | Effect |
|----------|--------|
| `KLOG` | Log verbosity: `0`=off, `1`=INF, `2`=ERR, `3`=DBG, `4`=OTH, `5`=TRC |
| `MKN_KUL_GIT_CO` | Extra args passed to `git clone` during dependency fetch |

---

## Platform Notes

| Header | Windows | Linux | BSD |
|--------|---------|-------|-----|
| `cpu.hpp` | `os/win/cpu.hpp` | `os/nix/cpu.hpp` | `os/bsd/cpu.hpp` |
| `env.hpp` | `os/win/env.hpp` | `os/nixish/env.hpp` | `os/nixish/env.hpp` |
| `ipc.hpp` | `os/win/ipc.hpp` | `os/nixish/ipc.hpp` | `os/nixish/ipc.hpp` |
| `signal.hpp` | `os/win/signal.hpp` | `os/nixish/signal.hpp` | `os/nixish/signal.hpp` |
| `sys.hpp` | `os/win/sys.hpp` | `os/nixish/sys.hpp` | `os/nixish/sys.hpp` |
| `proc.hpp` | `os/win/proc.hpp` | `os/nixish/proc.hpp` + `os/nix/proc.os.hpp` | similar |
| `threads.hpp` | `os/win/threads.os.hpp` | `os/nixish/threads.os.hpp` | similar |
16 changes: 9 additions & 7 deletions inc/mkn/kul/os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,21 +205,23 @@ class File : public fs::Item {

public:
File() : _n(), _d() {}
File(std::string const& n, bool m = false) : _n(Dir::LOCL(n)), _d(env::CWD()) {
File(std::string const& n, bool m = false) : _n(Dir::LOCL(n)) {
// _d starts empty so is() stats _n as-given (Dir::join returns it unprefixed),
// correctly resolving both absolute and CWD-relative input before any CWD default is applied.
if (is()) {
try {
this->_n = Dir::REAL(this->_n);
this->_d = Dir(Dir::PRNT(this->_n), m);
this->_n = this->_n.substr(_d.path().size() + 1);
} catch (mkn::kul::fs::Exception const& e) {
}
} else if (n.find(Dir::SEP()) != std::string::npos) {
this->_d = Dir(n.substr(0, n.rfind(Dir::SEP())));
this->_n = this->_n.substr(n.rfind(Dir::SEP()) + 1);
} else if (auto const& _N = Dir::REAL_OR_NULL(this->_n)) {
this->_d = Dir(Dir::PRNT(*_N), m);
} else {
if (n.find(Dir::SEP()) != std::string::npos) {
this->_d = Dir(n.substr(0, n.rfind(Dir::SEP())));
this->_n = this->_n.substr(n.rfind(Dir::SEP()) + 1);
} else {
if (auto const& _N = Dir::REAL_OR_NULL(this->_n)) this->_d = Dir(Dir::PRNT(*_N), m);
}
this->_d = Dir(env::CWD());
}
}
File(char const* n, bool m = false) : File(std::string(n), m) {}
Expand Down
4 changes: 1 addition & 3 deletions inc/mkn/kul/scm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ class SCM {
virtual std::string defaultRemoteBranch(std::string const& repo) const = 0;
};

// review https://gist.github.com/aleksey-bykov/1273f4982c317c92d532
namespace scm {

class Git : public SCM {
public:
std::string defaultRemoteBranch(std::string const& repo) const override {
Expand All @@ -85,14 +85,12 @@ class Git : public SCM {
p << "ls-remote"
<< "--symref" << repo << "HEAD";
try {
KLOG(TRC) << p;
p.start();
} catch (mkn::kul::proc::ExitException const& e) {
KEXCEPT(Exception, "SCM ERROR - Checking local branch") << p.toString();
}
auto const lines = mkn::kul::String::LINES(pc.outs());
if (lines.empty()) return {};
KLOG(TRC) << lines[0];
// "ref: refs/heads/master\tHEAD" -> "master"
auto ret = mkn::kul::String::SPLIT(lines[0], "/").back();
auto const tab = ret.find('\t');
Expand Down
57 changes: 57 additions & 0 deletions tst/test/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,60 @@ TEST(OperatingSystemTests, HasFileModifiedTimeStampSupport) {
ASSERT_TRUE(TimeStampHandler::INSTANCE().is());
ASSERT_TRUE(TimeStampHandler::INSTANCE().timeStamps().modified());
}

TEST(OperatingSystemTests, FileAbsolutePathMatchesRelativeForTopLevelFile) {
mkn::kul::File const relative("mkn.yaml");
ASSERT_TRUE(relative.is());
mkn::kul::File const absolute(relative.real());
EXPECT_TRUE(absolute.is());
EXPECT_EQ(relative.name(), absolute.name());
EXPECT_EQ(relative.real(), absolute.real());
EXPECT_EQ(relative.dir().real(), absolute.dir().real());
EXPECT_EQ(relative.size(), absolute.size());
}

TEST(OperatingSystemTests, FileAbsolutePathMatchesRelativeForNestedFile) {
mkn::kul::File const relative("inc/mkn/kul/os.hpp");
ASSERT_TRUE(relative.is());
mkn::kul::File const absolute(relative.real());
EXPECT_TRUE(absolute.is());
EXPECT_EQ(relative.name(), absolute.name());
EXPECT_EQ(relative.real(), absolute.real());
EXPECT_EQ(relative.dir().real(), absolute.dir().real());
EXPECT_EQ(relative.size(), absolute.size());
}

TEST(OperatingSystemTests, FileAbsolutePathResolvesRegardlessOfCWD) {
mkn::kul::File const relative("LICENSE.md");
ASSERT_TRUE(relative.is());
std::string const absPath = relative.real();

mkn::kul::os::PushDir const pd(mkn::kul::Dir("inc"));
mkn::kul::File const absolute(absPath);
EXPECT_TRUE(absolute.is());
EXPECT_EQ(absPath, absolute.real());
}

TEST(OperatingSystemTests, FileAbsolutePathIsCanonicalized) {
std::string const messy =
mkn::kul::env::CWD() + mkn::kul::Dir::SEP() + mkn::kul::Dir::SEP() + "mkn.yaml";
mkn::kul::File const f(messy);
ASSERT_TRUE(f.is());
EXPECT_EQ("mkn.yaml", f.name());
EXPECT_EQ(mkn::kul::Dir(mkn::kul::env::CWD()).path(), f.dir().path());
}

TEST(OperatingSystemTests, FileAbsoluteNonExistentPathSplitsDirAndName) {
std::string const absPath =
mkn::kul::env::CWD() + mkn::kul::Dir::SEP() + "does_not_exist_kul_os_test.txt";
mkn::kul::File const f(absPath);
EXPECT_FALSE(f.is());
EXPECT_EQ("does_not_exist_kul_os_test.txt", f.name());
EXPECT_EQ(mkn::kul::env::CWD(), f.dir().path());
}

TEST(OperatingSystemTests, FileBareNonExistentNameDefaultsToCWD) {
mkn::kul::File const f("does_not_exist_kul_os_test.txt");
EXPECT_FALSE(f.is());
EXPECT_EQ(mkn::kul::Dir(mkn::kul::env::CWD()).real(), f.dir().real());
}
Loading