+/* -*-c-*-
+ *
+ * $Id: xcatch.c,v 1.1 1998/12/15 23:46:50 mdw Exp $
+ *
+ * Catch input and trap it in an X window
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Edgeware X tools collection.
+ *
+ * X tools is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * X tools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with X tools; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: xcatch.c,v $
+ * Revision 1.1 1998/12/15 23:46:50 mdw
+ * New program: captures input and puts it in a window.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <gtk/gtk.h>
+
+#include <mLib/dstr.h>
+#include <mLib/mdwopt.h>
+#include <mLib/report.h>
+#include <mLib/quis.h>
+
+#include <mgLib/cancel.h>
+#include <mgLib/msg.h>
+
+/*----- Inportant state ---------------------------------------------------*/
+
+static unsigned int flags;
+
+enum {
+ f_closed = 1,
+ f_bogus = 2
+};
+
+GtkWidget *textbox = 0;
+GdkFont *font;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- The window's closed --- */
+
+static void killwin(GtkWidget *w, gpointer p)
+{
+ if (flags & f_closed)
+ gtk_main_quit();
+ else
+ textbox = 0;
+}
+
+/* --- Some input has arrived --- */
+
+static void ready(gpointer data, gint fd, GdkInputCondition c)
+{
+ char buf[1024];
+ int count;
+
+ /* --- Read the next buffer of data --- */
+
+ if (!(c & GDK_INPUT_READ))
+ return;
+ count = read(fd, buf, sizeof(buf));
+
+ /* --- Decide what to do --- */
+
+ if (count < 0) {
+ msg(":~OK", "error reading data: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (count == 0) {
+ close(fd);
+ if (textbox)
+ flags |= f_closed;
+ else
+ gtk_main_quit();
+ return;
+ }
+
+ /* --- If there's no output window, create one --- */
+
+ if (!textbox) {
+ GtkWidget *win;
+ GtkWidget *t;
+ GtkWidget *w;
+
+ win = gtk_dialog_new();
+ gtk_signal_connect(GTK_OBJECT(win), "destroy",
+ GTK_SIGNAL_FUNC(killwin), 0);
+
+ t = gtk_table_new(2, 2, 0);
+ gtk_container_border_width(GTK_CONTAINER(t), 8);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), t, 1, 1, 0);
+ gtk_widget_show(t);
+
+ textbox = gtk_text_new(0, 0);
+ gtk_table_attach(GTK_TABLE(t), textbox, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 0, 0);
+ gtk_text_set_editable(GTK_TEXT(textbox), 0);
+ gtk_widget_set_usize(textbox, 500, 100);
+ gtk_widget_show(textbox);
+
+ w = gtk_vscrollbar_new(GTK_TEXT(textbox)->vadj);
+ gtk_table_attach(GTK_TABLE(t), w, 1, 2, 0, 1,
+ 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show(w);
+
+ w = gtk_hscrollbar_new(GTK_TEXT(textbox)->hadj);
+ gtk_table_attach(GTK_TABLE(t), w, 0, 1, 1, 2,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0, 0);
+ gtk_widget_show(w);
+
+ gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(win)->action_area), 0);
+ w = gtk_button_new_with_label("Dismiss");
+ gtk_signal_connect_object(GTK_OBJECT(w), "clicked",
+ GTK_SIGNAL_FUNC(gtk_object_destroy),
+ GTK_OBJECT(win));
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(win)->action_area), w, 0, 0, 0);
+ GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(w);
+ cancel(GTK_WINDOW(win), w);
+ gtk_widget_show(w);
+
+ gtk_widget_show(win);
+ }
+
+ /* --- Append the new text --- */
+
+ gtk_text_insert(GTK_TEXT(textbox), font, 0, 0, buf, count);
+}
+
+/* --- Signal handler --- */
+
+static void reap(int sig)
+{
+ while (waitpid(-1, 0, WNOHANG) > 0)
+ ;
+}
+
+/* --- Main program --- */
+
+static void version(FILE *fp)
+{
+ fprintf(fp, "%s (xtoys version " VERSION ")\n", QUIS);
+}
+
+static void usage(FILE *fp)
+{
+ fprintf(fp, "Usage: %s [-f file] [-F font] [command [args...]]\n", QUIS);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd = -1;
+
+ ego(argv[0]);
+
+ gtk_init(&argc, &argv);
+
+ for (;;) {
+ static struct option opt[] = {
+ { "help", 0, 0, 'h' },
+ { "usage", 0, 0, 'u' },
+ { "version", 0, 0, 'v' },
+ { "file", gFlag_argReq, 0, 'f' },
+ { "font", gFlag_argReq, 0, 'F' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "huvf:F:", opt, 0, 0, 0);
+
+ if (i < 0)
+ break;
+
+ switch (i) {
+ case 'h':
+ version(stdout);
+ fputc('\n', stdout);
+ usage(stdout);
+ fputs(
+"\n"
+"Catches input from a pipe or other source, and captures it in a window.\n"
+"Nothing is displayed if there's no input.\n"
+"\n"
+"Options provided:\n"
+"\n"
+"-h, --help Display this help text\n"
+"-u, --usage Display a quick usage summary\n"
+"-v, --version Display the version number\n"
+"-f, --file=FILE Read input from the named file\n"
+"-F, --font=FONT Display output in the named font\n",
+ stdout);
+ exit(0);
+ break;
+ case 'u':
+ usage(stdout);
+ exit(0);
+ break;
+ case 'v':
+ version(stdout);
+ exit(0);
+ break;
+ case 'f':
+ if ((fd = open(optarg, O_RDONLY)) < 0) {
+ die(1, "couldn't open file: %s", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'F':
+ font = gdk_font_load(optarg);
+ break;
+ default:
+ flags |= f_bogus;
+ break;
+ }
+ }
+
+ if (flags & f_bogus) {
+ usage(stderr);
+ exit(1);
+ }
+
+ if (fd == -1) {
+ if (optind == argc)
+ fd = STDIN_FILENO;
+ else {
+ int pfd[2];
+ pid_t kid;
+ struct sigaction sa;
+
+ /* --- Set up a signal handler --- */
+
+ sa.sa_handler = reap;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGCHLD, &sa, 0);
+
+ /* --- Start a child program --- */
+
+ if (pipe(pfd))
+ die(1, "couldn't open pipe: %s", strerror(errno));
+ kid = fork();
+ if (kid < 0)
+ die(1, "couldn't fork: %s", strerror(errno));
+ if (kid == 0) {
+ dstr d;
+
+ close(pfd[0]);
+ if (pfd[1] != STDOUT_FILENO)
+ dup2(pfd[1], STDOUT_FILENO);
+ if (pfd[1] != STDERR_FILENO)
+ dup2(pfd[1], STDERR_FILENO);
+ if (pfd[1] != STDOUT_FILENO && pfd[1] != STDERR_FILENO)
+ close(pfd[1]);
+ execvp(argv[optind], argv + optind);
+
+ dstr_create(&d);
+ dstr_putf(&d, "%s: couldn't run `%s': %s\n",
+ QUIS, argv[optind], strerror(errno));
+ write(STDERR_FILENO, d.buf, d.len);
+ _exit(127);
+ }
+ fd = pfd[0];
+ close(pfd[1]);
+ }
+ }
+
+ gdk_input_add(fd, GDK_INPUT_READ, ready, 0);
+ gtk_main();
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/