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