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
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)

project(Pipe VERSION 0.1 LANGUAGES CXX)


if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(PIPE_IS_PROJECT ON)
set(PIPE_IS_PROJECT ON)
else()
set(PIPE_IS_PROJECT OFF)
set(PIPE_IS_PROJECT OFF)
endif()
option(PIPE_BUILD_SHARED "Build shared libraries" ON)
option(PIPE_BUILD_TESTS "Build Pipe tests" ${PIPE_IS_PROJECT})
Expand Down
2 changes: 1 addition & 1 deletion Include/Pipe/Core/EnumFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace p::core
}
} // namespace p::core

#define DEFINE_FLAG_OPERATORS(Type) \
#define PIPE_DEFINE_FLAG_OPERATORS(Type) \
constexpr p::UnderlyingType<Type> operator*(Type value) \
{ \
return static_cast<p::UnderlyingType<Type>>(value); \
Expand Down
6 changes: 3 additions & 3 deletions Include/Pipe/Core/Generic/GenericPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,17 @@ namespace p::core
// An 8-bit character type - In-memory only. 8-bit representation. Should
// really be char8_t but making this the generic option is easier for
// compilers which don't fully support C++11 yet (i.e. MSVC).
using Char8 = uint8;
using Char8 = char8_t;

// A 16-bit character type - In-memory only. 16-bit representation. Should
// really be char16_t but making this the generic option is easier for
// compilers which don't fully support C++11 yet (i.e. MSVC).
using Char16 = uint16;
using Char16 = char16_t;

// A 32-bit character type - In-memory only. 32-bit representation. Should
// really be char32_t but making this the generic option is easier for
// compilers which don't fully support C++11 yet (i.e. MSVC).
using Char32 = uint32;
using Char32 = char32_t;

// A switchable character - In-memory only.
// Either AnsiChar or WideChar
Expand Down
7 changes: 6 additions & 1 deletion Include/Pipe/Core/Generic/GenericPlatformProcess.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2015-2022 Piperift - All rights reserved
#pragma once

#include "Pipe/Core/Span.h"
#include "Pipe/Core/String.h"
#include "Pipe/Core/StringView.h"
#include "Pipe/Export.h"

Expand All @@ -9,13 +11,16 @@ namespace p::core
{
struct PIPE_API GenericPlatformProcess
{
static StringView GetExecutableFile() = delete;
static StringView GetExecutablePath() = delete;
static StringView GetBasePath() = delete;

/** Content saved to compiler or project directories should be rerouted to user directories
* instead **/
static bool ShouldSaveToUserDir()
{
return false;
}

static void ShowFolder(StringView path);
};
} // namespace p::core
Expand Down
1 change: 0 additions & 1 deletion Include/Pipe/Core/Linux/LinuxPlatformProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace p::core

static void ShowFolder(StringView path);
};

using PlatformProcess = LinuxPlatformProcess;
} // namespace p::core

Expand Down
6 changes: 3 additions & 3 deletions Include/Pipe/Core/Log.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace p::Log
PIPE_API void Init(Path logPath = {});
PIPE_API void Shutdown();

void PIPE_API Info(StringView msg);
void PIPE_API Warning(StringView msg);
void PIPE_API Error(StringView msg);
PIPE_API void Info(StringView msg);
PIPE_API void Warning(StringView msg);
PIPE_API void Error(StringView msg);

template<typename... Args>
void Info(StringView format, Args... args)
Expand Down
1 change: 0 additions & 1 deletion Include/Pipe/Core/Mac/MacPlatformProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace p::core

static void ShowFolder(StringView path);
};

using PlatformProcess = MacPlatformProcess;
} // namespace p::core

Expand Down
5 changes: 4 additions & 1 deletion Include/Pipe/Core/Span.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ namespace p::core
constexpr TSpan(T* data, i32 size) : data{data}, size{size} {}

template<sizet N>
constexpr TSpan(T (&value)[N]) : data{value}, size{N}
constexpr TSpan(T (&value)[N]) : data{&value}, size{N}
{}
constexpr TSpan(std::initializer_list<T> value)
: data{value.begin()}, size{i32(value.size())}
{}

