Return exit status of child process, rather than always returning
[xtoys] / xcatch.c
CommitLineData
63351ac6 1/* -*-c-*-
2 *
d62a74ae 3 * $Id: xcatch.c,v 1.3 1998/12/20 17:19:16 mdw Exp $
63351ac6 4 *
5 * Catch input and trap it in an X window
6 *
7 * (c) 1998 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the Edgeware X tools collection.
13 *
14 * X tools is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * X tools is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with X tools; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: xcatch.c,v $
d62a74ae 32 * Revision 1.3 1998/12/20 17:19:16 mdw
33 * Return exit status of child process, rather than always returning
34 * success.
35 *
4e6aae28 36 * Revision 1.2 1998/12/16 00:10:58 mdw
37 * Fix tabbing in help text.
38 *
63351ac6 39 * Revision 1.1 1998/12/15 23:46:50 mdw
40 * New program: captures input and puts it in a window.
41 *
42 */
43
44/*----- Header files ------------------------------------------------------*/
45
46#include <errno.h>
47#include <signal.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51
52#include <sys/types.h>
53#include <sys/wait.h>
54
55#include <fcntl.h>
56#include <unistd.h>
57
58#include <gtk/gtk.h>
59
60#include <mLib/dstr.h>
61#include <mLib/mdwopt.h>
62#include <mLib/report.h>
63#include <mLib/quis.h>
64
65#include <mgLib/cancel.h>
66#include <mgLib/msg.h>
67
68/*----- Inportant state ---------------------------------------------------*/
69
70static unsigned int flags;
71
72enum {
73 f_closed = 1,
74 f_bogus = 2
75};
76
d62a74ae 77static GtkWidget *textbox = 0;
78static GdkFont *font;
79
80static pid_t kid = -1;
81static int status;
63351ac6 82
83/*----- Main code ---------------------------------------------------------*/
84
85/* --- The window's closed --- */
86
87static void killwin(GtkWidget *w, gpointer p)
88{
89 if (flags & f_closed)
90 gtk_main_quit();
91 else
92 textbox = 0;
93}
94
95/* --- Some input has arrived --- */
96
97static void ready(gpointer data, gint fd, GdkInputCondition c)
98{
99 char buf[1024];
100 int count;
101
102 /* --- Read the next buffer of data --- */
103
104 if (!(c & GDK_INPUT_READ))
105 return;
106 count = read(fd, buf, sizeof(buf));
107
108 /* --- Decide what to do --- */
109
110 if (count < 0) {
111 msg(":~OK", "error reading data: %s", strerror(errno));
112 exit(EXIT_FAILURE);
113 }
114
115 if (count == 0) {
116 close(fd);
117 if (textbox)
118 flags |= f_closed;
119 else
120 gtk_main_quit();
121 return;
122 }
123
124 /* --- If there's no output window, create one --- */
125
126 if (!textbox) {
127 GtkWidget *win;
128 GtkWidget *t;
129 GtkWidget *w;
130
131 win = gtk_dialog_new();
132 gtk_signal_connect(GTK_OBJECT(win), "destroy",
133 GTK_SIGNAL_FUNC(killwin), 0);
134
135 t = gtk_table_new(2, 2, 0);
136 gtk_container_border_width(GTK_CONTAINER(t), 8);
137 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), t, 1, 1, 0);
138 gtk_widget_show(t);
139
140 textbox = gtk_text_new(0, 0);
141 gtk_table_attach(GTK_TABLE(t), textbox, 0, 1, 0, 1,
142 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
143 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
144 0, 0);
145 gtk_text_set_editable(GTK_TEXT(textbox), 0);
146 gtk_widget_set_usize(textbox, 500, 100);
147 gtk_widget_show(textbox);
148
149 w = gtk_vscrollbar_new(GTK_TEXT(textbox)->vadj);
150 gtk_table_attach(GTK_TABLE(t), w, 1, 2, 0, 1,
151 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
152 gtk_widget_show(w);
153
154 w = gtk_hscrollbar_new(GTK_TEXT(textbox)->hadj);
155 gtk_table_attach(GTK_TABLE(t), w, 0, 1, 1, 2,
156 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0, 0);
157 gtk_widget_show(w);
158
159 gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(win)->action_area), 0);
160 w = gtk_button_new_with_label("Dismiss");
161 gtk_signal_connect_object(GTK_OBJECT(w), "clicked",
162 GTK_SIGNAL_FUNC(gtk_object_destroy),
163 GTK_OBJECT(win));
164 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(win)->action_area), w, 0, 0, 0);
165 GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
166 gtk_widget_grab_default(w);
167 cancel(GTK_WINDOW(win), w);
168 gtk_widget_show(w);
169
170 gtk_widget_show(win);
171 }
172
173 /* --- Append the new text --- */
174
175 gtk_text_insert(GTK_TEXT(textbox), font, 0, 0, buf, count);
176}
177
178/* --- Signal handler --- */
179
180static void reap(int sig)
181{
d62a74ae 182 pid_t k;
183 int s;
184
185 for (;;) {
186 k = waitpid(-1, &s, WNOHANG);
187 if (k <= 0)
188 break;
189 if (k == kid) {
190 if (WIFEXITED(s))
191 status = WEXITSTATUS(s);
192 else
193 status = 127;
194 }
195 }
63351ac6 196}
197
198/* --- Main program --- */
199
200static void version(FILE *fp)
201{
202 fprintf(fp, "%s (xtoys version " VERSION ")\n", QUIS);
203}
204
205static void usage(FILE *fp)
206{
207 fprintf(fp, "Usage: %s [-f file] [-F font] [command [args...]]\n", QUIS);
208}
209
210int main(int argc, char *argv[])
211{
212 int fd = -1;
213
214 ego(argv[0]);
215
216 gtk_init(&argc, &argv);
217
218 for (;;) {
219 static struct option opt[] = {
220 { "help", 0, 0, 'h' },
221 { "usage", 0, 0, 'u' },
222 { "version", 0, 0, 'v' },
223 { "file", gFlag_argReq, 0, 'f' },
224 { "font", gFlag_argReq, 0, 'F' },
225 { 0, 0, 0, 0 }
226 };
227 int i = mdwopt(argc, argv, "huvf:F:", opt, 0, 0, 0);
228
229 if (i < 0)
230 break;
231
232 switch (i) {
233 case 'h':
234 version(stdout);
235 fputc('\n', stdout);
236 usage(stdout);
237 fputs(
238"\n"
239"Catches input from a pipe or other source, and captures it in a window.\n"
240"Nothing is displayed if there's no input.\n"
241"\n"
242"Options provided:\n"
243"\n"
244"-h, --help Display this help text\n"
245"-u, --usage Display a quick usage summary\n"
246"-v, --version Display the version number\n"
4e6aae28 247"-f, --file=FILE\t Read input from the named file\n"
248"-F, --font=FONT\t Display output in the named font\n",
63351ac6 249 stdout);
250 exit(0);
251 break;
252 case 'u':
253 usage(stdout);
254 exit(0);
255 break;
256 case 'v':
257 version(stdout);
258 exit(0);
259 break;
260 case 'f':
261 if ((fd = open(optarg, O_RDONLY)) < 0) {
262 die(1, "couldn't open file: %s", strerror(errno));
263 exit(1);
264 }
265 break;
266 case 'F':
267 font = gdk_font_load(optarg);
268 break;
269 default:
270 flags |= f_bogus;
271 break;
272 }
273 }
274
275 if (flags & f_bogus) {
276 usage(stderr);
277 exit(1);
278 }
279
280 if (fd == -1) {
281 if (optind == argc)
282 fd = STDIN_FILENO;
283 else {
284 int pfd[2];
63351ac6 285 struct sigaction sa;
286
287 /* --- Set up a signal handler --- */
288
289 sa.sa_handler = reap;
290 sigemptyset(&sa.sa_mask);
291 sa.sa_flags = 0;
292 sigaction(SIGCHLD, &sa, 0);
293
294 /* --- Start a child program --- */
295
296 if (pipe(pfd))
297 die(1, "couldn't open pipe: %s", strerror(errno));
298 kid = fork();
299 if (kid < 0)
300 die(1, "couldn't fork: %s", strerror(errno));
301 if (kid == 0) {
302 dstr d;
303
304 close(pfd[0]);
305 if (pfd[1] != STDOUT_FILENO)
306 dup2(pfd[1], STDOUT_FILENO);
307 if (pfd[1] != STDERR_FILENO)
308 dup2(pfd[1], STDERR_FILENO);
309 if (pfd[1] != STDOUT_FILENO && pfd[1] != STDERR_FILENO)
310 close(pfd[1]);
311 execvp(argv[optind], argv + optind);
312
313 dstr_create(&d);
314 dstr_putf(&d, "%s: couldn't run `%s': %s\n",
315 QUIS, argv[optind], strerror(errno));
316 write(STDERR_FILENO, d.buf, d.len);
317 _exit(127);
318 }
319 fd = pfd[0];
320 close(pfd[1]);
321 }
322 }
323
324 gdk_input_add(fd, GDK_INPUT_READ, ready, 0);
325 gtk_main();
d62a74ae 326 return (status);
63351ac6 327}
328
329/*----- That's all, folks -------------------------------------------------*/