aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2022-03-10 12:39:04 +0500
committerEgor Tensin <Egor.Tensin@gmail.com>2022-03-10 12:48:59 +0500
commit4a13df61b92b8bf673f8a71d5fa0abf0356a4899 (patch)
tree071a3830ce0f2309e40a4bb16b7dd42018bd852f
parentMakefile: remove stupid header, etc. (diff)
downloadwinapi-common-4a13df61b92b8bf673f8a71d5fa0abf0356a4899.tar.gz
winapi-common-4a13df61b92b8bf673f8a71d5fa0abf0356a4899.zip
add Doxygen docs
-rw-r--r--CMakeLists.txt11
-rw-r--r--Makefile9
-rw-r--r--README.md7
-rw-r--r--include/winapi/buffer.hpp14
-rw-r--r--include/winapi/cmd_line.hpp60
-rw-r--r--include/winapi/error.hpp10
-rw-r--r--include/winapi/file.hpp22
-rw-r--r--include/winapi/handle.hpp32
-rw-r--r--include/winapi/path.hpp2
-rw-r--r--include/winapi/pipe.hpp6
-rw-r--r--include/winapi/process.hpp34
-rw-r--r--include/winapi/process_io.hpp16
-rw-r--r--include/winapi/resource.hpp2
-rw-r--r--include/winapi/shmem.hpp24
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<unsigned char> {
public:
typedef std::vector<unsigned char> Parent;
Buffer() = default;
+ /** Construct a buffer from an explicit list of byte values. */
Buffer(std::initializer_list<unsigned char> lst) : Parent{lst} {}
+ /** Construct a buffer from an instance of `std::vector<unsigned char>`. */
explicit Buffer(Parent&& src) : Parent{std::move(src)} {}
+ /** Construct a buffer from an instance of `std::basic_string`. */
template <typename CharT>
explicit Buffer(const std::basic_string<CharT>& 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 <typename CharT>
void set(const std::basic_string<CharT>& src) {
set(src.c_str(), src.length() * sizeof(std::basic_string<CharT>::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<const char*>(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<const wchar_t*>(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<std::string>& 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<std::string>&& 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<std::string> 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<std::string>& get_args() const { return m_args; }
+ /**
+ * Get list of arguments for this command line.
+ * @return List of UTF-8 strings.
+ */
std::vector<std::string> 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 <windows.h>
@@ -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 <typename Ret>
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 <typename CharT>
void write(const std::basic_string<CharT>& 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<std::string> 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<void, Unmap> m_addr;
};
+/** @brief Easy way to represent a C++ object as a shared memory region. */
template <typename T>
class SharedObject {
public:
typedef typename std::aligned_storage<sizeof(T), __alignof(T)>::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 <typename... Args>
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<T*>(m_shmem.ptr()); }
+ /** Get reference to the object. */
T& get() const { return *ptr(); }
T* operator->() const { return ptr(); }