TSpan(const TArray<Mut<T>>& value) : data{value.Data()}, size{value.Size()} {}
Expand Down
16 changes: 1 addition & 15 deletions Include/Pipe/Core/String.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ namespace p::core

if constexpr (IsSame<FromChar, ToChar>)
{
dest = source;
dest += source;
}
else if constexpr (sizeof(FromChar) == 1 && sizeof(ToChar) == 2)
{
Expand All @@ -114,27 +114,13 @@ namespace p::core
}
}

// Help FromChar deduction
template<typename ToStringType, typename FromChar>
inline void ConvertTo(const TString<FromChar>& source, ToStringType& dest)
{
ConvertTo(TStringView<FromChar>{source}, dest);
}

template<typename ToStringType, typename FromChar>
inline ToStringType Convert(TStringView<FromChar> source)
{
ToStringType dest;
ConvertTo(source, dest);
return Move(dest);
}

// Help FromChar deduction
template<typename ToStringType, typename FromChar>
inline ToStringType Convert(const TString<FromChar>& source)
{
return Move(Convert<ToStringType>(TStringView<FromChar>{source}));
}
}; // namespace Strings
} // namespace p::core

Expand Down
227 changes: 227 additions & 0 deletions Include/Pipe/Core/Subprocess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// Copyright 2015-2022 Piperift - All rights reserved
// Modified from https://github.com/sheredom/subprocess.h
#pragma once

#include "Pipe/Core/EnumFlags.h"
#include "Pipe/Core/Span.h"
#include "Pipe/Core/StringView.h"
#include "Pipe/Export.h"

#include <stdio.h>
#include <string.h>


#if !defined(_MSC_VER)
# include <signal.h>
# include <spawn.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
#endif


