Safetensors
GGUF
Turkish
llama
Llama-3
instruct
finetune
chatml
gpt4
synthetic data
distillation
function calling
json mode
axolotl
roleplaying
chat
Instructions to use tda45/TdAI with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- llama-cpp-python
How to use tda45/TdAI with llama-cpp-python:
# !pip install llama-cpp-python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="tda45/TdAI", filename="llama.cpp/models/ggml-vocab-aquila.gguf", )
output = llm( "Once upon a time,", max_tokens=512, echo=True ) print(output)
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use tda45/TdAI with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf tda45/TdAI # Run inference directly in the terminal: llama cli -hf tda45/TdAI
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf tda45/TdAI # Run inference directly in the terminal: llama cli -hf tda45/TdAI
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf tda45/TdAI # Run inference directly in the terminal: ./llama-cli -hf tda45/TdAI
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf tda45/TdAI # Run inference directly in the terminal: ./build/bin/llama-cli -hf tda45/TdAI
Use Docker
docker model run hf.co/tda45/TdAI
- LM Studio
- Jan
- Ollama
How to use tda45/TdAI with Ollama:
ollama run hf.co/tda45/TdAI
- Unsloth Studio
How to use tda45/TdAI with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for tda45/TdAI to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for tda45/TdAI to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for tda45/TdAI to start chatting
- Atomic Chat new
- Docker Model Runner
How to use tda45/TdAI with Docker Model Runner:
docker model run hf.co/tda45/TdAI
- Lemonade
How to use tda45/TdAI with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull tda45/TdAI
Run and chat with the model
lemonade run user.TdAI-{{QUANT_TAG}}List all available models
lemonade list
| /* | |
| The latest version of this library is available on GitHub; | |
| https://github.com/sheredom/subprocess.h | |
| */ | |
| /* | |
| This is free and unencumbered software released into the public domain. | |
| Anyone is free to copy, modify, publish, use, compile, sell, or | |
| distribute this software, either in source code form or as a compiled | |
| binary, for any purpose, commercial or non-commercial, and by any | |
| means. | |
| In jurisdictions that recognize copyright laws, the author or authors | |
| of this software dedicate any and all copyright interest in the | |
| software to the public domain. We make this dedication for the benefit | |
| of the public at large and to the detriment of our heirs and | |
| successors. We intend this dedication to be an overt act of | |
| relinquishment in perpetuity of all present and future rights to this | |
| software under copyright law. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
| OTHER DEALINGS IN THE SOFTWARE. | |
| For more information, please refer to <http://unlicense.org/> | |
| */ | |
| /* disable warning: '__cplusplus' is not defined as a preprocessor macro, | |
| * replacing with '0' for '#if/#elif' */ | |
| struct subprocess_s; | |
| enum subprocess_option_e { | |
| // stdout and stderr are the same FILE. | |
| subprocess_option_combined_stdout_stderr = 0x1, | |
| // The child process should inherit the environment variables of the parent. | |
| subprocess_option_inherit_environment = 0x2, | |
| // Enable asynchronous reading of stdout/stderr before it has completed. | |
| subprocess_option_enable_async = 0x4, | |
| // Enable the child process to be spawned with no window visible if supported | |
| // by the platform. | |
| subprocess_option_no_window = 0x8, | |
| // 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. | |
| subprocess_option_search_user_path = 0x10 | |
| }; | |
| extern "C" { | |
| /// @brief Create a process. | |
| /// @param command_line 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 out_process The newly created process. | |
| /// @return On success zero is returned. | |
| subprocess_weak int subprocess_create(const char *const command_line[], | |
| int options, | |
| struct subprocess_s *const out_process); | |
| /// @brief Create a process (extended create). | |
| /// @param command_line 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 out_process The newly created process. | |
| /// @return On success zero is returned. | |
| /// | |
| /// If `options` contains `subprocess_option_inherit_environment`, then | |
| /// `environment` must be NULL. | |
| subprocess_weak int | |
| subprocess_create_ex(const char *const command_line[], int options, | |
| const char *const environment[], | |
| struct subprocess_s *const out_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. | |
| subprocess_pure subprocess_weak FILE * | |
| subprocess_stdin(const struct subprocess_s *const 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. | |
| subprocess_pure subprocess_weak FILE * | |
| subprocess_stdout(const struct subprocess_s *const 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 subprocess_option_combined_stdout_stderr | |
| /// option bit set, this function will return NULL, and the subprocess_stdout | |
| /// function should be used for both the standard output and error combined. | |
| subprocess_pure subprocess_weak FILE * | |
| subprocess_stderr(const struct subprocess_s *const process); | |
| /// @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. | |
| subprocess_weak int subprocess_join(struct subprocess_s *const process, | |
| int *const out_return_code); | |
| /// @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. | |
| subprocess_weak int subprocess_destroy(struct subprocess_s *const 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). | |
| subprocess_weak int subprocess_terminate(struct subprocess_s *const 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 `subprocess_option_enable_async` option in | |
| /// conjunction with this method. | |
| subprocess_weak unsigned | |
| subprocess_read_stdout(struct subprocess_s *const process, char *const buffer, | |
| unsigned 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 `subprocess_option_enable_async` option in | |
| /// conjunction with this method. | |
| subprocess_weak unsigned | |
| subprocess_read_stderr(struct subprocess_s *const process, char *const buffer, | |
| unsigned 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. | |
| subprocess_weak int subprocess_alive(struct subprocess_s *const process); | |
| typedef __int64 subprocess_intptr_t; | |
| typedef unsigned __int64 subprocess_size_t; | |
| typedef int subprocess_intptr_t; | |
| typedef unsigned int subprocess_size_t; | |
| typedef intptr_t subprocess_intptr_t; | |
| typedef size_t subprocess_size_t; | |
| typedef struct _PROCESS_INFORMATION *LPPROCESS_INFORMATION; | |
| typedef struct _SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES; | |
| typedef struct _STARTUPINFOA *LPSTARTUPINFOA; | |
| typedef struct _OVERLAPPED *LPOVERLAPPED; | |
| struct subprocess_subprocess_information_s { | |
| void *hProcess; | |
| void *hThread; | |
| unsigned long dwProcessId; | |
| unsigned long dwThreadId; | |
| }; | |
| struct subprocess_security_attributes_s { | |
| unsigned long nLength; | |
| void *lpSecurityDescriptor; | |
| int bInheritHandle; | |
| }; | |
| struct subprocess_startup_info_s { | |
| unsigned long cb; | |
| char *lpReserved; | |
| char *lpDesktop; | |
| char *lpTitle; | |
| unsigned long dwX; | |
| unsigned long dwY; | |
| unsigned long dwXSize; | |
| unsigned long dwYSize; | |
| unsigned long dwXCountChars; | |
| unsigned long dwYCountChars; | |
| unsigned long dwFillAttribute; | |
| unsigned long dwFlags; | |
| unsigned short wShowWindow; | |
| unsigned short cbReserved2; | |
| unsigned char *lpReserved2; | |
| void *hStdInput; | |
| void *hStdOutput; | |
| void *hStdError; | |
| }; | |
| struct subprocess_overlapped_s { | |
| uintptr_t Internal; | |
| uintptr_t InternalHigh; | |
| union { | |
| struct { | |
| unsigned long Offset; | |
| unsigned long OffsetHigh; | |
| } DUMMYSTRUCTNAME; | |
| void *Pointer; | |
| } DUMMYUNIONNAME; | |
| void *hEvent; | |
| }; | |
| __declspec(dllimport) unsigned long __stdcall GetLastError(void); | |
| __declspec(dllimport) int __stdcall SetHandleInformation(void *, unsigned long, | |
| unsigned long); | |
| __declspec(dllimport) int __stdcall CreatePipe(void **, void **, | |
| LPSECURITY_ATTRIBUTES, | |
| unsigned long); | |
| __declspec(dllimport) void *__stdcall CreateNamedPipeA( | |
| const char *, unsigned long, unsigned long, unsigned long, unsigned long, | |
| unsigned long, unsigned long, LPSECURITY_ATTRIBUTES); | |
| __declspec(dllimport) int __stdcall ReadFile(void *, void *, unsigned long, | |
| unsigned long *, LPOVERLAPPED); | |
| __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(void); | |
| __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); | |
| __declspec(dllimport) void *__stdcall CreateFileA(const char *, unsigned long, | |
| unsigned long, | |
| LPSECURITY_ATTRIBUTES, | |
| unsigned long, unsigned long, | |
| void *); | |
| __declspec(dllimport) void *__stdcall CreateEventA(LPSECURITY_ATTRIBUTES, int, | |
| int, const char *); | |
| __declspec(dllimport) int __stdcall CreateProcessA( | |
| const char *, char *, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, int, | |
| unsigned long, void *, const char *, LPSTARTUPINFOA, LPPROCESS_INFORMATION); | |
| __declspec(dllimport) int __stdcall CloseHandle(void *); | |
| __declspec(dllimport) unsigned long __stdcall WaitForSingleObject( | |
| void *, unsigned long); | |
| __declspec(dllimport) int __stdcall GetExitCodeProcess( | |
| void *, unsigned long *lpExitCode); | |
| __declspec(dllimport) int __stdcall TerminateProcess(void *, unsigned int); | |
| __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects( | |
| unsigned long, void *const *, int, unsigned long); | |
| __declspec(dllimport) int __stdcall GetOverlappedResult(void *, LPOVERLAPPED, | |
| unsigned long *, int); | |
| SUBPROCESS_DLLIMPORT int __cdecl _fileno(FILE *); | |
| SUBPROCESS_DLLIMPORT int __cdecl _open_osfhandle(subprocess_intptr_t, int); | |
| SUBPROCESS_DLLIMPORT subprocess_intptr_t __cdecl _get_osfhandle(int); | |
| void *__cdecl _alloca(subprocess_size_t); | |
| typedef size_t subprocess_size_t; | |
| struct subprocess_s { | |
| FILE *stdin_file; | |
| FILE *stdout_file; | |
| FILE *stderr_file; | |
| void *hProcess; | |
| void *hStdInput; | |
| void *hEventOutput; | |
| void *hEventError; | |
| pid_t child; | |
| int return_status; | |
| subprocess_size_t alive; | |
| }; | |
| subprocess_weak int subprocess_create_named_pipe_helper(void **rd, void **wr); | |
| int subprocess_create_named_pipe_helper(void **rd, void **wr) { | |
| const unsigned long pipeAccessInbound = 0x00000001; | |
| const unsigned long fileFlagOverlapped = 0x40000000; | |
| const unsigned long pipeTypeByte = 0x00000000; | |
| const unsigned long pipeWait = 0x00000000; | |
| const unsigned long genericWrite = 0x40000000; | |
| const unsigned long openExisting = 3; | |
| const unsigned long fileAttributeNormal = 0x00000080; | |
| const void *const invalidHandleValue = | |
| SUBPROCESS_PTR_CAST(void *, ~(SUBPROCESS_CAST(subprocess_intptr_t, 0))); | |
| struct subprocess_security_attributes_s saAttr = {sizeof(saAttr), | |
| SUBPROCESS_NULL, 1}; | |
| char name[256] = {0}; | |
| static subprocess_tls long index = 0; | |
| const long unique = index++; | |
| _snprintf(name, sizeof(name) - 1, | |
| "\\\\.\\pipe\\sheredom_subprocess_h.%08lx.%08lx.%ld", | |
| GetCurrentProcessId(), GetCurrentThreadId(), unique); | |
| snprintf(name, sizeof(name) - 1, | |
| "\\\\.\\pipe\\sheredom_subprocess_h.%08lx.%08lx.%ld", | |
| GetCurrentProcessId(), GetCurrentThreadId(), unique); | |
| *rd = | |
| CreateNamedPipeA(name, pipeAccessInbound | fileFlagOverlapped, | |
| pipeTypeByte | pipeWait, 1, 4096, 4096, SUBPROCESS_NULL, | |
| SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr)); | |
| if (invalidHandleValue == *rd) { | |
| return -1; | |
| } | |
| *wr = CreateFileA(name, genericWrite, SUBPROCESS_NULL, | |
| SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), | |
| openExisting, fileAttributeNormal, SUBPROCESS_NULL); | |
| if (invalidHandleValue == *wr) { | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| int subprocess_create(const char *const commandLine[], int options, | |
| struct subprocess_s *const out_process) { | |
| return subprocess_create_ex(commandLine, options, SUBPROCESS_NULL, | |
| out_process); | |
| } | |
| int subprocess_create_ex(const char *const commandLine[], int options, | |
| const char *const environment[], | |
| struct subprocess_s *const out_process) { | |
| int fd; | |
| void *rd, *wr; | |
| char *commandLineCombined; | |
| subprocess_size_t len; | |
| int i, j; | |
| int need_quoting; | |
| unsigned long flags = 0; | |
| const unsigned long startFUseStdHandles = 0x00000100; | |
| const unsigned long handleFlagInherit = 0x00000001; | |
| const unsigned long createNoWindow = 0x08000000; | |
| struct subprocess_subprocess_information_s processInfo; | |
| struct subprocess_security_attributes_s saAttr = {sizeof(saAttr), | |
| SUBPROCESS_NULL, 1}; | |
| char *used_environment = SUBPROCESS_NULL; | |
| struct subprocess_startup_info_s startInfo = {0, | |
| SUBPROCESS_NULL, | |
| SUBPROCESS_NULL, | |
| SUBPROCESS_NULL, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| SUBPROCESS_NULL, | |
| SUBPROCESS_NULL, | |
| SUBPROCESS_NULL, | |
| SUBPROCESS_NULL}; | |
| startInfo.cb = sizeof(startInfo); | |
| startInfo.dwFlags = startFUseStdHandles; | |
| if (subprocess_option_no_window == (options & subprocess_option_no_window)) { | |
| flags |= createNoWindow; | |
| } | |
| if (subprocess_option_inherit_environment != | |
| (options & subprocess_option_inherit_environment)) { | |
| if (SUBPROCESS_NULL == environment) { | |
| used_environment = SUBPROCESS_CONST_CAST(char *, "\0\0"); | |
| } else { | |
| // We always end with two null terminators. | |
| len = 2; | |
| for (i = 0; environment[i]; i++) { | |
| for (j = 0; '\0' != environment[i][j]; j++) { | |
| len++; | |
| } | |
| // For the null terminator too. | |
| len++; | |
| } | |
| used_environment = SUBPROCESS_CAST(char *, _alloca(len)); | |
| // Re-use len for the insertion position | |
| len = 0; | |
| for (i = 0; environment[i]; i++) { | |
| for (j = 0; '\0' != environment[i][j]; j++) { | |
| used_environment[len++] = environment[i][j]; | |
| } | |
| used_environment[len++] = '\0'; | |
| } | |
| // End with the two null terminators. | |
| used_environment[len++] = '\0'; | |
| used_environment[len++] = '\0'; | |
| } | |
| } else { | |
| if (SUBPROCESS_NULL != environment) { | |
| return -1; | |
| } | |
| } | |
| if (!CreatePipe(&rd, &wr, SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), | |
| 0)) { | |
| return -1; | |
| } | |
| if (!SetHandleInformation(wr, handleFlagInherit, 0)) { | |
| return -1; | |
| } | |
| fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, wr), 0); | |
| if (-1 != fd) { | |
| out_process->stdin_file = _fdopen(fd, "wb"); | |
| if (SUBPROCESS_NULL == out_process->stdin_file) { | |
| return -1; | |
| } | |
| } | |
| startInfo.hStdInput = rd; | |
| if (options & subprocess_option_enable_async) { | |
| if (subprocess_create_named_pipe_helper(&rd, &wr)) { | |
| return -1; | |
| } | |
| } else { | |
| if (!CreatePipe(&rd, &wr, | |
| SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 0)) { | |
| return -1; | |
| } | |
| } | |
| if (!SetHandleInformation(rd, handleFlagInherit, 0)) { | |
| return -1; | |
| } | |
| fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, rd), 0); | |
| if (-1 != fd) { | |
| out_process->stdout_file = _fdopen(fd, "rb"); | |
| if (SUBPROCESS_NULL == out_process->stdout_file) { | |
| return -1; | |
| } | |
| } | |
| startInfo.hStdOutput = wr; | |
| if (subprocess_option_combined_stdout_stderr == | |
| (options & subprocess_option_combined_stdout_stderr)) { | |
| out_process->stderr_file = out_process->stdout_file; | |
| startInfo.hStdError = startInfo.hStdOutput; | |
| } else { | |
| if (options & subprocess_option_enable_async) { | |
| if (subprocess_create_named_pipe_helper(&rd, &wr)) { | |
| return -1; | |
| } | |
| } else { | |
| if (!CreatePipe(&rd, &wr, | |
| SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 0)) { | |
| return -1; | |
| } | |
| } | |
| if (!SetHandleInformation(rd, handleFlagInherit, 0)) { | |
| return -1; | |
| } | |
| fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, rd), 0); | |
| if (-1 != fd) { | |
| out_process->stderr_file = _fdopen(fd, "rb"); | |
| if (SUBPROCESS_NULL == out_process->stderr_file) { | |
| return -1; | |
| } | |
| } | |
| startInfo.hStdError = wr; | |
| } | |
| if (options & subprocess_option_enable_async) { | |
| out_process->hEventOutput = | |
| CreateEventA(SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 1, 1, | |
| SUBPROCESS_NULL); | |
| out_process->hEventError = | |
| CreateEventA(SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 1, 1, | |
| SUBPROCESS_NULL); | |
| } else { | |
| out_process->hEventOutput = SUBPROCESS_NULL; | |
| out_process->hEventError = SUBPROCESS_NULL; | |
| } | |
| // Combine commandLine together into a single string | |
| len = 0; | |
| for (i = 0; commandLine[i]; i++) { | |
| // for the trailing \0 | |
| len++; | |
| // Quote the argument if it has a space in it | |
| if (strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL || | |
| commandLine[i][0] == SUBPROCESS_NULL) | |
| len += 2; | |
| for (j = 0; '\0' != commandLine[i][j]; j++) { | |
| switch (commandLine[i][j]) { | |
| default: | |
| break; | |
| case '\\': | |
| if (commandLine[i][j + 1] == '"') { | |
| len++; | |
| } | |
| break; | |
| case '"': | |
| len++; | |
| break; | |
| } | |
| len++; | |
| } | |
| } | |
| commandLineCombined = SUBPROCESS_CAST(char *, _alloca(len)); | |
| if (!commandLineCombined) { | |
| return -1; | |
| } | |
| // Gonna re-use len to store the write index into commandLineCombined | |
| len = 0; | |
| for (i = 0; commandLine[i]; i++) { | |
| if (0 != i) { | |
| commandLineCombined[len++] = ' '; | |
| } | |
| need_quoting = strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL || | |
| commandLine[i][0] == SUBPROCESS_NULL; | |
| if (need_quoting) { | |
| commandLineCombined[len++] = '"'; | |
| } | |
| for (j = 0; '\0' != commandLine[i][j]; j++) { | |
| switch (commandLine[i][j]) { | |
| default: | |
| break; | |
| case '\\': | |
| if (commandLine[i][j + 1] == '"') { | |
| commandLineCombined[len++] = '\\'; | |
| } | |
| break; | |
| case '"': | |
| commandLineCombined[len++] = '\\'; | |
| break; | |
| } | |
| commandLineCombined[len++] = commandLine[i][j]; | |
| } | |
| if (need_quoting) { | |
| commandLineCombined[len++] = '"'; | |
| } | |
| } | |
| commandLineCombined[len] = '\0'; | |
| if (!CreateProcessA( | |
| SUBPROCESS_NULL, | |
| commandLineCombined, // command line | |
| SUBPROCESS_NULL, // process security attributes | |
| SUBPROCESS_NULL, // primary thread security attributes | |
| 1, // handles are inherited | |
| flags, // creation flags | |
| used_environment, // used environment | |
| SUBPROCESS_NULL, // use parent's current directory | |
| SUBPROCESS_PTR_CAST(LPSTARTUPINFOA, | |
| &startInfo), // STARTUPINFO pointer | |
| SUBPROCESS_PTR_CAST(LPPROCESS_INFORMATION, &processInfo))) { | |
| return -1; | |
| } | |
| out_process->hProcess = processInfo.hProcess; | |
| out_process->hStdInput = startInfo.hStdInput; | |
| // We don't need the handle of the primary thread in the called process. | |
| CloseHandle(processInfo.hThread); | |
| if (SUBPROCESS_NULL != startInfo.hStdOutput) { | |
| CloseHandle(startInfo.hStdOutput); | |
| if (startInfo.hStdError != startInfo.hStdOutput) { | |
| CloseHandle(startInfo.hStdError); | |
| } | |
| } | |
| out_process->alive = 1; | |
| return 0; | |
| int stdinfd[2]; | |
| int stdoutfd[2]; | |
| int stderrfd[2]; | |
| pid_t child; | |
| extern char **environ; | |
| char *const empty_environment[1] = {SUBPROCESS_NULL}; | |
| posix_spawn_file_actions_t actions; | |
| char *const *used_environment; | |
| if (subprocess_option_inherit_environment == | |
| (options & subprocess_option_inherit_environment)) { | |
| if (SUBPROCESS_NULL != environment) { | |
| return -1; | |
| } | |
| } | |
| if (0 != pipe(stdinfd)) { | |
| return -1; | |
| } | |
| if (0 != pipe(stdoutfd)) { | |
| return -1; | |
| } | |
| if (subprocess_option_combined_stdout_stderr != | |
| (options & subprocess_option_combined_stdout_stderr)) { | |
| if (0 != pipe(stderrfd)) { | |
| return -1; | |
| } | |
| } | |
| if (environment) { | |
| used_environment = SUBPROCESS_CONST_CAST(char *const *, environment); | |
| } else if (subprocess_option_inherit_environment == | |
| (options & subprocess_option_inherit_environment)) { | |
| used_environment = environ; | |
| } else { | |
| used_environment = empty_environment; | |
| } | |
| if (0 != posix_spawn_file_actions_init(&actions)) { | |
| return -1; | |
| } | |
| // Close the stdin write end | |
| if (0 != posix_spawn_file_actions_addclose(&actions, stdinfd[1])) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| // Map the read end to stdin | |
| if (0 != | |
| posix_spawn_file_actions_adddup2(&actions, stdinfd[0], STDIN_FILENO)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| // Close the stdout read end | |
| if (0 != posix_spawn_file_actions_addclose(&actions, stdoutfd[0])) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| // Map the write end to stdout | |
| if (0 != | |
| posix_spawn_file_actions_adddup2(&actions, stdoutfd[1], STDOUT_FILENO)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| if (subprocess_option_combined_stdout_stderr == | |
| (options & subprocess_option_combined_stdout_stderr)) { | |
| if (0 != posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, | |
| STDERR_FILENO)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| } else { | |
| // Close the stderr read end | |
| if (0 != posix_spawn_file_actions_addclose(&actions, stderrfd[0])) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| // Map the write end to stdout | |
| if (0 != posix_spawn_file_actions_adddup2(&actions, stderrfd[1], | |
| STDERR_FILENO)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| } | |
| if (subprocess_option_search_user_path == | |
| (options & subprocess_option_search_user_path)) { | |
| if (0 != posix_spawnp(&child, commandLine[0], &actions, SUBPROCESS_NULL, | |
| SUBPROCESS_CONST_CAST(char *const *, commandLine), | |
| used_environment)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| } else { | |
| if (0 != posix_spawn(&child, commandLine[0], &actions, SUBPROCESS_NULL, | |
| SUBPROCESS_CONST_CAST(char *const *, commandLine), | |
| used_environment)) { | |
| posix_spawn_file_actions_destroy(&actions); | |
| return -1; | |
| } | |
| } | |
| // Close the stdin read end | |
| close(stdinfd[0]); | |
| // Store the stdin write end | |
| out_process->stdin_file = fdopen(stdinfd[1], "wb"); | |
| // Close the stdout write end | |
| close(stdoutfd[1]); | |
| // Store the stdout read end | |
| out_process->stdout_file = fdopen(stdoutfd[0], "rb"); | |
| if (subprocess_option_combined_stdout_stderr == | |
| (options & subprocess_option_combined_stdout_stderr)) { | |
| out_process->stderr_file = out_process->stdout_file; | |
| } else { | |
| // Close the stderr write end | |
| close(stderrfd[1]); | |
| // Store the stderr read end | |
| out_process->stderr_file = fdopen(stderrfd[0], "rb"); | |
| } | |
| // Store the child's pid | |
| out_process->child = child; | |
| out_process->alive = 1; | |
| posix_spawn_file_actions_destroy(&actions); | |
| return 0; | |
| } | |
| FILE *subprocess_stdin(const struct subprocess_s *const process) { | |
| return process->stdin_file; | |
| } | |
| FILE *subprocess_stdout(const struct subprocess_s *const process) { | |
| return process->stdout_file; | |
| } | |
| FILE *subprocess_stderr(const struct subprocess_s *const process) { | |
| if (process->stdout_file != process->stderr_file) { | |
| return process->stderr_file; | |
| } else { | |
| return SUBPROCESS_NULL; | |
| } | |
| } | |
| int subprocess_join(struct subprocess_s *const process, | |
| int *const out_return_code) { | |
| const unsigned long infinite = 0xFFFFFFFF; | |
| if (process->stdin_file) { | |
| fclose(process->stdin_file); | |
| process->stdin_file = SUBPROCESS_NULL; | |
| } | |
| if (process->hStdInput) { | |
| CloseHandle(process->hStdInput); | |
| process->hStdInput = SUBPROCESS_NULL; | |
| } | |
| WaitForSingleObject(process->hProcess, infinite); | |
| if (out_return_code) { | |
| if (!GetExitCodeProcess( | |
| process->hProcess, | |
| SUBPROCESS_PTR_CAST(unsigned long *, out_return_code))) { | |
| return -1; | |
| } | |
| } | |
| process->alive = 0; | |
| return 0; | |
| int status; | |
| if (process->stdin_file) { | |
| fclose(process->stdin_file); | |
| process->stdin_file = SUBPROCESS_NULL; | |
| } | |
| if (process->child) { | |
| if (process->child != waitpid(process->child, &status, 0)) { | |
| return -1; | |
| } | |
| process->child = 0; | |
| if (WIFEXITED(status)) { | |
| process->return_status = WEXITSTATUS(status); | |
| } else { | |
| process->return_status = EXIT_FAILURE; | |
| } | |
| process->alive = 0; | |
| } | |
| if (out_return_code) { | |
| *out_return_code = process->return_status; | |
| } | |
| return 0; | |
| } | |
| int subprocess_destroy(struct subprocess_s *const process) { | |
| if (process->stdin_file) { | |
| fclose(process->stdin_file); | |
| process->stdin_file = SUBPROCESS_NULL; | |
| } | |
| if (process->stdout_file) { | |
| fclose(process->stdout_file); | |
| if (process->stdout_file != process->stderr_file) { | |
| fclose(process->stderr_file); | |
| } | |
| process->stdout_file = SUBPROCESS_NULL; | |
| process->stderr_file = SUBPROCESS_NULL; | |
| } | |
| if (process->hProcess) { | |
| CloseHandle(process->hProcess); | |
| process->hProcess = SUBPROCESS_NULL; | |
| if (process->hStdInput) { | |
| CloseHandle(process->hStdInput); | |
| } | |
| if (process->hEventOutput) { | |
| CloseHandle(process->hEventOutput); | |
| } | |
| if (process->hEventError) { | |
| CloseHandle(process->hEventError); | |
| } | |
| } | |
| return 0; | |
| } | |
| int subprocess_terminate(struct subprocess_s *const process) { | |
| unsigned int killed_process_exit_code; | |
| int success_terminate; | |
| int windows_call_result; | |
| killed_process_exit_code = 99; | |
| windows_call_result = | |
| TerminateProcess(process->hProcess, killed_process_exit_code); | |
| success_terminate = (windows_call_result == 0) ? 1 : 0; | |
| return success_terminate; | |
| int result; | |
| result = kill(process->child, 9); | |
| return result; | |
| } | |
| unsigned subprocess_read_stdout(struct subprocess_s *const process, | |
| char *const buffer, unsigned size) { | |
| void *handle; | |
| unsigned long bytes_read = 0; | |
| struct subprocess_overlapped_s overlapped = {0, 0, {{0, 0}}, SUBPROCESS_NULL}; | |
| overlapped.hEvent = process->hEventOutput; | |
| handle = SUBPROCESS_PTR_CAST(void *, | |
| _get_osfhandle(_fileno(process->stdout_file))); | |
| if (!ReadFile(handle, buffer, size, &bytes_read, | |
| SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped))) { | |
| const unsigned long errorIoPending = 997; | |
| unsigned long error = GetLastError(); | |
| // Means we've got an async read! | |
| if (error == errorIoPending) { | |
| if (!GetOverlappedResult(handle, | |
| SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped), | |
| &bytes_read, 1)) { | |
| const unsigned long errorIoIncomplete = 996; | |
| const unsigned long errorHandleEOF = 38; | |
| error = GetLastError(); | |
| if ((error != errorIoIncomplete) && (error != errorHandleEOF)) { | |
| return 0; | |
| } | |
| } | |
| } | |
| } | |
| return SUBPROCESS_CAST(unsigned, bytes_read); | |
| const int fd = fileno(process->stdout_file); | |
| const ssize_t bytes_read = read(fd, buffer, size); | |
| if (bytes_read < 0) { | |
| return 0; | |
| } | |
| return SUBPROCESS_CAST(unsigned, bytes_read); | |
| } | |
| unsigned subprocess_read_stderr(struct subprocess_s *const process, | |
| char *const buffer, unsigned size) { | |
| void *handle; | |
| unsigned long bytes_read = 0; | |
| struct subprocess_overlapped_s overlapped = {0, 0, {{0, 0}}, SUBPROCESS_NULL}; | |
| overlapped.hEvent = process->hEventError; | |
| handle = SUBPROCESS_PTR_CAST(void *, | |
| _get_osfhandle(_fileno(process->stderr_file))); | |
| if (!ReadFile(handle, buffer, size, &bytes_read, | |
| SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped))) { | |
| const unsigned long errorIoPending = 997; | |
| unsigned long error = GetLastError(); | |
| // Means we've got an async read! | |
| if (error == errorIoPending) { | |
| if (!GetOverlappedResult(handle, | |
| SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped), | |
| &bytes_read, 1)) { | |
| const unsigned long errorIoIncomplete = 996; | |
| const unsigned long errorHandleEOF = 38; | |
| error = GetLastError(); | |
| if ((error != errorIoIncomplete) && (error != errorHandleEOF)) { | |
| return 0; | |
| } | |
| } | |
| } | |
| } | |
| return SUBPROCESS_CAST(unsigned, bytes_read); | |
| const int fd = fileno(process->stderr_file); | |
| const ssize_t bytes_read = read(fd, buffer, size); | |
| if (bytes_read < 0) { | |
| return 0; | |
| } | |
| return SUBPROCESS_CAST(unsigned, bytes_read); | |
| } | |
| int subprocess_alive(struct subprocess_s *const process) { | |
| int is_alive = SUBPROCESS_CAST(int, process->alive); | |
| if (!is_alive) { | |
| return 0; | |
| } | |
| { | |
| const unsigned long zero = 0x0; | |
| const unsigned long wait_object_0 = 0x00000000L; | |
| is_alive = wait_object_0 != WaitForSingleObject(process->hProcess, zero); | |
| } | |
| { | |
| int status; | |
| is_alive = 0 == waitpid(process->child, &status, WNOHANG); | |
| // If the process was successfully waited on we need to cleanup now. | |
| if (!is_alive) { | |
| if (WIFEXITED(status)) { | |
| process->return_status = WEXITSTATUS(status); | |
| } else { | |
| process->return_status = EXIT_FAILURE; | |
| } | |
| // Since we've already successfully waited on the process, we need to wipe | |
| // the child now. | |
| process->child = 0; | |
| if (subprocess_join(process, SUBPROCESS_NULL)) { | |
| return -1; | |
| } | |
| } | |
| } | |
| if (!is_alive) { | |
| process->alive = 0; | |
| } | |
| return is_alive; | |
| } | |
| } // extern "C" | |