La commande dialog
imprime le résultat des sélections de l'utilisateur sur stderr. Cela signifie que vous devrez capturer stderr, pas stdout. C'est un peu difficile. Je vais aller tester moi-même, mais je pense que la meilleure chose à faire est d'utiliser popen
comme ceci:
FILE *dialog = popen("(dialog --menu plus other arguments >/dev/tty) 2>&1");
Ensuite, vous pouvez lire à partir du fichier dialog
(à condition qu'il n'est pas NULL bien sûr).
Cela fonctionne parce que l'argument de popen est effectivement passé à un appel de sh
. Cela signifie que popen fonctionne vraiment sh -c <argument of popen>
donc toutes les redirections de shell standard fonctionnent. Donc, vous utilisez des parenthèses pour obtenir exactement ce que vous voulez, qui est pour le programme de dialogue lui-même d'envoyer sa sortie à son terminal de contrôle, et pour son stderr d'être redirigé vers l'endroit où vous pouvez le lire avec popen.
Une autre méthode présente les mêmes inconvénients que la solution popen
et présente l'inconvénient supplémentaire de vous demander d'ouvrir et de lire un autre fichier une fois la boîte de dialogue terminée. Mais il a l'avantage de la simplicité. Malheureusement, il vous faut aussi être capable d'écrire sur le système de fichiers, et l'endroit le plus naturel pour le faire (/ tmp) est chargé de problèmes de sécurité pour s'assurer que quelqu'un d'autre ne détourne pas votre fichier. Cette méthode consiste à faire system("dialog --menu plus other arguments 2>temp_file");
. Ensuite, vous lisez depuis temp_file quand c'est fait.
Ce sont tous deux un peu moche, d'autant plus que la boîte de dialogue prend beaucoup d'arguments susceptibles d'avoir des métacaractères de shell.Donc, même si le travail ci-dessus, je recommande fortement d'utiliser une combinaison de pipe
, fork
, execvp
, fdopen
, et waitpid
pour obtenir le résultat que vous recherchez.
Un squelette pour cela ressemblerait à quelque chose comme ceci:
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
const char *dia_args[] = {
"dialog",
"--output-fd",
NULL,
"--menu",
"Hi there",
"60", "15", "15",
"t1", "i1",
"t2", "i2",
"t3", "i3",
"t4", "i4",
"t5", "i5",
NULL
};
int pipefds[2];
if (pipe(pipefds) < 0) {
perror("pipe failed");
return 1;
} else {
const pid_t child = fork();
if (child < 0) {
perror("fork failed");
return 1;
} else if (child == 0) {
char pipefdstr[60];
close(pipefds[0]);
if (snprintf(pipefdstr, sizeof(pipefdstr) - 1, "%u", pipefds[1]) < 0) {
perror("snprintf failed");
return 1;
} else {
pipefdstr[sizeof(pipefdstr) - 1] = '\0'; /* Protect against bugs in snprintf */
dia_args[2] = pipefdstr;
execvp(dia_args[0], dia_args);
perror("Unable to exec dialog command");
return 1;
}
} else { /* child > 0 */
FILE *dialog = fdopen(pipefds[0], "r");
char inbuf[200];
int waitresult = 0;
if (dialog == NULL) {
perror("Unable to fdopen");
kill(child, SIGKILL);
return 1;
}
close(pipefds[1]);
while (fgets(inbuf, sizeof(inbuf) - 1, dialog)) {
inbuf[sizeof(inbuf) - 1] = '\0';
printf("Got [%s] from dialog.\n", inbuf);
}
fclose(dialog);
if (waitpid(child, &waitresult, 0) < 0) {
perror("waitpid failed");
return 1;
}
if (!WIFEXITED(waitresult) || (WEXITSTATUS(waitresult) != 0)) {
fprintf(stderr, "dialog exited abnormally.");
return 1;
}
}
}
return 0;
}
J'ai utilisé la première option, cela fonctionnait parfaitement. Merci beaucoup. – HalfBrian
utilise 'fgets (inbuf, sizeof (inbuf), boîte de dialogue)' pas 'sizeof (inbuf) - 1'. lisez le manuel pour les fgets – user102008
@ user102008 - Même si je savais que ça pourrait être 'sizeof (inbuf)' j'utiliserais toujours 'sizeof (inbuf) - 1' pour me protéger contre les erreurs d'implémentation dans' fgets'. – Omnifarious