prgbox.c revision 220750
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    const char *argv[4];
37
38    if ((*type == 'r' || *type != 'w') && pipe(fd) == 0) {
39	switch (pid = fork()) {
40	case -1:		/* Error. */
41	    (void) close(fd[0]);
42	    (void) close(fd[1]);
43	    break;
44	case 0:		/* child. */
45	    if (*type == 'r') {
46		if (fd[1] != STDOUT_FILENO) {
47		    (void) dup2(fd[1], STDOUT_FILENO);
48		    (void) close(fd[1]);
49		}
50		(void) dup2(STDOUT_FILENO, STDERR_FILENO);
51		(void) close(fd[0]);
52	    } else {
53		if (fd[0] != STDIN_FILENO) {
54		    (void) dup2(fd[0], STDIN_FILENO);
55		    (void) close(fd[0]);
56		}
57		(void) close(fd[1]);
58		(void) close(STDERR_FILENO);
59	    }
60	    /*
61	     * Bourne shell needs "-c" option to force it to use only the
62	     * given command.  Also, it needs the command to be parsed into
63	     * tokens.
64	     */
65	    argv[0] = "sh";
66	    argv[1] = "-c";
67	    argv[2] = command;
68	    argv[3] = NULL;
69	    execvp("sh", (char **)argv);
70	    _exit(127);
71	    /* NOTREACHED */
72	default:		/* parent */
73	    if (*type == 'r') {
74		result = fdopen(fd[0], type);
75		(void) close(fd[1]);
76	    } else {
77		result = fdopen(fd[1], type);
78		(void) close(fd[0]);
79	    }
80	    break;
81	}
82    }
83
84    return result;
85}
86
87/*
88 * Display text from a pipe in a scrolling window.
89 */
90int
91dialog_prgbox(const char *title,
92	      const char *cprompt,
93	      const char *command,
94	      int height,
95	      int width,
96	      int pauseopt)
97{
98    int code;
99    FILE *fp;
100
101    fp = dlg_popen(command, "r");
102    if (fp == NULL)
103	dlg_exiterr("pipe open failed: %s", command);
104
105    code = dlg_progressbox(title, cprompt, height, width, pauseopt, fp);
106
107    pclose(fp);
108
109    return code;
110}
111