mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (10/20/89)
Submitted-by: chuck@trantor.harris-atd.com (Chuck Musciano) Posting-number: Volume 1, Issue 78 Archive-name: contool2.2/part03 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 3 (of 3)." # Contents: contool.c contool.man dialog.c # Wrapped by chuck@melmac on Wed Sep 20 09:46:42 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'contool.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'contool.c'\" else echo shar: Extracting \"'contool.c'\" \(18607 characters\) sed "s/^X//" >'contool.c' <<'END_OF_FILE' X/************************************************************************/ X/* Copyright 1988, 1989 by Chuck Musciano and Harris Corporation */ X/* */ X/* Permission to use, copy, modify, and distribute this software */ X/* and its documentation for any purpose and without fee is */ X/* hereby granted, provided that the above copyright notice */ X/* appear in all copies and that both that copyright notice and */ X/* this permission notice appear in supporting documentation, and */ X/* that the name of Chuck Musciano and Harris Corporation not be */ X/* used in advertising or publicity pertaining to distribution */ X/* of the software without specific, written prior permission. */ X/* Chuck Musciano and Harris Corporation make no representations */ X/* about the suitability of this software for any purpose. It is */ X/* provided "as is" without express or implied warranty. This */ X/* software may not be sold without the prior explicit permission */ X/* of Harris Corporation. */ X/************************************************************************/ X X#include <stdio.h> X#include <fcntl.h> X#include <sys/ioctl.h> X#include <sys/file.h> X#include <sys/types.h> X#include <sys/stat.h> X X#include <suntool/sunview.h> X#include <suntool/textsw.h> X#include <suntool/icon_load.h> X X#include "contool.h" X XEXPORT char filter_path[256]; /* -c */ XEXPORT int blink_icon = TRUE; /* -i */ XEXPORT int pop_open = FALSE; /* -p */ XEXPORT int beep_amount = BEEP_COUNT; /* -s */ XEXPORT int do_time_stamp = TRUE; XEXPORT f_ptr filters = NULL; XEXPORT f_ptr curr_filter = NULL; X XPUBLIC Frame confirmer; X XPRIVATE char *ct_usage = "usage: contool [-b <file>] [-c <file>] [-d <size>] [-f <file>] [-g <file>] [-l <size>] [-n] [-o <logfile>] [-p] [-r <amt>] [-s <amt>]\n"; X XPRIVATE Frame bf; XPRIVATE Frame dialog = NULL; XPRIVATE Textsw text; XPRIVATE Icon good, bad, inverse; XPRIVATE struct pixrect *good_pr, *bad_pr, *inv_pr; XPRIVATE Menu_item stop_blink; XPRIVATE Rect open_rect; X XPRIVATE char bad_icon[512]; /* -b */ XPRIVATE int delete_amt = TEXT_DELETE_SIZE; /* -d */ XPRIVATE char inv_icon[512]; /* -f */ XPRIVATE char good_icon[512]; /* -g */ XPRIVATE int size_limit = TEXT_SIZE_LIMIT; /* -l */ XPRIVATE int resolution = TS_INTERVAL; /* -r */ X XPRIVATE int bad_is_up; XPRIVATE int beep_count; XPRIVATE int blinking = FALSE; XPRIVATE int event_in_progress = FALSE; XPRIVATE int explicit_filters = FALSE; XPRIVATE int icon_height; XPRIVATE int icon_width; XPRIVATE FILE *master = NULL; XPRIVATE int old_time = 0; XPRIVATE char *program; XPRIVATE FILE *slave = NULL; XPRIVATE FILE *logfile = NULL; X XPRIVATE struct itimerval timer = {{0, 500000}, {0, 500000}}; X X/************************************************************************/ X/* First, some basic console utility routines */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE acquire_console(path) X Xchar *path; X X{ X if (ioctl(fileno(slave), TIOCCONS, NULL) == -1) { X fprintf(stderr, "%s: could not attach %s to /dev/console\n", program, path); X exit(1); X } X} X X/************************************************************************/ XPRIVATE clear_messages() X X{ X textsw_reset(text, 0, 0); X old_time = 0; X} X X/************************************************************************/ XPRIVATE stop_blinking() X X{ X notify_set_itimer_func(bf, NULL, ITIMER_REAL, NULL, NULL); X window_set(bf, FRAME_ICON, good, 0); X blinking = FALSE; X menu_set(stop_blink, MENU_INACTIVE, TRUE, 0); X} X X/************************************************************************/ XPRIVATE edit_filters() X X{ Frame create_dialog_box(); X X if (dialog == NULL) X dialog = create_dialog_box(bf); X update_edit_dialog(filters); X update_defaults(); X window_set(dialog, WIN_SHOW, TRUE, 0); X} X X/************************************************************************/ X/* Now, filter and regular expression handlers */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE internal_message(a, b, c, d, e, f) X Xint a, b, c, d, e, f; X X{ char buf[512]; X X sprintf(buf, a, b, c, d, e, f); X time_stamp(); X write_log(buf); X do_insertion(buf, strlen(buf)); X} X X/************************************************************************/ XPRIVATE internal_error(a, b, c, d, e, f) X Xint a, b, c, d, e, f; X X{ char buf[512]; X X sprintf(buf, a, b, c, d, e, f); X time_stamp(); X fprintf(stderr, "*** %s: %s\n", program, buf); X} X X/************************************************************************/ XPRIVATE load_filters() X X{ char *result; X struct stat sb; X f_ptr new_filters, f; X static int load_time = 0; X X if (access(filter_path, R_OK) == -1) { X if (explicit_filters && load_time == 0) { X internal_error("filter file %s cannot be accessed", filter_path); X load_time = 1; X } X return; X } X if (stat(filter_path, &sb) == 0 && sb.st_mtime > load_time) X if (new_filters = read_filters(filter_path, internal_error)) { X for (f = new_filters; f->start; f++) X if (result = compile_exp(f, f->start, f->end)) { X internal_error(result); X f->valid = FALSE; X } X free_filters(filters); X filters = new_filters; X internal_message("*** filters loaded from %s\n", filter_path); X load_time = sb.st_mtime; X } X} X X/************************************************************************/ X/* Various event handlers for the console frame */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE Notify_value blink_proc(me, which) X Xint *me; Xint which; X X{ X if (event_in_progress) X return(NOTIFY_DONE); X if (beep_count > 0) { X window_bell(bf); X beep_count--; X } X if (blinking) { X if (bad_is_up) X window_set(bf, FRAME_ICON, inverse, 0); X else X window_set(bf, FRAME_ICON, bad, 0); X bad_is_up = !bad_is_up; X } X if (beep_count == 0 && !blinking) X notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL); X return(NOTIFY_DONE); X} X X/************************************************************************/ XPRIVATE Notify_value close_proc(frame, event, arg, type) X XFrame frame; XEvent *event; XNotify_arg arg; XNotify_event_type type; X X{ int init_closed, curr_closed, is_resize; X Notify_value value; X Rect *temp; X X event_in_progress = TRUE; X init_closed = (int) window_get(frame, FRAME_CLOSED); X is_resize = (event_id(event) == WIN_RESIZE); X value = notify_next_event_func(frame, event, arg, type); X curr_closed = (int) window_get(frame, FRAME_CLOSED); X if (init_closed != curr_closed) X if (!curr_closed && blinking) { X notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL); X window_set(bf, FRAME_ICON, good, 0); X blinking = FALSE; X menu_set(stop_blink, MENU_INACTIVE, TRUE, 0); X } X event_in_progress = FALSE; X if (is_resize) { X temp = (Rect *) window_get(frame, FRAME_OPEN_RECT); X if (temp->r_width <= icon_width && temp->r_height <= icon_height) { /* override spurious resize request */ X window_set(frame, FRAME_OPEN_RECT, &open_rect, FRAME_CLOSED, FALSE, 0); X notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL); X window_set(bf, FRAME_ICON, good, 0); X blinking = FALSE; X menu_set(stop_blink, MENU_INACTIVE, TRUE, 0); X } X else /* save away new open rect */ X open_rect = *temp; X } X return(value); X} X X/************************************************************************/ XPRIVATE Notify_value destroy_proc(frame, status) X XFrame frame; XDestroy_status status; X X{ X if (status == DESTROY_CHECKING) { X if (dialog) X window_destroy(dialog); X if (confirmer) X window_destroy(confirmer); X textsw_reset(text, 0, 0); X return(NOTIFY_DONE); X } X else X return(notify_next_destroy_func(frame, status)); X} X X/************************************************************************/ X/* Routines which handle capturing and displaying messages */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE write_log(s) X Xchar *s; X X{ int t; X static char hostname[100] = ""; X X if (logfile) { X if (*hostname == NULL) X if (gethostname(hostname, 99) != 0) X strcpy(hostname, "(unknown)"); X t = time(0); X fseek(logfile, 0L, 2); X fprintf(logfile, "%s\t%.16s\t%s", hostname, ctime(&t) + 4, s); X fflush(logfile); X } X} X X/************************************************************************/ XPRIVATE do_insertion(buf, len) X Xchar *buf; Xint len; X X{ int first, last; X X while (len > size_limit - ((int) window_get(text, TEXTSW_LENGTH) - TEXT_SIZE_FUZZ)) { /* make some room */ X first = 1; X last = TEXTSW_INFINITY; X if (textsw_find_bytes(text, &first, &last, "\n<<<", 4, 0) == -1) X if (textsw_find_bytes(text, &first, &last, "\n", 1, 0) == -1) X first = delete_amt; X textsw_delete(text, 0, first + 1); X } X window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0); X textsw_insert(text, buf, len); X} X X/************************************************************************/ XPRIVATE time_stamp() X X{ int t, pos; X char buf[5]; X X t = time(0); X if (t - old_time >= resolution) { X window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0); X pos = (int) window_get(text, TEXTSW_LENGTH); X if (pos != 0) { X window_get(text, TEXTSW_CONTENTS, pos - 1, buf, 1); X if (buf[0] != '\n') X do_insertion("\n", 1); X } X do_insertion("\n<<< ", 5); X do_insertion(ctime(&t), 24); X do_insertion(" >>>\n", 5); X old_time = t; X } X} X X/************************************************************************/ XPRIVATE Notify_value input_func(me, fd) X Xint *me; Xint fd; X X{ char old_c, *s, *t; X f_ptr f; X int count, do_blink = FALSE, do_open = FALSE; X static char in_buf[INPUT_BUFFER_SIZE + 2]; X X while ((count = read(fileno(master), in_buf, INPUT_BUFFER_SIZE)) >= 0) { X in_buf[count] = '\0'; X while (s = index(in_buf, '\015')) { X strcpy(s, s + 1); X count--; X } X for (t = in_buf; *t; *s = old_c, t = s) { X if (s = index(t, '\n')) { X old_c = *++s; X *s = '\0'; X } X else { X s = t + strlen(t); X old_c = '\0'; X } X if (curr_filter == NULL) { X load_filters(); X for (f = filters; f && f->start; f++) X if (f->valid && match_exp(f->start_re, f->scircf, t)) { X if (f->save) { X do_blink = f->flash; X beep_count = f->beep; X do_open = f->open; X if (f->stamp) X time_stamp(); X write_log(t); X do_insertion(t, strlen(t)); X } X if (f->end) { X curr_filter = f; X } X break; X } X if (f == NULL || f->start == NULL) { X if (do_time_stamp) X time_stamp(); X write_log(t); X do_insertion(t, strlen(t)); X do_blink = blink_icon; X do_open = pop_open; X beep_count = beep_amount; X } X } X else { X if (curr_filter->save) { X if (curr_filter->stamp) X time_stamp(); X write_log(t); X do_insertion(t, strlen(t)); X } X if (match_exp(curr_filter->end_re, curr_filter->ecircf, t)) X curr_filter = NULL; X } X } X } X window_set(text, TEXTSW_UPDATE_SCROLLBAR, 0); X if (do_open) X window_set(bf, FRAME_CLOSED, FALSE, 0); X if (do_blink) X if (window_get(bf, FRAME_CLOSED) && !blinking) { X window_set(bf, FRAME_ICON, bad, WIN_SHOW, TRUE, 0); X blinking = TRUE; X bad_is_up = TRUE; X menu_set(stop_blink, MENU_INACTIVE, FALSE, 0); X notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, &timer, NULL); X } X if (beep_count > 0 || blinking) X notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, &timer, NULL); X return(NOTIFY_DONE); X} X X/************************************************************************/ X/* Routines which parse options, create windows, and main() */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE parse_options(argc, argv) X Xint *argc; Xchar **argv; X X{ char *s, c; X X strcpy(good_icon, ICON_DIRECTORY); X strcat(good_icon, GOOD_ICON); X strcpy(bad_icon, ICON_DIRECTORY); X strcat(bad_icon, BAD_ICON); X strcpy(inv_icon, ICON_DIRECTORY); X strcat(inv_icon, INVERSE_ICON); X X strcpy(filter_path, getenv("HOME")); X strcat(filter_path, "/.contool"); X X while ((c = getopt(argc, argv, "b:c:d:f:g:l:no:pr:s:?", &s)) != EOF) X switch (c) { X case 'b' : strcpy(bad_icon, s); X break; X case 'c' : strcpy(filter_path, s); X explicit_filters = TRUE; X break; X case 'd' : if (verify(s, "0123456789")) X delete_amt = atoi(s); X else { X fprintf(stderr, "%s: invalid delete amount: %s\n", program, s); X exit(1); X } X break; X case 'f' : strcpy(inv_icon, s); X break; X case 'g' : strcpy(good_icon, s); X break; X case 'l' : if (verify(s, "0123456789")) X window_set(text, TEXTSW_MEMORY_MAXIMUM, (size_limit = atoi(s)) + TEXT_SIZE_FUZZ, 0); X else { X fprintf(stderr, "%s: invalid message limit: %s\n", program, s); X exit(1); X } X break; X case 'n' : blink_icon = FALSE; X break; X case 'o': if ((logfile = fopen(s, "a")) == NULL) { X fprintf(stderr, "%s : can't open logfile: %s\n", program, s); X exit(1); X } X break; X case 'p' : pop_open = TRUE; X break; X case 'r' : if (verify(s, "0123456789")) X resolution = atoi(s); X else { X fprintf(stderr, "%s: invalid timestamp resolution: %s\n", program, s); X exit(1); X } X break; X case 's' : if (verify(s, "0123456789")) X beep_amount = atoi(s); X else { X fprintf(stderr, "%s: invalid beep count: %s\n", program, s); X exit(1); X } X break; X case '?' : fprintf(stderr, ct_usage); X exit(0); X break; X default : fprintf(stderr, ct_usage); X exit(1); X } X} X X/************************************************************************/ Xstruct pixrect *load_icon(path, message) X Xchar *path; Xchar *message; X X{ char new_path[512], *real_path; X X if (access(path, R_OK) == -1) { X strcpy(new_path, ICON_DIRECTORY); X strcat(new_path, path); X if (access(new_path, R_OK) == -1) { X sprintf(message, "cannot read icon file %s", path); X return(NULL); X } X real_path = new_path; X } X else X real_path = path; X return(icon_load_mpr(real_path, message)); X} X X/************************************************************************/ XPRIVATE load_icons() X X{ char msg[IL_ERRORMSG_SIZE]; X X if ((good_pr = load_icon(good_icon, msg)) == NULL) { X fprintf(stderr, "%s: %s\n", program, msg); X exit(1); X } X good = icon_create(ICON_IMAGE, good_pr, X ICON_LABEL, "", X ICON_WIDTH, good_pr->pr_size.x, X ICON_HEIGHT, good_pr->pr_size.y, X 0); X icon_width = good_pr->pr_size.x; X icon_height = good_pr->pr_size.y; X if ((bad_pr = load_icon(bad_icon, msg)) == NULL) { X fprintf(stderr, "%s: %s\n", program, msg); X exit(1); X } X bad = icon_create(ICON_IMAGE, bad_pr, X ICON_LABEL, "", X ICON_WIDTH, bad_pr->pr_size.x, X ICON_HEIGHT, bad_pr->pr_size.y, X 0); X if (bad_pr->pr_size.x > icon_width) X icon_width = bad_pr->pr_size.x; X if (bad_pr->pr_size.y > icon_height) X icon_height = bad_pr->pr_size.y; X if (*inv_icon == '\0') X strcpy(inv_icon, bad_icon); X if ((inv_pr = load_icon(inv_icon, msg)) == NULL) { X fprintf(stderr, "%s: %s\n", program, msg); X exit(1); X } X inverse = icon_create(ICON_IMAGE, inv_pr, X ICON_LABEL, "", X ICON_WIDTH, inv_pr->pr_size.x, X ICON_HEIGHT, inv_pr->pr_size.y, X 0); X if (inv_pr->pr_size.x > icon_width) X icon_width = inv_pr->pr_size.x; X if (inv_pr->pr_size.y > icon_height) X icon_height = inv_pr->pr_size.y; X window_set(bf, FRAME_ICON, good, 0); X} X X/************************************************************************/ Xmain(argc, argv) X Xint argc; Xchar **argv; X X{ char *path; X int i; X Menu menu; X X program = strsave(argv[0]); X X bf = window_create(NULL, FRAME, X FRAME_ARGC_PTR_ARGV, &argc, argv, X FRAME_LABEL, TOOL_LABEL, X 0); X text = window_create(bf, TEXTSW, X TEXTSW_DISABLE_CD, TRUE, X TEXTSW_DISABLE_LOAD, TRUE, X TEXTSW_AGAIN_RECORDING, FALSE, X TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY, X TEXTSW_HISTORY_LIMIT, 0, X TEXTSW_MEMORY_MAXIMUM, size_limit + TEXT_SIZE_FUZZ, X 0); X open_rect = *((Rect *) window_get(bf, FRAME_OPEN_RECT)); X X argv = saveargs(argc, argv); X parse_options(&argc, argv); X if (argc != 1) { X fprintf(stderr, ct_usage); X exit(1); X } X X load_icons(); X X path = open_psuedo_tty(&master, "r", &slave, "w"); X if (master == NULL) { X fprintf(stderr, "%s: couldn't open any psuedo-tty\n"); X exit(1); X } X if (slave == NULL) { X fprintf(stderr, "%s: couldn't open slave side of %s\n", program, path); X exit(1); X } X X i = fcntl(fileno(master), F_GETFL, 0); X i |= FNDELAY; X if (fcntl(fileno(master), F_SETFL, i) == -1) { X fprintf(stderr, "%s: could not force %s to non-blocking i/o\n", program, path); X exit(1); X } X X acquire_console(path); X X stop_blink = menu_create_item(MENU_STRING, "Stop Blinking", X MENU_INACTIVE, TRUE, X MENU_ACTION_PROC, stop_blinking, X 0); X menu = menu_create(MENU_APPEND_ITEM, stop_blink, X MENU_ACTION_ITEM, "Become Console", acquire_console, X MENU_ACTION_ITEM, "Clear Messages", clear_messages, X MENU_ACTION_ITEM, "Edit Filters", edit_filters, X MENU_PULLRIGHT_ITEM, "Frame", window_get(bf, WIN_MENU), X 0); X window_set(bf, WIN_MENU, menu, 0); X X notify_set_input_func(bf, input_func, fileno(master)); X notify_interpose_destroy_func(bf, destroy_proc); X notify_interpose_event_func(bf, close_proc, NOTIFY_SAFE); X X load_filters(); X X window_main_loop(bf); X} END_OF_FILE if test 18607 -ne `wc -c <'contool.c'`; then echo shar: \"'contool.c'\" unpacked with wrong size! fi # end of 'contool.c' fi if test -f 'contool.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'contool.man'\" else echo shar: Extracting \"'contool.man'\" \(14027 characters\) sed "s/^X//" >'contool.man' <<'END_OF_FILE' X.TH CONTOOL 1 "10 December 1986" X.SH NAME Xcontool \- capture and display console output X.SH SYNOPSIS Xcontool [\fB\(hyb\fP \fIfile\fP] [\fB\(hyc\fP \fIfile\fP] [\fB\(hyd\fP \fIsize\fP] [\fB\(hyf\fP \fIfile\fP] [\fB\(hyg\fP \fIfile\fP] [\fB\(hyl\fP \fIsize\fP] [\f3\(hyn\fP] [\f3\(hyo\fP \f2logfile\fP] [\f3\(hyp\fP] [\f3\(hyr\fP \f2amount\fP] [\f3\(hys\fP \f2count\fP] X.SH DESCRIPTION X.LP X\f2Contool\fP captures and displays any messages sent to the system console. XEach message is timestamped as it arrives. The messages are displayed in a Xscrolling text window, so the user can scroll through old messages. X.LP XWhen a message arrives, \f3contool\fP will beep and, if closed, begin Xblinking its icon until the user opens the tool. This behavior can be changed Xwith the various options, described below. X.LP X\f2Contool\fP must be run under \f2suntools\fP(1), and accepts the Xstandard window command line options. X.SH OPTIONS X.IP "\fB\\(hyb\fP \fIfile\fP" Xspecifies the \*(lqbad\*(rq icon to be displayed when a message Xhas arrived on the console. The \f2file\fP must be in the format used by X\f2iconedit\fP(1). X.IP "\fB\\(hyc\fP \fIfile\fP" Xspecifies a different filter file. If \fB\(hyc\fP is not used, \fIcontool\fP Xwill read filters from ~/.contool, if it exists. X.IP "\fB\\(hyd\fP \fIsize\fP" Xsets the amount of text that will be removed from the front of the message Xlog when the message size limit (see \fB\(hyl\fP, below) is exceeded. At Xleast \fIsize\fP bytes will be removed, along with any text up to the start Xof the next message. The default value is 1024 bytes. X.IP "\fB\\(hyf\fP \fIfile\fP" Xspecifies the \*(lqflash\*(rq icon which is alternated with the Xbad icon (see \f3\(hyb\fP, above) when a message has arrived on the console. XLike \f3\(hyb\fP, the file must be in the format used by \f2iconedit\fP(1). XTo disable the flashing feature, specify \*(lq\*(rq as the \f2file\fP, or use the X\f3\(hyn\fP option, below. X.IP "\fB\\(hyg\fP \fIfile\fP" Xspecifies the \*(lqgood\*(rq icon which is displayed when Xno unviewed messages are present on the console. This icon is displayed Xwhen the user closes \f2contool\fP, and remains displayed until a new message Xarrives. Like \f3\(hyb\fP and \f3\(hyf\fP, the \f2file\fP must be in the Xformat used by \f2iconedit\fP(1). X.IP "\fB\\(hyl\fP \fIsize\fP" Xsets the limit, in bytes, on the number of messages that will be saved. XWhen a message would exceed this limit, some number of bytes of text (see X\fB\(hyd\fP, above) will be deleted from the start of the message log. The Xdefault value is 32768 bytes. X.IP "\fB\\(hyn\fP \fIfile\fP" Xdisables icon flashing when a message arrives. X.IP "\fB\\(hyo\fP \fIfile\fP" Xinstructs contool to keep a log of all messages (that are accepted by Xthe filters) into the named \fIfile\fP. This is useful for logging the Xconsole messages from a network of workstations into files on a Xserver, making administration of such a network much simpler. Care Xshould be exercised in logging multiple machines to the one file; NFS Xsometimes doesn't append if concurrent updates are done. This may be Xan NFS bug. X.IP "\f3\(hyp\fP" Xcauses contool to pop open when a message arrives. By default, Xcontool stays closed and blinks when messages arrive. X.IP "\f3\(hyr\fP \f2amount\fP" Xcontrols the resolution of the timestamps placed in the Xmessage display. Normally, a message is not timestamped if it has arrived Xwithin sixty seconds of the last timestamp. This prevents a cascade Xof messages from receiving several, identical timestamps. If this option Xis specified, the \f2amount\fP indicates the time, in seconds, to allow Xbetween timestamps. X.IP "\f3\(hys\fP \f2count\fP" Xchanges the number of times \f2contool\fP will sound the bell Xwhen a message arrives. To disable the bell, set the \f2count\fP to zero. X.SH ROOT MENU X.LP X\f2Contool\fP replaces the normal frame root menu with a new menu containing Xfive entries. These entries are X.IP "\f2Stop Blinking\fP" XIf \f2contool\fP is blinking its icon, this entry will be enabled. If selected, Xthe blinking will stop. Blinking is also stopped if the user opens the \f2contool\fP window. X.IP "\f2Become Console\fP" XSunOS only allows one psuedo-terminal to have the console attribute. If some other Xprogram (including another invocation of \f2contool\fP) takes this attribute from the Xpsuedo-terminal \f2contool\fP is using, subsequent console messages will not be Xprocessed by \f2contool\fP. Selecting this menu entry will restore the console Xattribute to the psuedo-terminal \f2contool\fP is using. X.IP "\f2Clear Messages\fP" XAny messages currently held in \f2contool\fP's text window are removed. X.IP "\f2Edit Filters\fP" XThis selection brings up a dialog box which allows the user to modify the Xfilters \f2contool\fP uses to process incoming console messages. See EDITING XFILTERS, below. X.IP "\f2Frame\fP" XThis selection provides access to the original frame menu, so that the window Xcan be opened, closed, moved, resized, etc. X.SH EDITING FILTERS X.LP XWhen the \f2Edit Filters\fP item is selected from the frame menu, the filter Xediting dialog box appears. This dialog box is divided into three windows: Xthe control panel, the filter display, and the default message actions. X.LP XThe control panel has several buttons which allow filters to be loaded, saved, Xand modified. These buttons are: X.IP "\f2Load\fP" XThis button causes filters to be read from the file indicated in the \*(lqFile\*(rq Xfield in the control panel. The loaded filters are displayed in the filter Xdisplay, replacing any previous filters. The loaded filters \f2do not\fP Xreplace the active filter set used by \f2contool\fP until the \f2Done\fP Xbutton is clicked. X.IP "\f2Save\fP" XThe current set of filters in the filter display is written to the file specified Xin the \*(lqFile\*(rq field in the control. X.IP "\f2Cut\fP" XAny filters in the filter display which are selected (see below) are removed from the Xfilter display and placed in the clipboard. They can be retrieved with the X\f2Paste\fP button. Any previous contents of the clipboard are lost. If no filters Xare selected, the clipboard is cleared. X.IP "\f2Copy\fP" XAny filters in the filter display which are selected (see below) are copied to Xthe clipboard. They can be retrieved with the X\f2Paste\fP button. Any previous contents of the clipboard are lost. If no filters Xare selected, the clipboard is cleared. X.IP "\f2Paste\fP" XThe contents of the clipboard are pasted into the filter display \f2before\fP the Xfirst selected filter. If no filter is selected, they are pasted at the end of the filter list. XIf the clipboard is empty, a single empty filter is pasted. A simple way to create a Xnew blank filter is to clear any filter selections, click \f2Cut\fP and then \f2Paste\fP. X.IP "\f2Reset\fP" XThe current set of \f2contool\fP filters are displayed in the filter display, and the Xdefault message settings are displayed in the default message actions. Any previous Xfilters or default actions are lost. X.IP "\f2Done\fP" XThe filters in the filter display, and the default message actions, are made the Xcurrent \f2contool\fP filter set, and the edit dialog box is closed. If there are Xany errors in the displayed filters, they must be corrected before the filters will be accepted. X.IP "\f2Cancel\fP" XThe edit dialog box is closed, and any filters in the filter display are discarded. XClicking \f2Cancel\fP will always exit the edit dialog box, even if filter errors exist. X.LP XThe filter display window shows one filter per line. Each filter is preceded by several Xsmall icons, representing the selection handle and filter attributes. X.LP XThe filter handle is a small hollow triangle pointing at the filter. When a filter Xis selected, the triangle will become solid. The left and middle mouse buttons Xallow filters to be selected by clicking on the filter handles. Clicking the left Xmouse button on a handle clears any previously selected handles, and selects Xthe current handle. Clicking the middle mouse button on a handle toggles that Xfilter's selection handle, without changing any existing selections. This is Xin keeping with the Sun standard mouse actions: left button makes an initial Xselection, middle button modifies the existing selection. To clear all selections, Xfirst click left on any handle to clear existing selections, and then click middle to clear Xthe current selection. X.LP XEach filter has several icons representing the action \f2contool\fP should take when Xa message matches that filter. These icons are: X.IP "\f2Save Message\fP" XThis icon toggles between an arrow pointing into a small window (indicating that Xthe message will be saved) and an arrow pointing into a trash container (indicating Xthat the message is to be discarded). If a message is to be saved, several other Xicons become visible, controlling beeping, flashing, and window behavior. X.IP "\f2Time Stamp\fP" XThis icon controls whether saved messages will be time stamped when written to Xthe console window. A clock face with hands indicates that a message will be Xtime stamped; a question mark in place of the hands prevents time stamping. X.IP "\f2Open Window\fP" XWhen this icon is set to the \*(lqpop open\*(rq image (a small dot expanding Xinto a window), \f2contool\fP will open its window when a message matches Xthe associated filter pattern. If set to the \*(lqdon't open\*(rq image (just Xa small dot), the window will not change its state when the message arrives. X.IP "\f2Flash Icon\fP" XWhen this icon is a dot surrounded by radiating lines, \f2contool\fP will flash Xits icon when the appropriate message arrives. If the radiating lines are Xnot present, no flashing behavior will occur. X.IP "\f2Beep\fP" XThis icon switches between \*(lqquiet\*(rq (an image of a person holding Xtheir finger to their lips) and from one to four \*(lqbeep\*(rq symbols X(sounds waves radiating from a small dot). When set to \*(lqquiet\*(rq, X\f2contool\fP will not sound the terminal bell when a message arrives. XIf one or more \*(lqbeep\*(rq symbols are shown, \f2contool\fP will sound Xthe bell the indicated number of times. X.IP "\f2Message Length\fP" XThis icon toggles between \*(lqsingle line\*(rq (one small line of text) Xand \*(lqmulti-line\*(rq (several small lines of text) mode. In single Xline mode, one text field is provided for the filter pattern, and the Xfilter will be applied to each line of each console message that Xarrives. In multi-line mode, two fields, one for the starting pattern Xand another for the ending pattern, are provided. If a console message Xmatches the starting pattern, that filter will be in effect until a Xsubsequent line matches the ending pattern. All of the lines will be Xsaved or discarded as indicated by the \f2Save Message\fP icon. The Xbeeping, flashing, and window behaviors will only occur when the Xfirst line of the message is received. X.IP "" XSince it is not possible imbed newline characters in a filter pattern, Xsingle line filters should be used for single line messages (like someone Xbecoming superuser, for example) and multi-line filters should be Xused for block messages (like certain window system messages). X.LP XAn incoming message is tested against each filter in the order in which Xthey are displayed in the filter display. The first filter to match Xis used to control the message. If a multi-line filter matches, all Xsubsequent console messages will be controlled by that filter until the Xending pattern is matched. X.LP XFilter patterns can contain regular expressions like those accepted by \f2ed\fP(1). X.LP XIf a message does not match any filter, the actions in the default message Xwindow are applied to the filter. The icons in this window have the same Xmeaning as those in the filter display, with the exception that the \f2Save Message\fP Xicon cannot be switched to \*(lqignore\*(rq mode, and there is no single line/multi-line Xcnotrol. X.SH FILE FORMAT X.LP X\f2Contool\fP reads and writes filters in a human-readable format. XIn the filter file, blank lines and comments (starting with \*(lq#\*(rq Xand continuing to the end of line) are ignored. Remaining lines Xdescribe filters, one per line. Except within the actual filter Xpattern, case is not significant when reading the filter file. X.LP XThe first token on each line must be either \*(lqsave\*(rq or \*(lqignore\*(rq. XIf the first token is \*(lqsave\*(rq, one or more of the following filter Xattributes can follow the word \*(lqsave\*(rq: X.IP "\f2beep\fP <n>" Xdetermines the number of times the terminal bell will be sounded for this filter. XThe default is zero. X.IP "\f2flash\fP or \f2noflash\fP" Xdetermines if the icon will flash for this filter. XThe default is \f2noflash\fP. X.IP "\f2open\fP or \f2noopen\fP" Xdetermines if the window will pop open for this filter. XThe default is \f2noopen\fP. X.IP "\f2stamp\fP or \f2nostamp\fP" Xdetermines if messages matching this filter will be timestamped in the console window. XThe default is \f2nostamp\fP. X.LP XIf the first token is \*(lqignore\*(rq, none of these attributes are allowed. X.LP XAfter the \*(lqignore\*(rq token, or the \*(lqsave\*(rq token and optional Xattributes, are quoted strings representing the filter. For single line Xfilters, one quote string is permitted. For multi-line filters, two Xquoted strings, separated by the word \*(lqto\*(rq, are expected. X.LP XAs an example, the following two lines are valid filter specifications: X.IP "" XSAVE BEEP 0 NOFLASH NOOPEN STAMP 'SU: chuck' X.br XIGNORE 'Window data lock' TO 'The offending process' X.SH FILES X.ta 2i Xcontool.icon default \f3\(hyg\fP icon X.br Xstopsign.icon default \f3\(hyb\fP icon X.br Xstopsign_inv.icon default \f3\(hyf\fP icon X.br X~/.contool filter pattern file X.SH SEE ALSO Xed(1), suntools(1) X.SH AUTHOR X.LP XChuck Musciano X.br XAdvanced Technology Department X.br XHarris Corporation X.br XPO Box 37, MS 3A/1912 X.br XMelbourne, FL 32902 X.br X(407) 727-6131 X.br XARPA: chuck@trantor.harris-atd.com X.SH BUGS X.LP X\f2Contool\fP is a view-only tool, and there is no way to type commands Xon the console. END_OF_FILE if test 14027 -ne `wc -c <'contool.man'`; then echo shar: \"'contool.man'\" unpacked with wrong size! fi # end of 'contool.man' fi if test -f 'dialog.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dialog.c'\" else echo shar: Extracting \"'dialog.c'\" \(11074 characters\) sed "s/^X//" >'dialog.c' <<'END_OF_FILE' X/************************************************************************/ X/* Copyright 1988, 1989 by Chuck Musciano and Harris Corporation */ X/* */ X/* Permission to use, copy, modify, and distribute this software */ X/* and its documentation for any purpose and without fee is */ X/* hereby granted, provided that the above copyright notice */ X/* appear in all copies and that both that copyright notice and */ X/* this permission notice appear in supporting documentation, and */ X/* that the name of Chuck Musciano and Harris Corporation not be */ X/* used in advertising or publicity pertaining to distribution */ X/* of the software without specific, written prior permission. */ X/* Chuck Musciano and Harris Corporation make no representations */ X/* about the suitability of this software for any purpose. It is */ X/* provided "as is" without express or implied warranty. This */ X/* software may not be sold without the prior explicit permission */ X/* of Harris Corporation. */ X/************************************************************************/ X X#include <stdio.h> X X#include <sys/file.h> X X#include <suntool/sunview.h> X#include <suntool/panel.h> X X#include "contool.h" X#include "entry.h" X XPUBLIC Pixrect *better_button_image(); X XEXPORT Pixfont *bold, *regular; XEXPORT Panel other; X XPRIVATE Frame dialog = NULL; XPRIVATE Panel items; XPRIVATE Panel_item file_name; X X/************************************************************************/ X/* Support routines for edit buttons */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE f_ptr update_filters() X X{ int i, curr, limit, errors = FALSE; X char *result, *start, *end; X f_ptr f, new_filters = NULL; X X for (i = 0; i < entries; i++) X panel_set(entry[i].handle, PANEL_VALUE, 0, 0); X for (i = 0; i < entries; i++) X if (entry[i].created) { X start = (char *) panel_get(entry[i].start, PANEL_VALUE); X if (panel_get(entry[i].lines, PANEL_VALUE)) { X if (*start == '\0') { X window_error("Filter error:\n Filter %d is missing its starting pattern", i + 1); X panel_set(entry[i].handle, PANEL_VALUE, 1, 0); X panel_set(items, PANEL_CARET_ITEM, entry[i].start, 0); X errors = TRUE; X continue; X } X end = (char *) panel_get(entry[i].end, PANEL_VALUE); X if (*end == '\0') { X window_error("Filter error:\n Filter %d is missing its ending pattern", i + 1); X panel_set(entry[i].handle, PANEL_VALUE, 1, 0); X panel_set(items, PANEL_CARET_ITEM, entry[i].end, 0); X errors = TRUE; X continue; X } X } X else { X end = NULL; X if (*start == '\0') { X window_error("Filter error:\n Filter %d has no pattern specified", i + 1); X panel_set(entry[i].handle, PANEL_VALUE, 1, 0); X panel_set(items, PANEL_CARET_ITEM, entry[i].start, 0); X errors = TRUE; X continue; X } X } X if (result = compile_exp(NULL, start, end)) { X window_error("Error in filter %d:\n %s", i + 1, result); X panel_set(entry[i].handle, PANEL_VALUE, 1, 0); X panel_set(items, PANEL_CARET_ITEM, entry[i].start, 0); X errors = TRUE; X continue; X } X } X if (errors) X return(NULL); X for (i = 0, f = next_filter(&new_filters, &curr, &limit); i < MAX_ENTRIES; i++) X if (entry[i].created) { X f->save = (int) panel_get(entry[i].save, PANEL_VALUE); X f->beep = (int) panel_get(entry[i].beep, PANEL_VALUE); X f->open = (int) panel_get(entry[i].open, PANEL_VALUE); X f->flash = (int) panel_get(entry[i].flash, PANEL_VALUE); X f->stamp = (int) panel_get(entry[i].stamp, PANEL_VALUE); X f->start = strsave(panel_get(entry[i].start, PANEL_VALUE)); X f->end = panel_get(entry[i].lines, PANEL_VALUE)? strsave(panel_get(entry[i].end, PANEL_VALUE)) : NULL; X f->valid = TRUE; X compile_exp(f, f->start, f->end); X f = next_filter(&new_filters, &curr, &limit); X } X return(new_filters); X} X X/************************************************************************/ X/* Edit button action routines */ X/************************************************************************/ X X/************************************************************************/ XPRIVATE load_filters() X X{ char *path, *result; X f_ptr new_filters, f; X X path = (char *) panel_get(file_name, PANEL_VALUE); X if (access(path, R_OK) == 0) { X if (new_filters = read_filters(path, window_error)) { X for (f = new_filters; f->start; f++) X if (result = compile_exp(f, f->start, f->end)) { X window_error("Bad filter encountered in %s:\n %s", path, result); X f->valid = FALSE; X } X update_edit_dialog(new_filters); X free_filters(new_filters); X } X } X else X window_error("Cannot read filter file %s", path); X} X X/************************************************************************/ XPRIVATE save_filters() X X{ char *path; X f_ptr filters; X X if (filters = update_filters()) { X path = (char *) panel_get(file_name, PANEL_VALUE); X write_filters(filters, path, window_error); X } X else X window_error("Filters have not been saved"); X} X X/************************************************************************/ XPRIVATE cut_filter() X X{ int i, j; X X clear_clipboard(); X for (i = 0; i < entries; i++) X if (panel_get(entry[i].handle, PANEL_VALUE)) { X add_to_clipboard(entry + i); X delete_entry(entry + i); X } X else if (cb_size > 0) X move_entry(entry, i, i - cb_size); X entries -= cb_size; X panel_update_scrolling_size(items); X panel_paint(items, PANEL_NO_CLEAR); X} X X/************************************************************************/ XPRIVATE copy_filter() X X{ int i; X f_ptr f; X X clear_clipboard(); X for (i = cb_size = 0; i < entries; i++) X if (panel_get(entry[i].handle, PANEL_VALUE)) X add_to_clipboard(entry + i); X} X X/************************************************************************/ XPRIVATE paste_filter() X X{ int i, j, count; X X for (i = 0; i < entries; i++) X if (panel_get(entry[i].handle, PANEL_VALUE)) X break; X for (j = entries - 1, count = cb_size? cb_size : 1; j >= i; j--) X move_entry(entry, j, j + count); X if (cb_size == 0) { X update_entry(items, entry, i, NULL); X panel_set(items, PANEL_CARET_ITEM, entry[i].start, 0); X entries++; X } X else { X for (j = 0; j < cb_size; j++) X update_entry(items, entry, i + j, clipboard + j); X entries += cb_size; X } X panel_update_scrolling_size(items); X panel_paint(items, PANEL_NO_CLEAR); X} X X/************************************************************************/ XPRIVATE done_edit() X X{ f_ptr new_filters; X X if (new_filters = update_filters()) { X free_filters(filters); X filters = new_filters; X curr_filter = NULL; X install_defaults(); X strcpy(filter_path, panel_get(file_name, PANEL_VALUE)); X window_set(dialog, WIN_SHOW, FALSE, 0); X } X} X X/************************************************************************/ XPRIVATE reset_edit() X X{ X update_edit_dialog(filters); X update_defaults(); X} X X/************************************************************************/ XPRIVATE quit_edit() X X{ X window_set(dialog, WIN_SHOW, FALSE, 0); X} X X/************************************************************************/ X/* External entry points to this module */ X/************************************************************************/ X X/************************************************************************/ XEXPORT update_edit_dialog(filters) X Xf_ptr filters; X X{ register int i; X register e_ptr e; X register f_ptr f; X X for (i = 0, f = filters; f->start; i++, e++, f++) { X create_entry(items, entry, i); X update_entry(items, entry, i, f); X } X for (entries = i, e = entry + i; i < MAX_ENTRIES; i++, e++) X delete_entry(e); X panel_update_scrolling_size(items); X panel_paint(items, PANEL_CLEAR); X} X X/************************************************************************/ XEXPORT Frame create_dialog_box(base) X XFrame base; X X{ Panel control; X Panel_item c, p, d; X int i; X X if (dialog) X return; X bold = pf_open(BOLD_FONT); X regular = pf_open(REGULAR_FONT); X dialog = window_create(base, FRAME, X FRAME_LABEL, "<< Contool Filter Editor >>", X FRAME_SHOW_LABEL, TRUE, X FRAME_NO_CONFIRM, TRUE, X FRAME_DONE_PROC, done_edit, X 0); X control = window_create(dialog, PANEL, X WIN_WIDTH, ITEM_WIDTH, X 0); X panel_create_item(control, PANEL_BUTTON, X PANEL_LABEL_IMAGE, better_button_image(control, "Load", 12, 4, bold), X PANEL_NOTIFY_PROC, load_filters, X 0); X panel_create_item(control, PANEL_BUTTON, X PANEL_LABEL_IMAGE, better_button_image(control, "Save", 12, 3, bold), X PANEL_NOTIFY_PROC, save_filters, X 0); X c = panel_create_item(control, PANEL_BUTTON, X PANEL_LABEL_IMAGE, better_button_image(control, "Cut", 12, 4, bold), X PANEL_NOTIFY_PROC, cut_filter, X 0); X p = panel_create_item(control, PANEL_BUTTON, X PANEL_LABEL_IMAGE, better_button_image(control, "Paste", 12, 3, bold), X PANEL_NOTIFY_PROC, paste_filter, X 0); X d = panel_create_item(control, PANEL_BUTTON, X PANEL_LABEL_IMAGE, better_button_image(control, "Done", 12, 4, bold), X PANEL_NOTIFY_PROC, done_edit, X 0); X file_name = panel_create_item(control, PANEL_TEXT, X PANEL_ITEM_Y, 35, X PANEL_LABEL_STRING, "File:", X PANEL_LABEL_FONT, bold, X PANEL_VALUE_STORED_LENGTH, 256, X PANEL_VALUE_DISPLAY_LENGTH, 24, X PANEL_VALUE_FONT, regular, X PANEL_VALUE, filter_path, X 0); X panel_create_item(control, PANEL_BUTTON, X PANEL_ITEM_Y, 31, X PANEL_LABEL_IMAGE, better_button_image(control, "Copy", 12, 4, bold), X PANEL_NOTIFY_PROC, copy_filter, X PANEL_ITEM_X, panel_get(c, PANEL_ITEM_X), X 0); X panel_create_item(control, PANEL_BUTTON, X PANEL_ITEM_Y, 31, X PANEL_LABEL_IMAGE, better_button_image(control, "Reset", 12, 4, bold), X PANEL_NOTIFY_PROC, reset_edit, X PANEL_ITEM_X, panel_get(p, PANEL_ITEM_X), X 0); X panel_create_item(control, PANEL_BUTTON, X PANEL_ITEM_Y, 31, X PANEL_LABEL_IMAGE, better_button_image(control, "Cancel", 12, 4, bold), X PANEL_NOTIFY_PROC, quit_edit, X PANEL_ITEM_X, panel_get(d, PANEL_ITEM_X), X 0); X window_fit_height(control); X items = window_create(dialog, PANEL, X WIN_X, 0, X WIN_BELOW, control, X WIN_WIDTH, ITEM_WIDTH, X WIN_HEIGHT, ROW_HEIGHT * 10 + ROW_MARGIN * 11, X WIN_VERTICAL_SCROLLBAR, scrollbar_create(0), X 0); X other = window_create(dialog, PANEL, X WIN_X, 0, X WIN_BELOW, items, X WIN_WIDTH, ITEM_WIDTH, X WIN_HEIGHT, ROW_HEIGHT + ROW_MARGIN * 2, X 0); X window_fit(dialog); X for (i = 0; i < MAX_ENTRIES; i++) X entry[i].created = FALSE; X return(dialog); X} END_OF_FILE if test 11074 -ne `wc -c <'dialog.c'`; then echo shar: \"'dialog.c'\" unpacked with wrong size! fi # end of 'dialog.c' fi echo shar: End of archive 3 \(of 3\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 Chuck Musciano ARPA : chuck@trantor.harris-atd.com Harris Corporation Usenet: ...!uunet!x102a!trantor!chuck PO Box 37, MS 3A/1912 AT&T : (407) 727-6131 Melbourne, FL 32902 FAX : (407) 727-{5118,5227,4004} Gee, Beaver, everything that's fun can get you in trouble. Haven't you learned that yet? --Gilbert