Skip to content

Instantly share code, notes, and snippets.

@opsJson
Created June 7, 2023 01:22
Show Gist options
  • Save opsJson/515644eff27b29ad91b79522ca3b2c40 to your computer and use it in GitHub Desktop.
Save opsJson/515644eff27b29ad91b79522ca3b2c40 to your computer and use it in GitHub Desktop.
Pipe output of any command line program to buffer in C.
#ifndef CMDL_H_
#define CMDL_H_
#ifdef _WIN32
#include <windows.h>
static const char *cmdl_errlist[] = {
"No Error.",
"CreatePipe() failed: could not create a pipe.",
"CreateProcessA() failed: could not create child process.",
"CloseHandle() failed: could not close write end of pipe.",
"CloseHandle() failed: could not close read end of pipe.",
"CloseHandle() failed: could not close thread.",
"CloseHandle() failed: could not close process.",
};
static const unsigned int cmdl_errlist_size = sizeof(cmdl_errlist)/sizeof(cmdl_errlist[0]);
static unsigned int cmdl_errno = 0;
const char *cmdl_strerror(void) {
if (cmdl_errno >= cmdl_errlist_size) return "Invalid Error.";
return cmdl_errlist[cmdl_errno];
}
int cmdl_win32(char *command, char *buffer, int size) {
HANDLE pipefd[2];
STARTUPINFOA si = {0};
PROCESS_INFORMATION pi = {0};
SECURITY_ATTRIBUTES sa = {0};
DWORD bytes;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = 1;
if (!CreatePipe(&pipefd[0], &pipefd[1], &sa, 0)) {
cmdl_errno = 1;
return 0;
}
si.cb = sizeof(si);
si.hStdOutput = pipefd[1];
si.dwFlags = STARTF_USESTDHANDLES;
if (!CreateProcessA(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
cmdl_errno = 2;
return 0;
}
if (!CloseHandle(pipefd[1])) {
cmdl_errno = 3;
return 0;
}
while (size) {
if (!ReadFile(pipefd[0], buffer, size, &bytes, NULL)) break;
buffer += bytes;
size -= bytes;
}
if (!CloseHandle(pipefd[0])) {
cmdl_errno = 4;
return 0;
}
if (!CloseHandle(pi.hThread)) {
cmdl_errno = 5;
return 0;
}
if (!CloseHandle(pi.hProcess)) {
cmdl_errno = 6;
return 0;
}
return 1;
}
#define cmdl cmdl_win32
#else
#include <unistd.h>
#include <sys/types.h>
static const char *cmdl_errlist[] = {
"No Error.",
"pipe() failed: could not create a pipe.",
"fork() failed: could fork the process.",
"close() failed: could close the read end of child process.",
"dup2() failed: could reopen the write end of child process as parent stdout.",
"close() failed: could close the old write end of child process.",
"execlp() failed: could not execute command.",
"close() failed: could close the write end of parent process.",
"read() failed: could read from child process.",
};
static const unsigned int cmdl_errlist_size = sizeof(cmdl_errlist)/sizeof(cmdl_errlist[0]);
static unsigned int cmdl_errno = 0;
const char *cmdl_strerror(void) {
if (cmdl_errno >= cmdl_errlist_size) return "Invalid Error.";
return cmdl_errlist[cmdl_errno];
}
int cmdl_posix(char *command, char *buffer, int size) {
pid_t pid;
int pipefd[2];
if (pipe(pipefd) < 0) {
cmdl_errno = 1;
return 0;
}
pid = fork();
if (pid < 0) {
cmdl_errno = 2;
return 0;
}
if (pid == 0) {
if (close(pipefd[0]) < 0) {
cmdl_errno = 3;
return 0;
}
if (dup2(pipefd[1], STDOUT_FILENO) < 0) {
cmdl_errno = 4;
return 0;
}
if (close(pipefd[1]) < 0) {
cmdl_errno = 5;
return 0;
}
if (execlp("sh", "sh", "-c", command, NULL) < 0) {
cmdl_errno = 6;
return 0;
}
}
else {
if (close(pipefd[1]) < 0) {
cmdl_errno = 7;
return 0;
}
if (read(pipefd[0], buffer, size) < 0) {
cmdl_errno = 8;
return 0;
}
}
return 1;
}
#define cmdl cmdl_posix
#endif /* _WIN32 */
#endif /* CMDL_H_ */
/*///////////////////////////////////
Testing:
///////////////////////////////////*/
#include <stdio.h>
int main() {
char buffer[2048] = {0};
if (!cmdl("curl github.com -L", buffer, sizeof(buffer))) {
printf("ERROR: %s\n", cmdl_strerror());
return 1;
}
printf("%s", buffer);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment