v01i078: A Sunview console message hander, v2.2, Part03/03
Charles Mcgrew
mcgrew at dartagnan.rutgers.edu
Fri Oct 20 09:06:11 AEST 1989
Submitted-by: chuck at 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 at 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 at 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 at 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
More information about the Comp.sources.sun
mailing list