namespace p::core
{
enum class PIPE_API SubprocessOptions
{
None = 0,

// stdout and stderr are the same FILE.
CombinedOutErr = 1 << 0,

// The child process should inherit the environment variables of the parent.
InheritEnvironment = 1 << 1,

// Enable asynchronous reading of stdout/stderr before it has completed.
EnableAsync = 1 << 2,

// Enable the child process to be spawned with no window visible if supported
// by the platform.
NoWindow = 1 << 3,

// If set, the process will terminate when the instance is destroyed
TerminateIfDestroyed = 1 << 4,

// Search for program names in the PATH variable. Always enabled on Windows.
// Note: this will **not** search for paths in any provided custom environment
// and instead uses the PATH of the spawning process.
SearchUserPath = InheritEnvironment | NoWindow
};
PIPE_DEFINE_FLAG_OPERATORS(SubprocessOptions)


#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded"
#endif
struct PIPE_API Subprocess
{
FILE* cinFile = nullptr;
FILE* coutFile = nullptr;
FILE* cerrFile = nullptr;

#if defined(_MSC_VER)
void* hProcess = nullptr;
void* hStdInput = nullptr;
void* hEventOutput = nullptr;
void* hEventError = nullptr;
#else
pid_t child = 0;
i32 returnStatus = 0;
#endif

SubprocessOptions options = SubprocessOptions::None;
bool alive = false;


Subprocess() = default;
Subprocess(Subprocess&& other) noexcept;
~Subprocess();
};
#ifdef __clang__
# pragma clang diagnostic pop
#endif


/**
* @brief Create a process (extended create).
* @param command An array of strings for the command line to execute for
* this process. The last element must be NULL to signify the end of the array.
* The memory backing this parameter only needs to persist until this function
* returns.
* @param options A bit field of subprocess_option_e's to pass.
* @param environment An optional array of strings for the environment to use
* for a child process (each element of the form FOO=BAR). The last element
* must be NULL to signify the end of the array.
* @param outProcess The newly created process.
* @return On success zero is returned.
*
* If `options` contains `subprocess_option_inherit_environment`, then
* `environment` must be NULL.
*/
PIPE_API TOptional<Subprocess> RunProcessEx(TSpan<const char* const> command,
TSpan<const char* const> environment, SubprocessOptions options = SubprocessOptions::None);

/**
* @brief Create a process.
* @param command An array of strings for the command line to execute for
* this process. The last element must be NULL to signify the end of the array.
* The memory backing this parameter only needs to persist until this function
* returns.
* @param options A bit field of subprocess_option_e's to pass.
* @param outProcess The newly created process.
* @return On success zero is returned.
*/
inline PIPE_API TOptional<Subprocess> RunProcess(
TSpan<const char* const> command, SubprocessOptions options = SubprocessOptions::None)
{
return RunProcessEx(command, {}, options);
}

/**
* @brief Wait for a process to finish execution.
* @param process The process to wait for.
* @param out_return_code The return code of the returned process (can be
* NULL).
* @return On success zero is returned.
*
* Joining a process will close the stdin pipe to the process.
*/
PIPE_API i32 WaitProcess(Subprocess* process, i32* outReturnCode);

/**
* @brief Destroy a previously created process.
* @param process The process to destroy.
* @return On success zero is returned.
*
* If the process to be destroyed had not finished execution, it may out live
* the parent process.
*/
PIPE_API i32 DestroyProcess(Subprocess* process);

/**
* @brief Terminate a previously created process.
* @param process The process to terminate.
* @return On success zero is returned.
*
* If the process to be destroyed had not finished execution, it will be
* terminated (i.e killed).
*/
PIPE_API i32 TerminateProcess(Subprocess* process);

/**
* @brief Read the standard output from the child process.
* @param process The process to read from.
* @param buffer The buffer to read into.
* @param size The maximum number of bytes to read.
* @return The number of bytes actually read into buffer. Can only be 0 if the
* process has complete.
*
* The only safe way to read from the standard output of a process during it's
* execution is to use the `SubprocessOptions::EnableAsync` option in
* conjuction with this method.
*/
PIPE_API u32 ReadProcessCout(Subprocess* process, char* buffer, u32 size);

/**
* @brief Read the standard error from the child process.
* @param process The process to read from.
* @param buffer The buffer to read into.
* @param size The maximum number of bytes to read.
* @return The number of bytes actually read into buffer. Can only be 0 if the
* process has complete.
*
* The only safe way to read from the standard error of a process during it's
* execution is to use the `SubprocessOptions::EnableAsync` option in
* conjuction with this method.
*/
PIPE_API u32 ReadProcessCerr(Subprocess* process, char* buffer, u32 size);

/**
* @brief Returns if the subprocess is currently still alive and executing.
* @param process The process to check.
* @return If the process is still alive non-zero is returned.
*/
PIPE_API bool IsAlive(Subprocess* process);

/**
* @brief Get the standard input file for a process.
* @param process The process to query.
* @return The file for standard input of the process.
*
* The file returned can be written to by the parent process to feed data to
* the standard input of the process.
*/
PIPE_API FILE* GetProcessCin(const Subprocess* process);

/**
* @brief Get the standard output file for a process.
* @param process The process to query.
* @return The file for standard output of the process.
*
* The file returned can be read from by the parent process to read data from
* the standard output of the child process.
*/
PIPE_API FILE* GetProcessCout(const Subprocess* process);

/**
* @brief Get the standard error file for a process.
* @param process The process to query.
* @return The file for standard error of the process.
*
* The file returned can be read from by the parent process to read data from
* the standard error of the child process.
*
* If the process was created with the SubprocessOptions::CombinedOutErr
* option bit set, this function will return NULL, and the GetProcessCout
* function should be used for both the standard output and error combined.
*/
PIPE_API FILE* GetProcessCerr(const Subprocess* process);
} // namespace p::core


namespace p
{
using namespace p::core;
}
3 changes: 3 additions & 0 deletions Include/Pipe/Core/Windows/WindowsPlatformMisc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "Pipe/Core/Generic/GenericPlatformMisc.h"
#include "Pipe/Core/StringView.h"


namespace p::core
Expand All @@ -12,6 +13,8 @@ namespace p::core
struct PIPE_API WindowsPlatformMisc : public GenericPlatformMisc
{
static u32 GetMaxPathLength();

static const TChar* GetSystemErrorMessage(TChar* buffer, i32 size, i32 error = 0);
};

using PlatformMisc = WindowsPlatformMisc;
Expand Down
Loading