From 13d7c09125f8eec703d0a43a9a87fc8aa08f7319 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 12 Jan 2021 12:17:30 +0100 Subject: Libraries: Move to Userland/Libraries/ --- Libraries/LibCore/Account.cpp | 316 ---------- Libraries/LibCore/Account.h | 109 ---- Libraries/LibCore/ArgsParser.cpp | 392 ------------ Libraries/LibCore/ArgsParser.h | 94 --- Libraries/LibCore/CMakeLists.txt | 37 -- Libraries/LibCore/Command.cpp | 127 ---- Libraries/LibCore/Command.h | 40 -- Libraries/LibCore/ConfigFile.cpp | 242 -------- Libraries/LibCore/ConfigFile.h | 82 --- Libraries/LibCore/DateTime.cpp | 263 -------- Libraries/LibCore/DateTime.h | 74 --- Libraries/LibCore/DirIterator.cpp | 121 ---- Libraries/LibCore/DirIterator.h | 65 -- Libraries/LibCore/DirectoryWatcher.cpp | 98 --- Libraries/LibCore/DirectoryWatcher.h | 61 -- Libraries/LibCore/ElapsedTimer.cpp | 57 -- Libraries/LibCore/ElapsedTimer.h | 54 -- Libraries/LibCore/Event.cpp | 72 --- Libraries/LibCore/Event.h | 159 ----- Libraries/LibCore/EventLoop.cpp | 835 ------------------------- Libraries/LibCore/EventLoop.h | 122 ---- Libraries/LibCore/File.cpp | 270 --------- Libraries/LibCore/File.h | 78 --- Libraries/LibCore/FileStream.h | 171 ------ Libraries/LibCore/Forward.h | 61 -- Libraries/LibCore/GetPassword.cpp | 70 --- Libraries/LibCore/GetPassword.h | 37 -- Libraries/LibCore/Gzip.cpp | 165 ----- Libraries/LibCore/Gzip.h | 41 -- Libraries/LibCore/IODevice.cpp | 336 ----------- Libraries/LibCore/IODevice.h | 133 ---- Libraries/LibCore/IODeviceStreamReader.h | 61 -- Libraries/LibCore/LocalServer.cpp | 161 ----- Libraries/LibCore/LocalServer.h | 57 -- Libraries/LibCore/LocalSocket.cpp | 107 ---- Libraries/LibCore/LocalSocket.h | 45 -- Libraries/LibCore/MimeData.cpp | 102 ---- Libraries/LibCore/MimeData.h | 72 --- Libraries/LibCore/NetworkJob.cpp | 108 ---- Libraries/LibCore/NetworkJob.h | 83 --- Libraries/LibCore/NetworkResponse.cpp | 39 -- Libraries/LibCore/NetworkResponse.h | 46 -- Libraries/LibCore/Notifier.cpp | 76 --- Libraries/LibCore/Notifier.h | 66 -- Libraries/LibCore/Object.cpp | 270 --------- Libraries/LibCore/Object.h | 346 ----------- Libraries/LibCore/ProcessStatisticsReader.cpp | 142 ----- Libraries/LibCore/ProcessStatisticsReader.h | 98 --- Libraries/LibCore/Property.cpp | 42 -- Libraries/LibCore/Property.h | 59 -- Libraries/LibCore/Socket.cpp | 236 -------- Libraries/LibCore/Socket.h | 89 --- Libraries/LibCore/SocketAddress.cpp | 36 -- Libraries/LibCore/SocketAddress.h | 115 ---- Libraries/LibCore/StandardPaths.cpp | 77 --- Libraries/LibCore/StandardPaths.h | 42 -- Libraries/LibCore/SyscallUtils.h | 56 -- Libraries/LibCore/TCPServer.cpp | 125 ---- Libraries/LibCore/TCPServer.h | 58 -- Libraries/LibCore/TCPSocket.cpp | 70 --- Libraries/LibCore/TCPSocket.h | 44 -- Libraries/LibCore/Timer.cpp | 96 --- Libraries/LibCore/Timer.h | 81 --- Libraries/LibCore/UDPServer.cpp | 123 ---- Libraries/LibCore/UDPServer.h | 66 -- Libraries/LibCore/UDPSocket.cpp | 61 -- Libraries/LibCore/UDPSocket.h | 42 -- Libraries/LibCore/puff.cpp | 840 -------------------------- Libraries/LibCore/puff.h | 44 -- 69 files changed, 9063 deletions(-) delete mode 100644 Libraries/LibCore/Account.cpp delete mode 100644 Libraries/LibCore/Account.h delete mode 100644 Libraries/LibCore/ArgsParser.cpp delete mode 100644 Libraries/LibCore/ArgsParser.h delete mode 100644 Libraries/LibCore/CMakeLists.txt delete mode 100644 Libraries/LibCore/Command.cpp delete mode 100644 Libraries/LibCore/Command.h delete mode 100644 Libraries/LibCore/ConfigFile.cpp delete mode 100644 Libraries/LibCore/ConfigFile.h delete mode 100644 Libraries/LibCore/DateTime.cpp delete mode 100644 Libraries/LibCore/DateTime.h delete mode 100644 Libraries/LibCore/DirIterator.cpp delete mode 100644 Libraries/LibCore/DirIterator.h delete mode 100644 Libraries/LibCore/DirectoryWatcher.cpp delete mode 100644 Libraries/LibCore/DirectoryWatcher.h delete mode 100644 Libraries/LibCore/ElapsedTimer.cpp delete mode 100644 Libraries/LibCore/ElapsedTimer.h delete mode 100644 Libraries/LibCore/Event.cpp delete mode 100644 Libraries/LibCore/Event.h delete mode 100644 Libraries/LibCore/EventLoop.cpp delete mode 100644 Libraries/LibCore/EventLoop.h delete mode 100644 Libraries/LibCore/File.cpp delete mode 100644 Libraries/LibCore/File.h delete mode 100644 Libraries/LibCore/FileStream.h delete mode 100644 Libraries/LibCore/Forward.h delete mode 100644 Libraries/LibCore/GetPassword.cpp delete mode 100644 Libraries/LibCore/GetPassword.h delete mode 100644 Libraries/LibCore/Gzip.cpp delete mode 100644 Libraries/LibCore/Gzip.h delete mode 100644 Libraries/LibCore/IODevice.cpp delete mode 100644 Libraries/LibCore/IODevice.h delete mode 100644 Libraries/LibCore/IODeviceStreamReader.h delete mode 100644 Libraries/LibCore/LocalServer.cpp delete mode 100644 Libraries/LibCore/LocalServer.h delete mode 100644 Libraries/LibCore/LocalSocket.cpp delete mode 100644 Libraries/LibCore/LocalSocket.h delete mode 100644 Libraries/LibCore/MimeData.cpp delete mode 100644 Libraries/LibCore/MimeData.h delete mode 100644 Libraries/LibCore/NetworkJob.cpp delete mode 100644 Libraries/LibCore/NetworkJob.h delete mode 100644 Libraries/LibCore/NetworkResponse.cpp delete mode 100644 Libraries/LibCore/NetworkResponse.h delete mode 100644 Libraries/LibCore/Notifier.cpp delete mode 100644 Libraries/LibCore/Notifier.h delete mode 100644 Libraries/LibCore/Object.cpp delete mode 100644 Libraries/LibCore/Object.h delete mode 100644 Libraries/LibCore/ProcessStatisticsReader.cpp delete mode 100644 Libraries/LibCore/ProcessStatisticsReader.h delete mode 100644 Libraries/LibCore/Property.cpp delete mode 100644 Libraries/LibCore/Property.h delete mode 100644 Libraries/LibCore/Socket.cpp delete mode 100644 Libraries/LibCore/Socket.h delete mode 100644 Libraries/LibCore/SocketAddress.cpp delete mode 100644 Libraries/LibCore/SocketAddress.h delete mode 100644 Libraries/LibCore/StandardPaths.cpp delete mode 100644 Libraries/LibCore/StandardPaths.h delete mode 100644 Libraries/LibCore/SyscallUtils.h delete mode 100644 Libraries/LibCore/TCPServer.cpp delete mode 100644 Libraries/LibCore/TCPServer.h delete mode 100644 Libraries/LibCore/TCPSocket.cpp delete mode 100644 Libraries/LibCore/TCPSocket.h delete mode 100644 Libraries/LibCore/Timer.cpp delete mode 100644 Libraries/LibCore/Timer.h delete mode 100644 Libraries/LibCore/UDPServer.cpp delete mode 100644 Libraries/LibCore/UDPServer.h delete mode 100644 Libraries/LibCore/UDPSocket.cpp delete mode 100644 Libraries/LibCore/UDPSocket.h delete mode 100644 Libraries/LibCore/puff.cpp delete mode 100644 Libraries/LibCore/puff.h (limited to 'Libraries/LibCore') diff --git a/Libraries/LibCore/Account.cpp b/Libraries/LibCore/Account.cpp deleted file mode 100644 index 7e4d40669a..0000000000 --- a/Libraries/LibCore/Account.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Core { - -static String get_salt() -{ - char random_data[12]; - AK::fill_with_random(random_data, sizeof(random_data)); - - StringBuilder builder; - builder.append("$5$"); - builder.append(encode_base64(ReadonlyBytes(random_data, sizeof(random_data)))); - - return builder.build(); -} - -static Vector get_gids(const StringView& username) -{ - Vector extra_gids; - for (auto* group = getgrent(); group; group = getgrent()) { - for (size_t i = 0; group->gr_mem[i]; ++i) { - if (username == group->gr_mem[i]) { - extra_gids.append(group->gr_gid); - break; - } - } - } - endgrent(); - return extra_gids; -} - -Result Account::from_passwd(const passwd& pwd, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - RefPtr passwd_file; - if (open_passwd_file != Core::Account::OpenPasswdFile::No) { - auto open_mode = open_passwd_file == Core::Account::OpenPasswdFile::ReadOnly - ? Core::File::OpenMode::ReadOnly - : Core::File::OpenMode::ReadWrite; - auto file_or_error = Core::File::open("/etc/passwd", open_mode); - if (file_or_error.is_error()) - return file_or_error.error(); - passwd_file = file_or_error.value(); - } - - RefPtr shadow_file; - if (open_shadow_file != Core::Account::OpenShadowFile::No) { - auto open_mode = open_shadow_file == Core::Account::OpenShadowFile::ReadOnly - ? Core::File::OpenMode::ReadOnly - : Core::File::OpenMode::ReadWrite; - auto file_or_error = Core::File::open("/etc/shadow", open_mode); - if (file_or_error.is_error()) - return file_or_error.error(); - shadow_file = file_or_error.value(); - } - - Account account(pwd, get_gids(pwd.pw_name), move(passwd_file), move(shadow_file)); - endpwent(); - return account; -} - -Result Account::from_name(const char* username, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - struct passwd* pwd = nullptr; - errno = 0; - pwd = getpwnam(username); - if (!pwd) { - if (errno == 0) - return String("No such user"); - - return String(strerror(errno)); - } - return from_passwd(*pwd, open_passwd_file, open_shadow_file); -} - -Result Account::from_uid(uid_t uid, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - struct passwd* pwd = nullptr; - errno = 0; - pwd = getpwuid(uid); - if (!pwd) { - if (errno == 0) - return String("No such user"); - - return String(strerror(errno)); - } - return from_passwd(*pwd, open_passwd_file, open_shadow_file); -} - -bool Account::authenticate(const char* password) const -{ - // An empty passwd field indicates that no password is required to log in. - if (m_password_hash.is_empty()) - return true; - - // FIXME: Use crypt_r if it can be built in lagom. - char* hash = crypt(password, m_password_hash.characters()); - return hash != nullptr && strcmp(hash, m_password_hash.characters()) == 0; -} - -bool Account::login() const -{ - if (setgroups(m_extra_gids.size(), m_extra_gids.data()) < 0) - return false; - - if (setgid(m_gid) < 0) - return false; - - if (setuid(m_uid) < 0) - return false; - - return true; -} - -void Account::set_password(const char* password) -{ - m_password_hash = crypt(password, get_salt().characters()); -} - -void Account::set_password_enabled(bool enabled) -{ - if (enabled && m_password_hash != "" && m_password_hash[0] == '!') { - m_password_hash = m_password_hash.substring(1, m_password_hash.length() - 1); - } else if (!enabled && (m_password_hash == "" || m_password_hash[0] != '!')) { - StringBuilder builder; - builder.append('!'); - builder.append(m_password_hash); - m_password_hash = builder.build(); - } -} - -void Account::delete_password() -{ - m_password_hash = ""; -} - -Account::Account(const passwd& pwd, Vector extra_gids, RefPtr passwd_file, RefPtr shadow_file) - : m_passwd_file(move(passwd_file)) - , m_shadow_file(move(shadow_file)) - , m_username(pwd.pw_name) - , m_uid(pwd.pw_uid) - , m_gid(pwd.pw_gid) - , m_gecos(pwd.pw_gecos) - , m_home_directory(pwd.pw_dir) - , m_shell(pwd.pw_shell) - , m_extra_gids(extra_gids) -{ - if (m_shadow_file) { - load_shadow_file(); - } -} - -String Account::generate_passwd_file() const -{ - StringBuilder builder; - - setpwent(); - - struct passwd* p; - errno = 0; - while ((p = getpwent())) { - if (p->pw_uid == m_uid) { - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - m_username, - m_uid, m_gid, - m_gecos, - m_home_directory, - m_shell); - - } else { - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - p->pw_name, p->pw_uid, - p->pw_gid, p->pw_gecos, p->pw_dir, - p->pw_shell); - } - } - endpwent(); - - if (errno) { - dbgln("errno was non-zero after generating new passwd file."); - return {}; - } - - return builder.to_string(); -} - -void Account::load_shadow_file() -{ - ASSERT(m_shadow_file); - ASSERT(m_shadow_file->is_open()); - - if (!m_shadow_file->seek(0)) { - ASSERT_NOT_REACHED(); - } - - Vector entries; - - for (;;) { - auto line = m_shadow_file->read_line(); - if (line.is_null()) - break; - auto parts = line.split(':'); - if (parts.size() != 2) { - dbgln("Malformed shadow entry, ignoring."); - continue; - } - const auto& username = parts[0]; - const auto& password_hash = parts[1]; - entries.append({ username, password_hash }); - - if (username == m_username) { - m_password_hash = password_hash; - } - } - - m_shadow_entries = move(entries); -} - -String Account::generate_shadow_file() const -{ - StringBuilder builder; - bool updated_entry_in_place = false; - for (auto& entry : m_shadow_entries) { - if (entry.username == m_username) { - updated_entry_in_place = true; - builder.appendff("{}:{}\n", m_username, m_password_hash); - } else { - builder.appendff("{}:{}\n", entry.username, entry.password_hash); - } - } - if (!updated_entry_in_place) - builder.appendff("{}:{}\n", m_username, m_password_hash); - return builder.to_string(); -} - -bool Account::sync() -{ - ASSERT(m_passwd_file); - ASSERT(m_passwd_file->mode() == Core::File::OpenMode::ReadWrite); - ASSERT(m_shadow_file); - ASSERT(m_shadow_file->mode() == Core::File::OpenMode::ReadWrite); - - // FIXME: Maybe reorganize this to create temporary files and finish it completely before renaming them to /etc/{passwd,shadow} - // If truncation succeeds but write fails, we'll have an empty file :( - - auto new_passwd_file = generate_passwd_file(); - auto new_shadow_file = generate_shadow_file(); - - if (new_passwd_file.is_null() || new_shadow_file.is_null()) { - ASSERT_NOT_REACHED(); - } - - if (!m_passwd_file->seek(0) || !m_shadow_file->seek(0)) { - ASSERT_NOT_REACHED(); - } - - if (!m_passwd_file->truncate(0)) { - dbgln("Truncating passwd file failed."); - return false; - } - - if (!m_passwd_file->write(new_passwd_file)) { - // FIXME: Improve Core::File::write() error reporting. - dbgln("Writing to passwd file failed."); - return false; - } - - if (!m_shadow_file->truncate(0)) { - dbgln("Truncating shadow file failed."); - return false; - } - - if (!m_shadow_file->write(new_shadow_file)) { - // FIXME: Improve Core::File::write() error reporting. - dbgln("Writing to shadow file failed."); - return false; - } - - return true; - // FIXME: Sync extra groups. -} - -} diff --git a/Libraries/LibCore/Account.h b/Libraries/LibCore/Account.h deleted file mode 100644 index fdd7d9bea9..0000000000 --- a/Libraries/LibCore/Account.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace Core { - -class Account { -public: - enum class OpenPasswdFile { - No, - ReadOnly, - ReadWrite, - }; - - enum class OpenShadowFile { - No, - ReadOnly, - ReadWrite, - }; - - static Result from_name(const char* username, OpenPasswdFile = OpenPasswdFile::No, OpenShadowFile = OpenShadowFile::No); - static Result from_uid(uid_t uid, OpenPasswdFile = OpenPasswdFile::No, OpenShadowFile = OpenShadowFile::No); - - bool authenticate(const char* password) const; - bool login() const; - - String username() const { return m_username; } - String password_hash() const { return m_password_hash; } - - // Setters only affect in-memory copy of password. - // You must call sync to apply changes. - void set_password(const char* password); - void set_password_enabled(bool enabled); - void delete_password(); - bool has_password() const { return !m_password_hash.is_empty(); } - - uid_t uid() const { return m_uid; } - gid_t gid() const { return m_gid; } - const String& gecos() const { return m_gecos; } - const String& home_directory() const { return m_home_directory; } - const String& shell() const { return m_shell; } - const Vector& extra_gids() const { return m_extra_gids; } - - bool sync(); - -private: - static Result from_passwd(const passwd&, OpenPasswdFile, OpenShadowFile); - - Account(const passwd& pwd, Vector extra_gids, RefPtr passwd_file, RefPtr shadow_file); - void load_shadow_file(); - - String generate_passwd_file() const; - String generate_shadow_file() const; - - RefPtr m_passwd_file; - RefPtr m_shadow_file; - - String m_username; - - // Contents of passwd field in passwd entry. - // Can be empty, "x", or contain a leading '!' - String m_password_hash; - uid_t m_uid { 0 }; - gid_t m_gid { 0 }; - String m_gecos; - String m_home_directory; - String m_shell; - Vector m_extra_gids; - - struct ShadowEntry { - String username; - String password_hash; - }; - Vector m_shadow_entries; -}; - -} diff --git a/Libraries/LibCore/ArgsParser.cpp b/Libraries/LibCore/ArgsParser.cpp deleted file mode 100644 index 121272e38b..0000000000 --- a/Libraries/LibCore/ArgsParser.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2020, Sergey Bugaev - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -static constexpr bool isnan(double __x) { return __builtin_isnan(__x); } - -static Optional convert_to_double(const char* s) -{ - char* p; - double v = strtod(s, &p); - if (isnan(v) || p == s) - return {}; - return v; -} - -namespace Core { - -ArgsParser::ArgsParser() -{ - add_option(m_show_help, "Display this message", "help", 0); -} - -bool ArgsParser::parse(int argc, char** argv, bool exit_on_failure) -{ - auto print_usage_and_exit = [this, argv, exit_on_failure] { - print_usage(stderr, argv[0]); - if (exit_on_failure) - exit(1); - }; - - Vector