From 4a13df61b92b8bf673f8a71d5fa0abf0356a4899 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Thu, 10 Mar 2022 12:39:04 +0500 Subject: add Doxygen docs --- CMakeLists.txt | 11 ++++++++ Makefile | 9 +++++++ README.md | 7 +++++ include/winapi/buffer.hpp | 14 ++++++++++ include/winapi/cmd_line.hpp | 60 +++++++++++++++++++++++++++++++++++++++++-- include/winapi/error.hpp | 10 ++++++++ include/winapi/file.hpp | 22 ++++++++++++++++ include/winapi/handle.hpp | 32 ++++++++++++++++++++++- include/winapi/path.hpp | 2 ++ include/winapi/pipe.hpp | 6 +++++ include/winapi/process.hpp | 34 +++++++++++++++++++++++- include/winapi/process_io.hpp | 16 ++++++++++++ include/winapi/resource.hpp | 2 ++ include/winapi/shmem.hpp | 24 +++++++++++++++++ 14 files changed, 245 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 035ea3a..86ca24a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,3 +29,14 @@ if(WINAPI_COMMON_TESTS) endif() install(FILES LICENSE.txt DESTINATION share) + +find_package(Doxygen) +if(DOXYGEN_FOUND) + set(DOXYGEN_INCLUDE_GRAPH NO) + set(DOXYGEN_INCLUDED_BY_GRAPH NO) + set(DOXYGEN_SHOW_INCLUDE_FILES NO) + set(DOXYGEN_SORT_MEMBER_DOCS NO) + set(DOXYGEN_SOURCE_BROWSER YES) + set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) + doxygen_add_docs(docs README.md ${winapi_common_include} ${winapi_common_src}) +endif() diff --git a/Makefile b/Makefile index f3a99d8..64c45fd 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,15 @@ install: build test: cd -- '$(call escape,$(cmake_dir))' && ctest -C '$(call escape,$(CONFIGURATION))' --verbose +xdg-open := $(shell command -v xdg-open 2> /dev/null) + +.PHONY: docs +docs: + cmake --build '$(call escape,$(cmake_dir))' --target docs +ifdef xdg-open + xdg-open '$(call escape,$(cmake_dir))/html/index.html' &> /dev/null +endif + clang-tidy := run-clang-tidy ifeq (1,$(shell test -e /usr/share/clang/run-clang-tidy.py && echo 1)) clang-tidy := /usr/share/clang/run-clang-tidy.py diff --git a/README.md b/README.md index abb9774..67212e8 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,13 @@ directory (defaults to building with MinGW-w64): make build make test +Documentation +------------- + +Build & display the documentation using + + make docs + License ------- diff --git a/include/winapi/buffer.hpp b/include/winapi/buffer.hpp index 4d47930..10ff479 100644 --- a/include/winapi/buffer.hpp +++ b/include/winapi/buffer.hpp @@ -16,33 +16,45 @@ namespace winapi { +/** + * @brief Binary data container. + * + * This class wraps a blob of binary data. + */ class Buffer : public std::vector { public: typedef std::vector Parent; Buffer() = default; + /** Construct a buffer from an explicit list of byte values. */ Buffer(std::initializer_list lst) : Parent{lst} {} + /** Construct a buffer from an instance of `std::vector`. */ explicit Buffer(Parent&& src) : Parent{std::move(src)} {} + /** Construct a buffer from an instance of `std::basic_string`. */ template explicit Buffer(const std::basic_string& src) { set(src); } + /** Construct a buffer from a memory region. */ Buffer(const void* src, std::size_t nb) { set(src, nb); } + /** Replace the buffer's contents with the data from `std::basic_string`. */ template void set(const std::basic_string& src) { set(src.c_str(), src.length() * sizeof(std::basic_string::char_type)); } + /** Replace the buffer's contents with the data from a memory region. */ void set(const void* src, std::size_t nb) { resize(nb); std::memcpy(data(), src, nb); } + /** Interpret the buffer's contents as a `std::string`. */ std::string as_utf8() const { const auto c_str = reinterpret_cast(data()); const auto nb = size(); @@ -50,6 +62,7 @@ public: return {c_str, nch}; } + /** Interpret the buffer's contents as a `std::wstring`. */ std::wstring as_utf16() const { const auto c_str = reinterpret_cast(data()); const auto nb = size(); @@ -62,6 +75,7 @@ public: return {c_str, nch}; } + /** Append another buffer to the end of this one. */ void add(const Buffer& src) { const auto nb = size(); resize(nb + src.size()); diff --git a/include/winapi/cmd_line.hpp b/include/winapi/cmd_line.hpp index 8735660..d1a4a7e 100644 --- a/include/winapi/cmd_line.hpp +++ b/include/winapi/cmd_line.hpp @@ -11,38 +11,94 @@ namespace winapi { +/** + * @brief Command line for the current process or for launching new processes. + * + * This class takes care of proper parsing and stringifying command line + * arguments so that they are safe to use with CreateProcess, ShellExecute, + * etc. + */ class CommandLine { public: + /** Get the command line used to launch this process. */ static CommandLine query(); - static CommandLine parse(const std::string&); - + /** + * Parse a command line from a string. + * @param src UTF-8 encoded string. + */ + static CommandLine parse(const std::string& src); + + /** + * Build a command line from main() arguments. + * @param argc Length of the argv array. + * @param argv UTF-16 encoded strings. + */ static CommandLine from_main(int argc, wchar_t* argv[]); + /** + * Build an empty command line. + * It won't have neither argv[0], nor any other args. + */ CommandLine() = default; + /** + * Build a command line. + * @param argv0 UTF-8 string, argv[0]. + * @param args List of UTF-8 strings, other arguments. + */ explicit CommandLine(const std::string& argv0, const std::vector& args = {}) : m_argv0{argv0}, m_args{args} {} + /** + * Build a command line. + * @param argv0 UTF-8 string, argv[0]. + * @param args List of UTF-8 strings, other arguments. + */ explicit CommandLine(std::string&& argv0, std::vector&& args = {}) : m_argv0{std::move(argv0)}, m_args{std::move(args)} {} + /** + * Build a command line. + * @param argv List of UTF-8 strings, including argv[0]. + */ explicit CommandLine(std::vector argv); static std::string escape(const std::string&); static std::string escape_cmd(const std::string&); + /** + * Build a string that represents this command line. + * @return UTF-8 string. + */ std::string to_string() const; + /** + * Build a string that represents this command line, but omit argv[0]. + * @return UTF-8 string. + */ std::string args_to_string() const; + /** + * Get argv[0] for this command line. + * @return UTF-8 string. + */ std::string get_argv0() const { return m_argv0; } + /** Test if this command line has any additional arguments besides argv[0]. */ bool has_args() const { return !get_args().empty(); } + /** + * Get list of arguments for this command line beyond argv[0]. + * @return List of UTF-8 strings. + */ const std::vector& get_args() const { return m_args; } + /** + * Get list of arguments for this command line. + * @return List of UTF-8 strings. + */ std::vector get_argv() const; private: diff --git a/include/winapi/error.hpp b/include/winapi/error.hpp index 8ecd720..35e10f0 100644 --- a/include/winapi/error.hpp +++ b/include/winapi/error.hpp @@ -3,6 +3,11 @@ // For details, see https://github.com/egor-tensin/winapi-common. // Distributed under the MIT License. +/** + * @file + * @brief Make `std::system_error` work with `GetLastError()`. + */ + #pragma once #include @@ -30,6 +35,11 @@ inline const CategoryWindows& category_windows() { return instance; } +/** + * Build a `std::system_error` from the value of `GetLastError()`. + * @param code Value of `GetLastError()`. + * @param function Name of the function that failed, like "CreateFile". + */ std::system_error windows(DWORD code, const char* function); template diff --git a/include/winapi/file.hpp b/include/winapi/file.hpp index 7d0126c..b1c8ce3 100644 --- a/include/winapi/file.hpp +++ b/include/winapi/file.hpp @@ -21,6 +21,11 @@ namespace winapi { bool operator==(const FILE_ID_128& a, const FILE_ID_128& b); +/** + * @brief File I/O. + * + * Easily open, read & write files. + */ class File : public Handle { public: struct ID { @@ -32,20 +37,37 @@ public: } }; + /** Open file for reading. */ static File open_r(const std::string&); + /** @overload */ static File open_r(const CanonicalPath&); + /** Open file for reading (inc. ability to read its attributes). */ static File open_read_attributes(const std::string&); + /** @overload */ static File open_read_attributes(const CanonicalPath&); + /** Open file for writing. */ static File open_w(const std::string&); + /** @overload */ static File open_w(const CanonicalPath&); + /** Delete a file. */ static void remove(const std::string&); + /** @overload */ static void remove(const CanonicalPath&); + /** Make a File instance from an open handle. */ explicit File(Handle&& handle) : Handle{std::move(handle)} {} + /** + * Get file size. + * @return File size, bytes. + */ std::size_t get_size() const; + /** + * Get file ID. + * File ID is a unique representation of a file, suitable for hashing. + */ ID query_id() const; }; diff --git a/include/winapi/handle.hpp b/include/winapi/handle.hpp index 8ea90aa..b5a7547 100644 --- a/include/winapi/handle.hpp +++ b/include/winapi/handle.hpp @@ -16,6 +16,12 @@ namespace winapi { +/** + * @brief HANDLE wrapper. + * + * This class wraps HANDLE, allowing for painless reads and writes from a + * random handle. + */ class Handle { public: Handle() = default; @@ -29,21 +35,45 @@ public: bool is_valid() const; static bool is_valid(HANDLE); + /** Close this handle. */ void close(); + /** Check if this is a standard console handle. */ bool is_std() const; + /** Check if this is the stdin handle. */ static Handle std_in(); + /** Check if this is the stdout handle. */ static Handle std_out(); + /** Check if this is the stderr handle. */ static Handle std_err(); + /** Read everything from this handle. */ Buffer read() const; static constexpr std::size_t max_chunk_size = 16 * 1024; + /** + * Read a chunk from this handle. + * @param read_chunk Receives the data read. + * @return `true` if there's more data, `false` otherwise. + */ bool read_chunk(Buffer& read_chunk) const; - void write(const void*, std::size_t nb) const; + /** + * Write data to this handle. + * @param data Pointer to binary data. + * @param nb Data size. + */ + void write(const void* data, std::size_t nb) const; + /** + * Write data to this handle. + * @param buffer Binary data to write. + */ void write(const Buffer& buffer) const; + /** + * Write data to this handle. + * @param src Binary data to write. + */ template void write(const std::basic_string& src) const { write(src.c_str(), src.size() * sizeof(CharT)); diff --git a/include/winapi/path.hpp b/include/winapi/path.hpp index f2b0aa9..26d89ce 100644 --- a/include/winapi/path.hpp +++ b/include/winapi/path.hpp @@ -9,8 +9,10 @@ namespace winapi { +/** @brief Absolute, canonical path. */ class CanonicalPath { public: + /** Make an absolute, canonical path. */ static std::string canonicalize(const std::string&); explicit CanonicalPath(const std::string&); diff --git a/include/winapi/pipe.hpp b/include/winapi/pipe.hpp index aec87cd..e4f8624 100644 --- a/include/winapi/pipe.hpp +++ b/include/winapi/pipe.hpp @@ -11,13 +11,19 @@ namespace winapi { +/** @brief Anonymous pipe wrapper. */ class Pipe { public: + /** Create a new pipe. */ Pipe(); + /** Get the read end of the pipe. */ Handle& read_end() { return m_read_end; } + /** @overload */ const Handle& read_end() const { return m_read_end; } + /** Get the write end of the pipe. */ Handle& write_end() { return m_write_end; } + /** @overload */ const Handle& write_end() const { return m_write_end; } private: diff --git a/include/winapi/process.hpp b/include/winapi/process.hpp index d5a4ed5..92d9da5 100644 --- a/include/winapi/process.hpp +++ b/include/winapi/process.hpp @@ -20,6 +20,7 @@ namespace winapi { +/** @brief Process parameters for Process::create(). */ struct ProcessParameters { enum ConsoleCreationMode { ConsoleNone, @@ -34,6 +35,7 @@ struct ProcessParameters { ConsoleCreationMode console_mode = ConsoleNew; }; +/** @brief Process parameters for Process::shell(). */ struct ShellParameters : ProcessParameters { static ShellParameters runas(const CommandLine& cmd_line) { ShellParameters params{cmd_line}; @@ -46,36 +48,66 @@ struct ShellParameters : ProcessParameters { boost::optional verb; }; +/** + * @brief Create a new process or open an existing process. + */ class Process { public: using ID = DWORD; + /** Create a new process using ProcessParameters. */ static Process create(ProcessParameters); + /** Create a new process using the given command line. */ static Process create(const CommandLine&); + /** Create a new process using the given command line and IO settings. */ static Process create(const CommandLine&, process::IO); + /** Create a new shell process using ShellParameters. */ static Process shell(const ShellParameters&); + /** Create a new shell process using the given command line. */ static Process shell(const CommandLine&); + /** Open the current process. */ static Process current(); - static Process open(ID, DWORD permissions = default_permissions()); + /** + * Open an existing process. + * @param id Process ID. + * @param permissions Required permissions. + */ + static Process open(ID id, DWORD permissions = default_permissions()); + /** Open an existing process with read permissions. */ static Process open_r(ID); + /** Permissions that allow to query process's status. */ static DWORD default_permissions(); + /** Permissions that allows to read process's memory. */ static DWORD read_permissions(); + /** Get this process's ID. */ ID get_id() const { return m_id; } + /** Get this process's handle. */ const Handle& get_handle() const { return m_handle; } + /** Check if this process is running (i.e. not terminated). */ bool is_running() const; + /** Wait for the process to terminate. */ void wait() const; + /** Make this process terminate with an exit code. */ void terminate(int ec = 0) const; + /** Same as calling terminate() and wait(). */ void shut_down(int ec = 0) const; + /** Get terminated process's exit code. */ int get_exit_code() const; + /** Get this process's executable path. */ std::string get_exe_path() const; + /** Get a binary resource from the process's executable. */ static Resource get_resource(uint32_t id); + /** + * Get a string resource from the process's executable. + * @return UTF-8 string. + */ static std::string get_resource_string(uint32_t id); private: diff --git a/include/winapi/process_io.hpp b/include/winapi/process_io.hpp index 805ada8..9df145c 100644 --- a/include/winapi/process_io.hpp +++ b/include/winapi/process_io.hpp @@ -21,27 +21,43 @@ struct Stream { Handle handle; }; +/** @brief Redirect child process's stdin. */ struct Stdin : Stream { + /** No redirection. */ Stdin(); + /** Make child process read form a file. */ explicit Stdin(const std::string& file); + /** @overload */ explicit Stdin(const CanonicalPath& file); + /** Make child process read form a pipe. */ explicit Stdin(Pipe&); }; +/** @brief Redirect child process's stdout. */ struct Stdout : Stream { + /** No redirection. */ Stdout(); + /** Redirect child process's stdout to a file. */ explicit Stdout(const std::string& file); + /** @overload */ explicit Stdout(const CanonicalPath& file); + /** Redirect child process's stdout to a pipe. */ explicit Stdout(Pipe&); }; +/** @brief Redirect child process's stderr. */ struct Stderr : Stream { + /** No redirection. */ Stderr(); + /** Redirect child process's stderr to a file. */ explicit Stderr(const std::string& file); + /** @overload */ explicit Stderr(const CanonicalPath& file); + /** Redirect child process's stderr to a pipe. */ explicit Stderr(Pipe&); }; +/** @brief Child process IO settings. */ struct IO { IO() = default; diff --git a/include/winapi/resource.hpp b/include/winapi/resource.hpp index 2f77d3e..8b6e41b 100644 --- a/include/winapi/resource.hpp +++ b/include/winapi/resource.hpp @@ -11,6 +11,7 @@ namespace winapi { +/** @brief Resources embedded in a PE (Portable Executable). */ struct Resource { // This is just a pointer to static data. @@ -18,6 +19,7 @@ struct Resource { Resource(const void* data, std::size_t nb) : data{data}, nb{nb} {} + /** Extract resource data into a Buffer instance. */ Buffer copy() const { return {data, nb}; } const void* data = nullptr; diff --git a/include/winapi/shmem.hpp b/include/winapi/shmem.hpp index 4fc5ac7..d1ad997 100644 --- a/include/winapi/shmem.hpp +++ b/include/winapi/shmem.hpp @@ -15,12 +15,24 @@ namespace winapi { +/** @brief Named shared memory region. */ class SharedMemory { public: + /** + * Creates a shared memory region. + * @param name UTF-8 string. + * @param nb Number of bytes. + */ static SharedMemory create(const std::string& name, std::size_t nb); + /** + * Opens a shared memory region. + * @param name UTF-8 string. + */ static SharedMemory open(const std::string& name); + /** Get pointer to the data. */ void* get() const { return m_addr.get(); } + /** @overload */ void* ptr() const { return get(); } private: @@ -36,11 +48,17 @@ private: std::unique_ptr m_addr; }; +/** @brief Easy way to represent a C++ object as a shared memory region. */ template class SharedObject { public: typedef typename std::aligned_storage::type AlignedType; + /** + * Create the object & construct a shared memory region to store it. + * @param name UTF-8 string, name of the shared memory region. + * @param args Arguments to construct the object. + */ template static SharedObject create(const std::string& name, Args&&... args) { SharedObject obj{SharedMemory::create(name, sizeof(AlignedType))}; @@ -49,6 +67,10 @@ public: return obj; } + /** + * Open a shared memory region that stores the object. + * @param name UTF-8 string, name of the shared memory region. + */ static SharedObject open(const std::string& name) { SharedObject obj{SharedMemory::open(name)}; return obj; @@ -64,7 +86,9 @@ public: } } + /** Get pointer to the object. */ T* ptr() const { return reinterpret_cast(m_shmem.ptr()); } + /** Get reference to the object. */ T& get() const { return *ptr(); } T* operator->() const { return ptr(); } -- cgit v1.2.3