X-Git-Url: https://git.distorted.org.uk/~mdw/xtoys/blobdiff_plain/fa64e43069529b159016b7e5f8cd8f09a11ba12d..f6795c17f9899da2759a2f5782e17b2ee5a0dbb9:/xcatch.c diff --git a/xcatch.c b/xcatch.c deleted file mode 100644 index 6ddb4ea..0000000 --- a/xcatch.c +++ /dev/null @@ -1,371 +0,0 @@ -/* -*-c-*- - * - * $Id: xcatch.c,v 1.10 2004/04/08 01:36:29 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. - */ - -/*----- Header files ------------------------------------------------------*/ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -/*----- Inportant state ---------------------------------------------------*/ - -static unsigned int flags; - -#define f_closed 1u -#define f_bogus 2u - -static GtkWidget *textbox = 0; -static GdkFont *font; - -static pid_t kid = -1; -static int status; - -/*----- 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 doscroll = 1; - GtkText *t = 0; - GtkAdjustment *va = 0; - - /* --- If not ready to read then go away --- */ - - if (!(c & GDK_INPUT_READ)) - return; - - /* --- Decide whether to scroll the window --- */ - - if (textbox) { - t = GTK_TEXT(textbox); - va = t->vadj; - if (va->value + va->page_size < va->upper) - doscroll = 0; - gtk_text_freeze(t); - } - - /* --- Read data into the buffer --- * - * - * This is a bit of a mess. - */ - - for (;;) { - int r = read(fd, buf, sizeof(buf)); - - /* --- The read failed --- * - * - * Maybe there's no more data to read. In this case, we get - * @EWOULDBLOCK@, indicating it's time to stop and do something else. - * Otherwise something serious has happened. - */ - - if (r < 0) { - if (errno == EWOULDBLOCK) - break; - msg(QUIS, ":~OK", "error reading data: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* --- End of file --- * - * - * If the box is closed, then exit quiety; otherwise wait for it to - * go away. - */ - - if (r == 0) { - close(fd); - if (textbox) - flags |= f_closed; - else - gtk_main_quit(); - break; - } - - /* --- If there's no output window, create one --- */ - - if (!textbox) { - GtkWidget *win; - GtkWidget *tbl; - GtkWidget *w; - - win = gtk_dialog_new(); - gtk_window_set_policy(GTK_WINDOW(win), 1, 1, 0); - gtk_signal_connect(GTK_OBJECT(win), "destroy", - GTK_SIGNAL_FUNC(killwin), 0); - - tbl = gtk_table_new(2, 2, 0); - gtk_container_border_width(GTK_CONTAINER(tbl), 8); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), tbl, 1, 1, 1); - gtk_widget_show(tbl); - - textbox = gtk_text_new(0, 0); - t = GTK_TEXT(textbox); - va = t->vadj; - gtk_table_attach(GTK_TABLE(tbl), textbox, 0, 1, 0, 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - 0, 0); - gtk_text_set_editable(t, 0); - gtk_widget_set_usize(textbox, 500, 300); - gtk_text_freeze(t); - gtk_widget_show(textbox); - - w = gtk_vscrollbar_new(va); - gtk_table_attach(GTK_TABLE(tbl), w, 1, 2, 0, 1, - 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); - gtk_widget_show(w); - - w = gtk_hscrollbar_new(t->hadj); - gtk_table_attach(GTK_TABLE(tbl), 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); - } - - gtk_text_insert(t, font, 0, 0, buf, r); - } - - if (textbox) { - gtk_text_thaw(t); - if (doscroll) - gtk_adjustment_set_value(va, va->upper - va->page_size); - } -} - -/* --- Signal handler --- */ - -static void reap(int sig) -{ - pid_t k; - int s; - int e = errno; - - for (;;) { - k = waitpid(-1, &s, WNOHANG); - if (k <= 0) - break; - if (k == kid) { - if (WIFEXITED(s)) - status = WEXITSTATUS(s); - else - status = 127; - } - } - errno = e; -} - -/* --- 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", OPTF_ARGREQ, 0, 'f' }, - { "font", OPTF_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\t Read input from the named file\n" -"-F, --font=FONT\t 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]; - struct sigaction sa; - sigset_t newmask, oldmask; - - /* --- Set up a signal handler --- */ - - sa.sa_handler = reap; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP; -#ifdef SA_RESTART - sa.sa_flags |= SA_RESTART; -#endif - sigaction(SIGCHLD, &sa, 0); - - /* --- Start a child program --- */ - - if (pipe(pfd)) - die(1, "couldn't open pipe: %s", strerror(errno)); - - sigemptyset(&newmask); - sigaddset(&newmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &newmask, &oldmask); - - kid = fork(); - if (kid < 0) - die(1, "couldn't fork: %s", strerror(errno)); - if (kid == 0) { - dstr d = DSTR_INIT; - - 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_putf(&d, "%s: couldn't run `%s': %s\n", - QUIS, argv[optind], strerror(errno)); - write(STDERR_FILENO, d.buf, d.len); - dstr_destroy(&d); - _exit(127); - } - - sigprocmask(SIG_SETMASK, &oldmask, 0); - fd = pfd[0]; - close(pfd[1]); - } - } - - { - int f = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, f | O_NONBLOCK); - } - - gdk_input_add(fd, GDK_INPUT_READ, ready, 0); - gtk_main(); - return (status); -} - -/*----- That's all, folks -------------------------------------------------*/