Я не доверяю popen/pclose
, так как я работал на слишком многих системах, где SIGCHLD
обрабатывался немного по-другому. И я не доверяю синтаксическому анализу sh
, используемому popen
, поскольку я редко его использую.
Короткая 22-летняя книга О'Рейли Использование C в системе UNIX Дэйва Карри по-прежнему очень хороший справочник для такого рода вещей.
В любом случае, вот код. Он немного длинен, так как он разбирает пример строки "/bin/ls /etc"
в массив {"/bin/ls", "/etc", 0}
. Но я считаю, что использовать формат строки проще и короче 98% времени, хотя этот пример опровергает это.
Этот код генерирует список /etc.
Вам нужно изменить некоторые вещи, например, например. NUMBER()
, что совпадает с XtNumber()
. И вам нужно решить, соответствует ли оно вашей обработке SIGCHLD
.
int main(void) { // list the files in /etc
char buf[100];
FILE *fp;
int pid = spawnfp("/bin/ls /etc", &fp);
while (fgets(buf, sizeof buf, fp))
printf("%s", buf);
fclose(fp); // pclose() replacement
kill(pid, SIGKILL); // pclose() replacement
return 0;
}
Подпрограммы здесь:
static int spawnpipe(const char *argv[], int *fd) // popen() replacement
{
int pid;
int pipe_fds[2];
if (pipe(pipe_fds) < 0)
FatalError("pipe");
switch ((pid = fork()))
{
case -1:
FatalError("fork");
case 0: // child
close(1);
close(2);
dup(pipe_fds[0]);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execv(argv[0], (char * const *)argv);
perror("execv");
_exit(EXIT_FAILURE); // sic, not exit()
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
Это преобразует строку ascii в список argv
, который, вероятно, бесполезен для вас:
Bool convertStringToArgvList(char *p, const char **argv, int maxNumArgs)
{
// Break up a string into tokens, on spaces, except that quoted bits,
// with single-quotes, are kept together, without the quotes. Such
// single-quotes cannot be escaped. A double-quote is just an ordinary char.
// This is a *very* basic parsing, but ok for pre-programmed strings.
int cnt = 0;
while (*p)
{
while (*p && *p <= ' ') // skip spaces
p++;
if (*p == '\'') // single-quote block
{
if (cnt < maxNumArgs)
argv[cnt++] = ++p; // drop quote
while (*p && *p != '\'')
p++;
}
else if (*p) // simple space-delineated token
{
if (cnt < maxNumArgs)
argv[cnt++] = p;
while (*p > ' ')
p++;
}
if (*p)
*p++ = 0; // nul-terminate
}
if (cnt < maxNumArgs)
argv[cnt++] = 0;
return cnt <= maxNumArgs; // check for too many tokens (unlikely)
}
Это преобразует строку аргумента в токены и, что более важно, fd
в fp
, так как OP запросил stdout
:
int spawnfp(const char *command, FILE **fpp)
{
const char *argv[100];
int fd, pid;
if (!convertStringToArgvList(strdupa(command), argv, NUMBER(argv)))
FatalError("spawnfp");
pid = spawnpipe(argv, &fd);
*fpp = fdopen(fd, "r");
return pid;
}