prgbox.c revision 220749
1/*
2 *  $Id: prgbox.c,v 1.6 2011/03/02 09:59:26 tom Exp $
3 *
4 *  prgbox.c -- implements the prg box
5 *
6 *  Copyright 2011	Thomas E. Dickey
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU Lesser General Public License as
10 *  published by the Free Software Foundation; either version 2.1 of the
11 *  License, or (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful, but
14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  Lesser General Public License for more details.
17 *
18 *  You should have received a copy of the GNU Lesser General Public
19 *  License along with this program; if not, write to
20 *	Free Software Foundation, Inc.
21 *	51 Franklin St., Fifth Floor
22 *	Boston, MA 02110, USA.
23 */
24
25#include <dialog.h>
26
27/*
28 * Open a pipe which ties stderr and stdout together.
29 */
30static FILE *
31dlg_popen(const char *command, const char *type)
32{
33    FILE *result = 0;
34    int fd[2];
35    int pid;
36    char *blob;
37    char **argv;
38
39    if ((*type == 'r' || *type != 'w') && pipe(fd) == 0) {
40	switch (pid = fork()) {
41	case -1:		/* Error. */
42	    (void) close(fd[0]);
43	    (void) close(fd[1]);
44	    break;
45	case 0:		/* child. */
46	    if (*type == 'r') {
47		if (fd[1] != STDOUT_FILENO) {
48		    (void) dup2(fd[1], STDOUT_FILENO);
49		    (void) close(fd[1]);
50		}
51		(void) dup2(STDOUT_FILENO, STDERR_FILENO);
52		(void) close(fd[0]);
53	    } else {
54		if (fd[0] != STDIN_FILENO) {
55		    (void) dup2(fd[0], STDIN_FILENO);
56		    (void) close(fd[0]);
57		}
58		(void) close(fd[1]);
59		(void) close(STDERR_FILENO);
60	    }
61	    /*
62	     * Bourne shell needs "-c" option to force it to use only the
63	     * given command.  Also, it needs the command to be parsed into
64	     * tokens.
65	     */
66	    if ((blob = malloc(4 + strlen(command))) != 0) {
67		sprintf(blob, "-c %s", command);
68		argv = dlg_string_to_argv(blob);
69		execvp("sh", argv);
70	    }
71	    _exit(127);
72	    /* NOTREACHED */
73	default:		/* parent */
74	    if (*type == 'r') {
75		result = fdopen(fd[0], type);
76		(void) close(fd[1]);
77	    } else {
78		result = fdopen(fd[1], type);
79		(void) close(fd[0]);
80	    }
81	    break;
82	}
83    }
84
85    return result;
86}
87
88/*
89 * Display text from a pipe in a scrolling window.
90 */
91int
92dialog_prgbox(const char *title,
93	      const char *cprompt,
94	      const char *command,
95	      int height,
96	      int width,
97	      int pauseopt)
98{
99    int code;
100    FILE *fp;
101
102    fp = dlg_popen(command, "r");
103    if (fp == NULL)
104	dlg_exiterr("pipe open failed: %s", command);
105
106    code = dlg_progressbox(title, cprompt, height, width, pauseopt, fp);
107
108    pclose(fp);
109
110    return code;
111}
112