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