{"id":20468957,"url":"https://github.com/neko-box-coder/system2","last_synced_at":"2025-04-13T10:27:09.949Z","repository":{"id":224218911,"uuid":"760230459","full_name":"Neko-Box-Coder/System2","owner":"Neko-Box-Coder","description":"Ability to call shell commands just like the system function in C, but can communicate with stdin and stdout and stderr.","archived":false,"fork":false,"pushed_at":"2024-12-15T18:10:25.000Z","size":178,"stargazers_count":11,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T01:51:26.576Z","etag":null,"topics":["c","command","header-only","shell","stderr","stdin","stdout","subprocess","subprocess-run","system"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Neko-Box-Coder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-20T02:57:03.000Z","updated_at":"2025-02-03T21:18:20.000Z","dependencies_parsed_at":"2024-03-08T00:22:09.964Z","dependency_job_id":"41630479-c9e4-4509-ada8-f79199a41e8c","html_url":"https://github.com/Neko-Box-Coder/System2","commit_stats":null,"previous_names":["neko-box-coder/system2"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Neko-Box-Coder%2FSystem2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Neko-Box-Coder%2FSystem2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Neko-Box-Coder%2FSystem2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Neko-Box-Coder%2FSystem2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Neko-Box-Coder","download_url":"https://codeload.github.com/Neko-Box-Coder/System2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248697403,"owners_count":21147322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","command","header-only","shell","stderr","stdin","stdout","subprocess","subprocess-run","system"],"created_at":"2024-11-15T14:07:28.044Z","updated_at":"2025-04-13T10:27:09.934Z","avatar_url":"https://github.com/Neko-Box-Coder.png","language":"C","readme":"### System2\n\n`System2` is a cross-platform c library that allows you to call shell commands and other executables (subprocess), just like `system` but with the ability to\nprovide input to stdin and capture the output from stdout and stderr.\n\n```text\n  _______________________________\n/_______________________________/|\n|o   ____  _  _  ____  ____   o|$|\n|   / ___)( \\/ )/ ___)(___ \\   |$| ______\n|   \\___ \\ )  / \\___ \\ / __/   |$| $$$$$/\n|   (____/(__/  (____/(____)   |$| $$$$/\n|o____________________________o|/  \u0026//\n```\n\u003e From: https://patorjk.com with Graceful font\n\n\u003e [!NOTE]\n\u003e \n\u003e For a C++ wrapper, check out [System2.cpp](https://github.com/Neko-Box-Coder/System2.cpp)\n\n#### Features\n\n- Written in C99, and is ready to be used in C++ as well\n- Cross-platform (POSIX and Windows)\n- Command interaction with stdin, stdout, and stderr\n- Invoking shell commands and launching executables\n- Blocking (sync) and non-blocking (async) version\n- No dependencies (only standard C and system libraries).\n    No longer need a heavy framework like boost or poco just to capture output from running a command.\n- Header only library (source version available as well)\n- UTF-8 support\\*\n- CMake integration\n\n\\* See Remarks for UTF-8 support\n\n#### Quick Start With Minimum running example (Without checks)\nCheck [main.c](./main.c) for more examples.\n\n```c\n//This bypasses inheriting memory from parent process on linux (glibc 2.24) but removes the ability to use RunDirectory.\n//See https://github.com/Neko-Box-Coder/System2/issues/3\n//#define SYSTEM2_POSIX_SPAWN 1\n\n//#define SYSTEM2_DECLARATION_ONLY 1\n\n//#define SYSTEM2_IMPLEMENTATION_ONLY 1\n\n\n#include \"System2.h\"\n#include \u003cstdio.h\u003e\n\nint main(int argc, char** argv) \n{\n    System2CommandInfo commandInfo;\n    memset(\u0026commandInfo, 0, sizeof(System2CommandInfo));\n    commandInfo.RedirectInput = true;\n    commandInfo.RedirectOutput = true;\n\n    #if defined(__unix__) || defined(__APPLE__)\n        System2Run(\"read testVar \u0026\u0026 echo testVar is \\\\\\\"$testVar\\\\\\\"\", \u0026commandInfo);\n    #endif\n    \n    #if defined(_WIN32)\n        System2Run(\"set /p testVar= \u0026\u0026 echo testVar is \\\"!testVar!\\\"\", \u0026commandInfo);\n    #endif\n    \n    char input[] = \"test content\\n\";\n    System2WriteToInput(\u0026commandInfo, input, sizeof(input));\n    \n    //Waiting here simulates the child process has \"finished\" and we read the output of it\n    //Sleep(2000);\n    \n    char outputBuffer[1024];\n    uint32_t bytesRead = 0;\n    \n    //System2ReadFromOutput can also return SYSTEM2_RESULT_READ_NOT_FINISHED if we have more to read\n    //In which case can use a do while loop to keep getting the output\n    System2ReadFromOutput(\u0026commandInfo, outputBuffer, 1023, \u0026bytesRead);\n    outputBuffer[bytesRead] = 0;\n    \n    int returnCode = -1;\n    System2GetCommandReturnValueSync(\u0026commandInfo, \u0026returnCode, false);\n    \n    printf(\"%s\\n\", outputBuffer);\n    printf(\"%s: %d\\n\", \"Command has executed with return value\", returnCode);\n    \n    return 0;\n    \n    //Output: Command has executed with return value: 0\n    //Output: testVar is \"test content\"\n}\n```\n\n#### API Documentation\n```cpp\ntypedef struct\n{\n    bool RedirectInput;         //Redirect input with pipe?\n    bool RedirectOutput;        //Redirect output with pipe?\n    const char* RunDirectory;   //The directory to run the command in?\n    \n    #if defined(_WIN32)\n        bool DisableEscapes;    //Disable automatic escaping?\n    #endif\n    \n    //Internal fields...\n} System2CommandInfo;\n\n/*\nRuns the command in system shell just like the `system()` funcion with the given settings \n    passed with `inOutCommandInfo`.\n\nThis uses \n`sh -c command` for POSIX and\n`cmd /s /v /c command` for Windows\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_PIPE_CREATE_FAILED\n- SYSTEM2_RESULT_CREATE_CHILD_PROCESS_FAILED\n- SYSTEM2_RESULT_PIPE_FD_CLOSE_FAILED\n- SYSTEM2_RESULT_COMMAND_CONSTRUCT_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_FILE_ACTION_DESTROY_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_FILE_ACTION_DUP2_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_RUN_DIRECTORY_NOT_SUPPORTED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2Run(  const char* command, \n                                                System2CommandInfo* inOutCommandInfo);\n\n/*\nRuns the executable (which can search in PATH env variable) with the given arguments and settings\n    passed with inOutCommandInfo.\n\nOn Windows, automatic escaping can be removed by setting the `DisableEscape` in `inOutCommandInfo`\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_PIPE_CREATE_FAILED\n- SYSTEM2_RESULT_CREATE_CHILD_PROCESS_FAILED\n- SYSTEM2_RESULT_PIPE_FD_CLOSE_FAILED\n- SYSTEM2_RESULT_COMMAND_CONSTRUCT_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_FILE_ACTION_DESTROY_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_FILE_ACTION_DUP2_FAILED\n- SYSTEM2_RESULT_POSIX_SPAWN_RUN_DIRECTORY_NOT_SUPPORTED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2RunSubprocess(const char* executable,\n                                                        const char* const* args,\n                                                        int argsCount,\n                                                        System2CommandInfo* inOutCommandInfo);\n\n\n/*\nReads the output (stdout and stderr) from the command. \nOutput string is **NOT** null terminated.\n\nIf SYSTEM2_RESULT_READ_NOT_FINISHED is returned, \nthis function can be called again until SYSTEM2_RESULT_SUCCESS to retrieve the rest of the output.\n\noutBytesRead determines how many bytes have been read for **this** function call\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_READ_NOT_FINISHED\n- SYSTEM2_RESULT_READ_FAILED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2ReadFromOutput(   const System2CommandInfo* info, \n                                                            char* outputBuffer, \n                                                            uint32_t outputBufferSize,\n                                                            uint32_t* outBytesRead);\n\n/*\nWrite the input (stdin) to the command. \n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_WRITE_FAILED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2WriteToInput( const System2CommandInfo* info, \n                                                        const char* inputBuffer, \n                                                        const uint32_t inputBufferSize);\n\n\n//TODO: Might want to add this to have this ability to close input pipe manually\n//SYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2CloseInput(System2CommandInfo* info);\n\n/*\nCleanup any open handles associated with the command.\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_PIPE_FD_CLOSE_FAILED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2CleanupCommand(const System2CommandInfo* info);\n\n/*\nGets the return code if the command has finished.\nOtherwise, this will return SYSTEM2_RESULT_COMMAND_NOT_FINISHED immediately.\n\nIf `manualCleanup` is false, \n`System2CleanupCommand()` is automatically called when the command has exited.\n\nOtherwise, `System2CleanupCommand()` should be called when the command has exited.\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_COMMAND_NOT_FINISHED\n- SYSTEM2_RESULT_COMMAND_TERMINATED\n- SYSTEM2_RESULT_PIPE_FD_CLOSE_FAILED\n- SYSTEM2_RESULT_COMMAND_WAIT_ASYNC_FAILED\n*/\nSYSTEM2_FUNC_PREFIX \nSYSTEM2_RESULT System2GetCommandReturnValueAsync(   const System2CommandInfo* info, \n                                                    int* outReturnCode,\n                                                    bool manualCleanup);\n\n/*\nWait for the command to finish and gets the return code\n\nIf `manualCleanup` is false, \n`System2CleanupCommand()` is automatically called when the command has exited.\n\nOtherwise, `System2CleanupCommand()` should be called when the command has exited.\n\nCould return the follow result:\n- SYSTEM2_RESULT_SUCCESS\n- SYSTEM2_RESULT_COMMAND_TERMINATED\n- SYSTEM2_RESULT_PIPE_FD_CLOSE_FAILED\n- SYSTEM2_RESULT_COMMAND_WAIT_SYNC_FAILED\n*/\nSYSTEM2_FUNC_PREFIX SYSTEM2_RESULT System2GetCommandReturnValueSync(const System2CommandInfo* info, \n                                                                    int* outReturnCode,\n                                                                    bool manualCleanup);\n```\n\n\n#### Using System2 in your project\n\nThis library has header only version, just include \"System2.h\" and you are good to go.\n\nHowever, this will leak system library headers to your codebase.\n\nIn that case, you can use the source version of the library.\n\n1. Define `SYSTEM2_DECLARATION_ONLY 1` before including `System2.h`\n\n2. Then, either:\n    - Add `System2.c` to you codebase\n    - Or include `System2.h` in a single c file and define `SYSTEM2_IMPLEMENTATION_ONLY 1` before it\n    - Or link your project with `System2` target in CMake`\n\n---\n#### Remarks\n- For Linux or MacOS, `System2Run()` and `System2RunSubprocess()` will inherit the parent process memory (due to how `fork()` works).\n    Meaning it is possible to over commit memory and therefore causes out of memory error.\n    - A temporary fix is there by using `posix_spawn()` instead of `fork()` by `#define SYSTEM2_POSIX_SPAWN 1` before `#include \"System2.h\"`\n    - See [Issue](https://github.com/Neko-Box-Coder/System2/issues/3)\n- For POSIX, UTF-8 support should work if it is available on the system. This is however **not tested**.\n- For Windows, UTF-8 support works for the **command** input (in theory XP and above but tested on Windows 10). \n    However, the output part is **NOT** in UTF-8. The closest thing you can get for the output is UTF-16 as far as I know.\n    Here's what needed to get output in UTF-16:\n    1. Instead of `System2Run(\"\u003cyour command\u003e\", \u0026commandInfo)`, do `System2Run(\"cmd /u /s /v /c \\\"\u003cyour command\u003e\\\"\", \u0026commandInfo)`\n        This will output a UTF-16 string from cmd stdout/stderr\n    2. Read output as usual from `System2ReadFromOutput` but interpret the output as wchar_t string instead.\n        - You can then use `WideCharToMultiByte` to convert the output to UTF-8 if needed\n    3. If you want to output the UTF-16 output to console, you need to use `_setmode` before calling `wprintf`/`printf`\n        - See [this](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?view=msvc-170) for `_setmode` example\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneko-box-coder%2Fsystem2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneko-box-coder%2Fsystem2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneko-box-coder%2Fsystem2/lists"}