11module;
22
33#ifdef _MSC_VER
4- # include <Windows .h >
4+ # include <Windows .h >
55#else
6- # include <stdlib .h >
7- # include <unistd .h >
6+ # include <stdlib .h >
7+ # include <unistd .h >
88#endif
99
1010export module cpp2b;
@@ -13,9 +13,9 @@ import std;
1313import std.compat;
1414
1515#ifdef _MSC_VER
16- extern char ** _environ;
16+ extern char** _environ;
1717#else
18- extern "C" char ** environ;
18+ extern "C" char** environ;
1919#endif
2020
2121export namespace cpp2b {
@@ -26,193 +26,227 @@ enum class compilation_type { debug, optimized, fast };
2626
2727constexpr auto host_platform() -> platform {
2828#if defined(_WIN32)
29- return platform::windows;
29+ return platform::windows;
3030#elif defined(__APPLE__)
31- return platform::macos;
31+ return platform::macos;
3232#elif defined(__linux__)
33- return platform::linux;
33+ return platform::linux;
3434#else
35- # error unknown platform
35+ # error unknown platform
3636#endif
3737}
3838
3939constexpr auto target_platform() -> platform {
40- return host_platform();
40+ return host_platform();
4141}
4242
4343constexpr auto compiler() -> compiler_type {
4444#if defined(_MSC_VER)
45- return compiler_type::msvc;
45+ return compiler_type::msvc;
4646#elif defined(__clang__)
47- return compiler_type::clang;
47+ return compiler_type::clang;
4848#elif defined(__GNUC__)
49- return compiler_type::gcc;
49+ return compiler_type::gcc;
5050#else
51- # error unknown compiler
51+ # error unknown compiler
5252#endif
5353}
5454} // namespace cpp2b
5555
5656export namespace cpp2b::env {
5757inline auto set_var(const std::string& name, const std::string& value) -> void {
5858#if defined(_MSC_VER)
59- SetEnvironmentVariableA(name.c_str(), value.c_str());
59+ SetEnvironmentVariableA(name.c_str(), value.c_str());
6060#else
61- setenv(name.c_str(), value.c_str(), 1);
61+ setenv(name.c_str(), value.c_str(), 1);
6262#endif
6363}
6464
6565inline auto set_var(auto name, auto value) -> void {
66- return cpp2b::env::set_var(std::string{name} , std::string{ value} );
66+ return cpp2b::env::set_var(std::string{name} , std::string{ value} );
6767}
6868
6969inline auto get_var(const std::string& name) -> std::optional<std::string > {
7070#if defined(_MSC_VER)
71- auto val = std::string{" " } ;
72- val.resize(GetEnvironmentVariableA(name.c_str(), val.data(), 1));
73-
74- if(!val.empty()) {
75- GetEnvironmentVariableA(name.c_str(), val.data(), val.size() + 1);
76- return val;
77- }
71+ DWORD val_len = GetEnvironmentVariableA(name.c_str(), nullptr, 0);
72+ if (val_len == 0) {
73+ return {} ;
74+ }
75+
76+ auto val = std::string(val_len - 1, '\0');
77+ GetEnvironmentVariableA(name.c_str(), val.data(), val_len);
78+ return val;
7879#else
79- auto val = std::getenv(name.c_str());
80- if(val != nullptr) {
81- return std::string{val} ;
82- }
80+ auto val = std::getenv(name.c_str());
81+ if(val != nullptr) {
82+ return std::string{val} ;
83+ }
8384#endif
8485
85- return { } ;
86+ return { } ;
8687}
8788
8889inline auto get_var(auto name) -> std::optional<std::string > {
89- return cpp2b::env::get_var(std::string{name} );
90+ return cpp2b::env::get_var(std::string{name} );
9091}
9192
9293class vars {
9394public:
94- struct entry {
95- std::string_view name;
96- std::string_view value;
97- } ;
98-
99- class iterator {
100- public:
101- using iterator_category = std::forward_iterator_tag;
102- using value_type = entry;
103- using difference_type = std::ptrdiff_t;
104- using pointer = const value_type*;
105- using reference = const value_type&;
106-
107- iterator(char** env) : env_(env) {
108- if (env_ && *env_) {
109- update_entry();
110- }
111- }
112-
113- reference operator*() const noexcept {
114- return current_entry_;
115- }
116-
117- pointer operator->() const noexcept {
118- return ¤t_entry_;
119- }
120-
121- iterator& operator++() noexcept {
122- if (env_ && *env_) {
123- ++env_;
124- if (*env_) {
125- update_entry();
126- } else {
127- env_ = nullptr; // end of iteration
128- }
129- }
130- return *this;
131- }
132-
133- iterator operator++(int) noexcept {
134- iterator temp = *this;
135- ++(*this);
136- return temp;
137- }
138-
139- friend bool operator==(const iterator& a, const iterator& b) noexcept {
140- return a.env_ == b.env_;
141- }
142-
143- friend bool operator!=(const iterator& a, const iterator& b) noexcept {
144- return ! (a == b);
145- }
146-
147- private:
148- void update_entry() noexcept {
149- if (env_ && *env_) {
150- std::string_view env_str(*env_);
151- auto pos = env_str.find(' =' );
152- if (pos != std::string_view::npos) {
153- current_entry_.name = env_str.substr(0, pos);
154- current_entry_.value = env_str.substr(pos + 1);
155- }
156- }
157- }
158-
159- char** env_ = nullptr;
160- value_type current_entry_;
161- };
162-
163- iterator begin() const noexcept {
95+ struct entry {
96+ std::string_view name;
97+ std::string_view value;
98+ } ;
99+
100+ class iterator {
101+ public:
102+ using iterator_category = std::forward_iterator_tag;
103+ using value_type = entry;
104+ using difference_type = std::ptrdiff_t;
105+ using pointer = const value_type*;
106+ using reference = const value_type&;
107+
108+ iterator(char** env) : env_(env) {
109+ if (env_ && *env_) {
110+ update_entry();
111+ }
112+ }
113+
114+ reference operator*() const noexcept {
115+ return current_entry_;
116+ }
117+
118+ pointer operator->() const noexcept {
119+ return ¤t_entry_;
120+ }
121+
122+ iterator& operator++() noexcept {
123+ if (env_ && *env_) {
124+ ++env_;
125+ if (*env_) {
126+ update_entry();
127+ } else {
128+ env_ = nullptr; // end of iteration
129+ }
130+ }
131+ return *this;
132+ }
133+
134+ iterator operator++(int) noexcept {
135+ iterator temp = *this;
136+ ++(*this);
137+ return temp;
138+ }
139+
140+ friend bool operator==(const iterator& a, const iterator& b) noexcept {
141+ return a.env_ == b.env_;
142+ }
143+
144+ friend bool operator!=(const iterator& a, const iterator& b) noexcept {
145+ return ! (a == b);
146+ }
147+
148+ private:
149+ void update_entry() noexcept {
150+ if (env_ && *env_) {
151+ std::string_view env_str(*env_);
152+ auto pos = env_str.find(' =' );
153+ if (pos != std::string_view::npos) {
154+ current_entry_.name = env_str.substr(0, pos);
155+ current_entry_.value = env_str.substr(pos + 1);
156+ }
157+ }
158+ }
159+
160+ char** env_ = nullptr;
161+ value_type current_entry_;
162+ };
163+
164+ iterator begin() const noexcept {
164165#ifdef _MSC_VER
165- return iterator(_environ);
166+ return iterator(_environ);
166167#else
167- return iterator(environ);
168+ return iterator(environ);
168169#endif
169- }
170+ }
170171
171- iterator end() const noexcept {
172- return iterator(nullptr);
173- }
172+ iterator end() const noexcept {
173+ return iterator(nullptr);
174+ }
174175};
175176
176177std::filesystem::path executable_path() {
177- static std::string executable_path_str;
178+ static std::string executable_path_str;
178179
179- if (! executable_path_str.empty()) {
180- return executable_path_str;
181- }
180+ if (! executable_path_str.empty()) {
181+ return executable_path_str;
182+ }
182183
183- auto size = 260;
184- auto buffer = std::vector<char >(size);
184+ auto size = 260;
185+ auto buffer = std::vector<char >(size);
185186
186187#if defined(_WIN32)
187- for (;;) {
188- DWORD len = GetModuleFileNameA(NULL, buffer.data(), size);
189- if (len == 0) {
190- executable_path_str = {} ;
191- return executable_path_str;
192- } else if (len < size - 1) {
193- executable_path_str = std::string(buffer.data(), len);
194- return executable_path_str;
195- }
196-
197- size += 260;
198- buffer.resize(size);
199- }
188+ for (;;) {
189+ DWORD len = GetModuleFileNameA(NULL, buffer.data(), size);
190+ if (len == 0) {
191+ executable_path_str = {} ;
192+ return executable_path_str;
193+ } else if(len < size - 1) {
194+ executable_path_str = std::string(buffer.data(), len);
195+ return executable_path_str;
196+ }
197+
198+ size += 260;
199+ buffer.resize(size);
200+ }
200201#elif defined(__linux__)
201- for (;;) {
202- ssize_t len = readlink(" /proc/self/exe" , buffer.data(), size - 1);
203- if (len < 0) {
204- executable_path_str = {} ;
205- return executable_path_str;
206- } else if (len < size - 1) {
207- executable_path_str = std::string(buffer.data(), len);
208- return executable_path_str;
209- }
210-
211- size += 260;
212- buffer.resize(size);
213- }
202+ for (;;) {
203+ ssize_t len = readlink(" /proc/self/exe" , buffer.data(), size - 1);
204+ if (len < 0) {
205+ executable_path_str = {} ;
206+ return executable_path_str;
207+ } else if(len < size - 1) {
208+ executable_path_str = std::string(buffer.data(), len);
209+ return executable_path_str;
210+ }
211+
212+ size += 260;
213+ buffer.resize(size);
214+ }
214215#else
215- # error unhandled executable_path platform
216+ # error unhandled executable_path platform
216217#endif
217218}
219+ } // namespace cpp2b::env
220+
221+ export namespace cpp2b::os {
222+ auto get_last_error() -> std::string {
223+ #if defined(_WIN32)
224+ DWORD errorMessageID = ::GetLastError();
225+ if (errorMessageID == 0) {
226+ return {} ; // No error
227+ }
228+
229+ LPSTR messageBuffer = nullptr;
230+
231+ size_t size = FormatMessageA(
232+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
233+ FORMAT_MESSAGE_IGNORE_INSERTS,
234+ nullptr,
235+ errorMessageID,
236+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
237+ (LPSTR)&messageBuffer,
238+ 0,
239+ nullptr
240+ );
241+
242+ auto message = std::string{ messageBuffer, size - 1} ;
243+
244+ LocalFree(messageBuffer);
245+
246+ return message;
247+ #else
248+ // TODO: other platforms
249+ return "";
250+ #endif
218251}
252+ } // namespace cpp2b::os
0 commit comments