[comp.sources.sun] v01i077: A Sunview console message hander, v2.2, Part02/03

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (10/20/89)

Submitted-by: chuck@trantor.harris-atd.com (Chuck Musciano)
Posting-number: Volume 1, Issue 77
Archive-name: contool2.2/part02

#! /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 2 (of 3)."
# Contents:  contool.h default.c entry.c filters.c images.c misc.c
#   regexp.c
# Wrapped by chuck@melmac on Wed Sep 20 09:46:41 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'contool.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'contool.h'\"
else
echo shar: Extracting \"'contool.h'\" \(4947 characters\)
sed "s/^X//" >'contool.h' <<'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/**************** Site dependent parameters ****************************/
X
X/* Where the default contool icons are kept.  !Must end in '/'! */
X
X#if !defined(ICON_DIRECTORY)
X#define		ICON_DIRECTORY		"./icons/"
X#endif
X
X/* Where the Sun-provided fonts reside.  Probably already correct */
X
X#define		BOLD_FONT		"/usr/lib/fonts/fixedwidthfonts/screen.b.14"
X#define		REGULAR_FONT		"/usr/lib/fonts/fixedwidthfonts/screen.r.14"
X
X/* The default icon names.  Alternate sets are shown, and you might want
X   to try these instead of the default set by uncommenting the desired set. */
X
X/* This set gives a blinking stop sign when messages arrive. */
X#define		GOOD_ICON		"contool.icon"
X#define		BAD_ICON		"stopsign.icon"
X#define		INVERSE_ICON		"stopsign_inv.icon"
X
X/* This set gives a terminal, labelled "Console", in a box.  The screen
X   flashes when messages arrive. */
X/* #define		GOOD_ICON	"contool.icon" */
X/* #define		BAD_ICON	"contool.icon" */
X/* #define		INVERSE_ICON	"contool_bad.icon" */
X
X/* This set gives a terminal, without a box.  Again, the screen flashes
X   when messages arrive. */
X/* #define		GOOD_ICON	"console1.icon" */
X/* #define		BAD_ICON	"console1_bad.icon" */
X/* #define		INVERSE_ICON	"console1_flash.icon" */
X
X/*************** End of site dependencies ******************************/
X
X#ifndef TRUE
X#define		TRUE			1
X#define		FALSE			0
X#endif
X
X#define		PRIVATE			static
X#define		PUBLIC			extern
X#define		EXPORT
X
X#define		TOOL_LABEL		"<< Console Tool 2.2 >>"
X
X#define		strsave(s)		((char *) strcpy(malloc(strlen(s) + 1), s))
X
X#define		BEEP_COUNT		3
X#define		TS_INTERVAL		60
X
X#define		TEXT_SIZE_LIMIT		32768
X#define		TEXT_SIZE_FUZZ		1024
X#define		TEXT_DELETE_SIZE	1024
X
X#define		INPUT_BUFFER_SIZE	4096
X
Xtypedef	char	boolean;
Xtypedef	struct	f_data	f_rec, *f_ptr;
X
Xstruct	f_data	{char		*start;		/* starting string */
X		 char		*start_re;	/* starting compiled regular expression */
X		 char		*end;		/* ending string */
X		 char		*end_re;	/* starting compiled regular expression */
X		 int		scircf;		/* used by regex */
X		 int		ecircf;		/* used by regex */
X		 boolean	valid;		/* filter expressions are valid */
X		 boolean	beep;		/* number of times to beep */
X		 boolean	flash;		/* make the icon blink */
X		 boolean	open;		/* pop open the console window */
X		 boolean	save;		/* save message in console */
X		 boolean	stamp;		/* timestamp message */
X		};
X
XPUBLIC	struct	pixrect	better_button_cross;
XPUBLIC	struct	pixrect	handle_pix;
XPUBLIC	struct	pixrect	nohandle_pix;
XPUBLIC	struct	pixrect	beep_0_pix;
XPUBLIC	struct	pixrect	beep_1_pix;
XPUBLIC	struct	pixrect	beep_2_pix;
XPUBLIC	struct	pixrect	beep_3_pix;
XPUBLIC	struct	pixrect	beep_4_pix;
XPUBLIC	struct	pixrect	open_pix;
XPUBLIC	struct	pixrect	close_pix;
XPUBLIC	struct	pixrect	flash_pix;
XPUBLIC	struct	pixrect	noflash_pix;
XPUBLIC	struct	pixrect	save_pix;
XPUBLIC	struct	pixrect	nosave_pix;
XPUBLIC	struct	pixrect	stamp_pix;
XPUBLIC	struct	pixrect	nostamp_pix;
XPUBLIC	struct	pixrect	single_pix;
XPUBLIC	struct	pixrect	range_pix;
XPUBLIC	struct	pixrect	stopsign_pix;
X
XPUBLIC	char	filter_path[256];
XPUBLIC	int	pop_open;
XPUBLIC	int	beep_amount;
XPUBLIC	int	blink_icon;
XPUBLIC	int	do_time_stamp;
XPUBLIC	f_ptr	filters;
XPUBLIC	f_ptr	curr_filter;
X
XPUBLIC	int	match_exp(/* char *exp, int circ, char *str */);
XPUBLIC	char	*compile_exp(/* f_ptr filter, char *start, char *end */);
XPUBLIC	int	getline(/* FILE *f, char *buf, int max */);
XPUBLIC	char	getopt(/* int *argc, char **argv, char *opts, char **parm*/);
XPUBLIC	char	*lower(/* char *str */);
XPUBLIC	int	verify(/* char *source, char *valid */);
XPUBLIC	char	**saveargs(/* int argc, char **argv */);
XPUBLIC	char	*open_psuedo_tty(/* FILE **master, char *m_mode, FILE **slave, char *s_mode */);
XPUBLIC	char	*index();
XPUBLIC	f_ptr	read_filters(/* char *path, void (*f)() */);
XPUBLIC	f_ptr	next_filter(/* f_ptr *base, int *curr, int *limit */);
XPUBLIC	char	**tokenize(/* char *line, int *count */);
END_OF_FILE
if test 4947 -ne `wc -c <'contool.h'`; then
    echo shar: \"'contool.h'\" unpacked with wrong size!
fi
# end of 'contool.h'
fi
if test -f 'default.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'default.c'\"
else
echo shar: Extracting \"'default.c'\" \(3650 characters\)
sed "s/^X//" >'default.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	<suntool/sunview.h>
X#include	<suntool/panel.h>
X#include	<suntool/scrollbar.h>
X
X#include	"contool.h"
X#include	"entry.h"
X
X#define		shift(item, amt)		panel_set(item, PANEL_ITEM_X, (int) panel_get(item, PANEL_ITEM_X) + amt, 0)
X
XPUBLIC	Panel	other;
X
XPRIVATE	e_rec	defaults = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE};
X
X/************************************************************************/
XEXPORT	update_defaults()
X
X{	int	x, y, amt;
X	Pixrect	*image;
X	Scrollbar	temp;
X
X	if (!defaults.created) {
X	   create_entry(other, &defaults, 0);
X	   panel_set(other, WIN_VERTICAL_SCROLLBAR, temp = scrollbar_create(0), 0);
X	   if ((Scrollbar_setting) scrollbar_get(temp, SCROLL_PLACEMENT) == SCROLL_WEST) {
X	      amt = (int) scrollbar_get(temp, SCROLL_WIDTH);
X	      shift(defaults.handle, amt);
X	      shift(defaults.save, amt);
X	      shift(defaults.stamp, amt);
X	      shift(defaults.open, amt);
X	      shift(defaults.flash, amt);
X	      shift(defaults.beep, amt);
X	      shift(defaults.lines, amt);
X	      shift(defaults.start, amt);
X	      shift(defaults.end, amt);
X	      }
X	   panel_set(other, WIN_VERTICAL_SCROLLBAR, NULL, 0);
X	   scrollbar_destroy(temp);
X	   eliminate(defaults.handle);
X	   eliminate(defaults.lines);
X	   eliminate(defaults.end);
X	   x = (int) panel_get(defaults.save, PANEL_ITEM_X);
X	   y = (int) panel_get(defaults.save, PANEL_ITEM_Y);
X	   eliminate(defaults.save);
X	   defaults.save = panel_create_item(other, PANEL_MESSAGE,
X	   					 PANEL_LABEL_IMAGE, &save_pix,
X	   					 PANEL_ITEM_X, x,
X	   					 PANEL_ITEM_Y, y,
X	   				      0);
X	   x = (int) panel_get(defaults.start, PANEL_ITEM_X);
X	   y = (int) panel_get(defaults.start, PANEL_ITEM_Y);
X	   eliminate(defaults.start);
X	   defaults.start = panel_create_item(other, PANEL_MESSAGE,
X	   					 PANEL_LABEL_STRING, "All other messages",
X	   					 PANEL_LABEL_FONT, bold,
X	   					 PANEL_ITEM_X, x,
X	   					 PANEL_ITEM_Y, y,
X	   				      0);
X	   defaults.created = TRUE;
X	   }
X	panel_set(defaults.beep, PANEL_VALUE, beep_amount, 0);
X	panel_set(defaults.flash, PANEL_VALUE, blink_icon, 0);
X	panel_set(defaults.open, PANEL_VALUE, pop_open, 0);
X	panel_set(defaults.stamp, PANEL_VALUE, do_time_stamp, 0);
X}
X
X/************************************************************************/
XEXPORT	install_defaults()
X
X{
X	beep_amount   = (int) panel_get(defaults.beep, PANEL_VALUE);
X	blink_icon    = (int) panel_get(defaults.flash, PANEL_VALUE);
X	pop_open      = (int) panel_get(defaults.open, PANEL_VALUE);
X	do_time_stamp = (int) panel_get(defaults.stamp, PANEL_VALUE);
X}
END_OF_FILE
if test 3650 -ne `wc -c <'default.c'`; then
    echo shar: \"'default.c'\" unpacked with wrong size!
fi
# end of 'default.c'
fi
if test -f 'entry.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'entry.c'\"
else
echo shar: Extracting \"'entry.c'\" \(9622 characters\)
sed "s/^X//" >'entry.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	<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	e_rec	entry[MAX_ENTRIES];
XEXPORT	int	entries = 0;
X
X/************************************************************************/
X/*	Routines handling dialog element interaction			*/
X/************************************************************************/
X
X/************************************************************************/
XPRIVATE	save_toggle_proc(item, value, event)
X
XPanel_item	item;
Xint		value;
XEvent		*event;
X
X{	e_ptr	e;
X
X	e = (e_ptr) panel_get(item, PANEL_CLIENT_DATA);
X	panel_set(e->beep,  PANEL_SHOW_ITEM, value, 0);
X	panel_set(e->open,  PANEL_SHOW_ITEM, value, 0);
X	panel_set(e->flash, PANEL_SHOW_ITEM, value, 0);
X	panel_set(e->stamp, PANEL_SHOW_ITEM, value, 0);
X}
X
X/************************************************************************/
XPRIVATE	lines_toggle_proc(item, value, event)
X
XPanel_item	item;
Xint		value;
XEvent		*event;
X
X{	e_ptr	e;
X
X	e = (e_ptr) panel_get(item, PANEL_CLIENT_DATA);
X	if (value) { /* go to multi-line filter */
X	   panel_set(e->start, PANEL_VALUE_DISPLAY_LENGTH, SHORT_TEXT_LENGTH, 0);
X	   panel_set(e->end, PANEL_SHOW_ITEM, TRUE, 0);
X	   panel_set(panel_get(item, PANEL_PARENT_PANEL), PANEL_CARET_ITEM, e->end, 0);
X	   }
X	else {
X	   panel_set(e->end, PANEL_SHOW_ITEM, FALSE, 0);
X	   panel_set(e->start, PANEL_VALUE_DISPLAY_LENGTH, LONG_TEXT_LENGTH, 0);
X	   panel_set(panel_get(item, PANEL_PARENT_PANEL), PANEL_CARET_ITEM, e->start, 0);
X	   }
X}
X
X/************************************************************************/
XPRIVATE	handle_toggle_proc(item, event)
X
XPanel_item	item;
XEvent		*event;
X
X{	e_ptr	e;
X	int	i;
X
X	if (event_is_down(event))
X	   if (event_id(event) == MS_LEFT)
X	      if (panel_get(item, PANEL_VALUE) == 0) {
X	         for (i = 0; i < entries; i++)
X	            panel_set(entry[i].handle, PANEL_VALUE, 0, 0);
X	         panel_set(item, PANEL_VALUE, 1 - (int) panel_get(item, PANEL_VALUE), 0);
X	         }
X	      else {
X	         for (i = 0; i < entries; i++)
X	            if (entry[i].handle != item && panel_get(entry[i].handle, PANEL_VALUE))
X	               break;
X	         if (i == entries)
X	            panel_set(item, PANEL_VALUE, 0, 0);
X	         else {
X	            for (i = 0; i < entries; i++)
X	               panel_set(entry[i].handle, PANEL_VALUE, 0, 0);
X	            panel_set(item, PANEL_VALUE, 1, 0);
X	            }
X	         }
X	   else if (event_id(event) == MS_MIDDLE)
X	      panel_set(item, PANEL_VALUE, 1 - (int) panel_get(item, PANEL_VALUE), 0);
X}
X
X/************************************************************************/
XEXPORT	create_entry(panel, base, row)
X
Xregister	Panel	panel;
X		e_ptr	base;
Xregister	int	row;
X
X{	register	e_ptr	e;
X
X	e = base + row;
X	if (e->created)
X	   return;
X	row = row * (ROW_HEIGHT + ROW_MARGIN) + ROW_MARGIN;
X	e->created = TRUE;
X	e->handle = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 4,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &nohandle_pix, &handle_pix, 0,
X	      				 PANEL_EVENT_PROC, handle_toggle_proc,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->save   = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 16,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &nosave_pix, &save_pix, 0,
X	      				 PANEL_NOTIFY_PROC, save_toggle_proc,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->stamp  = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 36,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &nostamp_pix, &stamp_pix, 0,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->open   = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 56,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &close_pix, &open_pix, 0,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->flash  = panel_create_item(panel, PANEL_CHOICE,
X	 				 PANEL_ITEM_X, 76,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &noflash_pix, &flash_pix, 0,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->beep   = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 96,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &beep_0_pix, &beep_1_pix, &beep_2_pix, &beep_3_pix, &beep_4_pix, 0,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->lines  = panel_create_item(panel, PANEL_CHOICE,
X	      				 PANEL_ITEM_X, 170,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
X	      				 PANEL_CHOICE_IMAGES, &single_pix, &range_pix, 0,
X	      				 PANEL_NOTIFY_PROC, lines_toggle_proc,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->start  = panel_create_item(panel, PANEL_TEXT,
X	      				 PANEL_ITEM_X, 190,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_VALUE_STORED_LENGTH, 256,
X	      				 PANEL_VALUE_DISPLAY_LENGTH, SHORT_TEXT_LENGTH,
X	      				 PANEL_VALUE_FONT, regular,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X	e->end    = panel_create_item(panel, PANEL_TEXT,
X	      				 PANEL_ITEM_X, 398,
X	      				 PANEL_ITEM_Y, row,
X	      				 PANEL_VALUE_STORED_LENGTH, 256,
X	      				 PANEL_VALUE_DISPLAY_LENGTH, SHORT_TEXT_LENGTH,
X	      				 PANEL_VALUE_FONT, regular,
X	      				 PANEL_LABEL_STRING, "to",
X	      				 PANEL_LABEL_FONT, bold,
X	      				 PANEL_CLIENT_DATA, e,
X	      			      0);
X}
X
X/************************************************************************/
XEXPORT	update_entry(panel, base, row, f)
X
XPanel	panel;
Xe_ptr	base;
Xint	row;
Xregister	f_ptr	f;
X
X{	f_rec	temp;
X	register	e_ptr	e;
X
X	create_entry(panel, base, row);
X	if (f == NULL) {
X	   bzero(&temp, sizeof(temp));
X	   temp.start = "";
X	   f = &temp;
X	   }
X	e = base + row;
X	panel_set(e->handle, PANEL_VALUE, 0,        PANEL_SHOW_ITEM, TRUE,    0);
X	panel_set(e->save,   PANEL_VALUE, f->save,  PANEL_SHOW_ITEM, TRUE,    0);
X	panel_set(e->beep,   PANEL_VALUE, f->beep,  PANEL_SHOW_ITEM, f->save, 0);
X	panel_set(e->open,   PANEL_VALUE, f->open,  PANEL_SHOW_ITEM, f->save, 0);
X	panel_set(e->flash,  PANEL_VALUE, f->flash, PANEL_SHOW_ITEM, f->save, 0);
X	panel_set(e->stamp,  PANEL_VALUE, f->stamp, PANEL_SHOW_ITEM, f->save, 0);
X	panel_set(e->start,  PANEL_VALUE, f->start, PANEL_SHOW_ITEM, TRUE,    0);
X	if (f->end) {
X	   panel_set(e->lines, PANEL_VALUE, 1, PANEL_SHOW_ITEM, TRUE, 0);
X	   panel_set(e->end, PANEL_VALUE, f->end, PANEL_SHOW_ITEM, TRUE, 0);
X	   panel_set(e->start, PANEL_VALUE_DISPLAY_LENGTH, SHORT_TEXT_LENGTH, 0);
X	   }
X	else {
X	   panel_set(e->lines, PANEL_VALUE, 0, PANEL_SHOW_ITEM, TRUE, 0);
X	   panel_set(e->end, PANEL_SHOW_ITEM, FALSE, 0);
X	   panel_set(e->start, PANEL_VALUE_DISPLAY_LENGTH, LONG_TEXT_LENGTH, 0);
X	   }
X}
X
X/************************************************************************/
XEXPORT	move_entry(base, old_row, new_row)
X
Xe_ptr	base;
Xint	old_row;
Xint	new_row;
X
X{	register	e_ptr	new_entry, old_entry;
X	register	int	row;
X
X	new_entry = base + new_row;
X	old_entry = base + old_row;
X	row = new_row * (ROW_HEIGHT + ROW_MARGIN) + ROW_MARGIN;
X	panel_set(old_entry->handle, PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->beep,   PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->open,   PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->flash,  PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->save,   PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->stamp,  PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->lines,  PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->end,    PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	panel_set(old_entry->start,  PANEL_ITEM_Y, row, PANEL_CLIENT_DATA, new_entry, 0);
X	*new_entry = *old_entry;
X	old_entry->created = FALSE;
X}
X
X/************************************************************************/
XEXPORT	delete_entry(e)
X
Xregister	e_ptr	e;
X
X{
X	if (e->created) {
X	   eliminate(e->handle);
X	   eliminate(e->beep);
X	   eliminate(e->open);
X	   eliminate(e->flash);
X	   eliminate(e->save);
X	   eliminate(e->stamp);
X	   eliminate(e->lines);
X	   eliminate(e->start);
X	   eliminate(e->end);
X	   e->created = FALSE;
X	   }
X}
END_OF_FILE
if test 9622 -ne `wc -c <'entry.c'`; then
    echo shar: \"'entry.c'\" unpacked with wrong size!
fi
# end of 'entry.c'
fi
if test -f 'filters.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'filters.c'\"
else
echo shar: Extracting \"'filters.c'\" \(6015 characters\)
sed "s/^X//" >'filters.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	<ctype.h>
X
X#include	"contool.h"
X
X#define		MAX_ERRORS		3
X
X/************************************************************************/
XPRIVATE	int	match(s1, s2)
X
Xregister	char	*s1;
Xregister	char	*s2; /* always in lower case */
X
X{
X	for ( ; *s1 && *s2; s1++, s2++)
X	   if (isupper(*s1)) {
X	      if (tolower(*s1) != *s2)
X	         return(FALSE);
X	      }
X	   else if (*s1 != *s2)
X	      return(FALSE);
X	return(*s1 == '\0' && *s2 == '\0');
X}
X
X/************************************************************************/
XEXPORT	f_ptr	next_filter(base, curr, limit)
X
Xf_ptr	*base;
Xint	*curr;
Xint	*limit;
X
X{	f_ptr	f;
X
X	if (*base == NULL) {
X	   f = *base = (f_ptr) malloc(sizeof(f_rec) * 16);
X	   *limit = 16;
X	   *curr = 1;
X	   }
X	else { 
X	   if (*curr >= *limit) {
X	      *base = (f_ptr) realloc(*base, sizeof(f_rec) * (*limit + 16));
X	      *limit += 16;
X	      }
X	   f = *base + *curr;
X	   (*curr)++;
X	   }
X	bzero(f, sizeof(f_rec));
X	return(f);
X}
X
X/************************************************************************/
XEXPORT	f_ptr	read_filters(path, error)
X
Xchar	*path;
Xvoid	(*error)();
X
X{	FILE	*in;
X	char	buf[512], **token, *p;
X	int	count, base, errors, curr, limit;
X	f_ptr	f, filter = NULL;
X
X	if ((in = fopen(path, "r")) == NULL) {
X	   error("Could not read filter file %s", path);
X	   return(NULL);
X	   }
X	f = next_filter(&filter, &curr, &limit);
X	for (errors = 0; errors < MAX_ERRORS && getline(in, buf, 512) != EOF; ) {
X	   if ((p = index(buf, '#')) != NULL)
X	      *p = '\0';
X	   if (strlen(buf) == 0 || verify(buf, " "))
X	      continue;
X	   token = tokenize(buf, &count);
X	   f->valid = TRUE;
X	   if (match(token[0], "ignore")) {
X	      base = 1;
X	      count--;
X	      }
X	   else if (match(token[0], "quiet")) {
X	      f->save = TRUE;
X	      f->stamp = TRUE;
X	      base = 1;
X	      count--;
X	      }
X	   else if (match(token[0], "save")) {
X	      f->save = TRUE;
X	      count--;
X	      for (base = 1; count > 0; base++, count--)
X	         if (match(token[base], "beep")) {
X	            if (verify(token[++base], "0123456789")) {
X	               f->beep = atoi(token[base]);
X	               count--;
X	               }
X	            else {
X	               error("Invalid filter:\n   invalid beep amount: %s", token[base]);
X	               errors++;
X	               f->valid = FALSE;
X	               break;
X	               }
X	            }
X	         else if (match(token[base], "flash"))
X	            f->flash = TRUE;
X	         else if (match(token[base], "noflash"))
X	            f->flash = FALSE;
X	         else if (match(token[base], "open"))
X	            f->open = TRUE;
X	         else if (match(token[base], "noopen"))
X	            f->open = FALSE;
X	         else if (match(token[base], "stamp"))
X	            f->stamp = TRUE;
X	         else if (match(token[base], "nostamp"))
X	            f->stamp = FALSE;
X	         else
X	            break;
X	      }
X	   else {
X	      error("Invalid filter:\n   Unknown action (%s) specified for\n\t%s", token[0], buf);
X	      f->valid = FALSE;
X	      errors++;
X	      }
X	   if (f->valid)
X	      if (count == 1)
X	         f->start = token[base];
X	      else if (count == 3)
X	         if (match(token[base + 1], "to")) {
X	            f->start = token[base];
X	            f->end = token[base + 2];
X	            }
X	         else {
X	            error("Invalid filter:\n   expected \"to\" instead of \"%s\" in\n\t\"%s\"\n", token[base + 1], buf);
X	            f->valid = FALSE;
X	            errors++;
X	            }
X	      else {
X	         error("Invalid filter:\n   too many tokens in\n\t%s", buf);
X	         f->valid = FALSE;
X	         errors++;
X	         }
X	   if (f->valid)
X	      f = next_filter(&filter, &curr, &limit);
X	   }
X	f->start = NULL;
X	fclose(in);
X	if (errors >= MAX_ERRORS) {
X	   error("Filter loading terminated prematurely.  Too many errors.");
X	   return(NULL);
X	   }
X	else
X	   return(filter);
X}
X
X/************************************************************************/
XEXPORT	write_filters(filter, path, error)
X
Xf_ptr	filter;
Xchar	*path;
Xvoid	(*error)();
X
X{	FILE	*f;
X
X	if ((f = fopen(path, "w")) == NULL) {
X	   error("Could not write filter file %s", path);
X	   return;
X	   }
X	for ( ; filter->start; filter++) {
X	   if (filter->save) {
X	      fprintf(f, "SAVE\tBEEP %2d\t", filter->beep);
X	      fprintf(f, "%sFLASH\t", filter->flash? "  " : "NO");
X	      fprintf(f, "%sOPEN\t", filter->open?  "  " : "NO");
X	      fprintf(f, "%sSTAMP\t", filter->stamp? "  " : "NO");
X	      }
X	   else
X	      fprintf(f, "IGNORE\t\t\t\t\t");
X	   fprintf(f, "'%s'", filter->start);
X	   if (filter->end)
X	      fprintf(f, " TO '%s'", filter->end);
X	   fprintf(f, "\n");
X	   }
X	fclose(f);
X}
X
X/************************************************************************/
XEXPORT	free_filters(filter)
X
Xf_ptr	filter;
X
X{	f_ptr 	f;
X
X	if (filter) {
X	   for (f = filter; f->start; f++) {
X	      free(f->start);
X	      if (f->end)
X	         free(f->end);
X	      }
X	   free(filter);
X	   }
X}
END_OF_FILE
if test 6015 -ne `wc -c <'filters.c'`; then
    echo shar: \"'filters.c'\" unpacked with wrong size!
fi
# end of 'filters.c'
fi
if test -f 'images.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'images.c'\"
else
echo shar: Extracting \"'images.c'\" \(3383 characters\)
sed "s/^X//" >'images.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	<suntool/sunview.h>
X
X#include	"contool.h"
X
XPRIVATE	short	cross_bits[] = {0x4000, 0xe000, 0x4000};
Xmpr_static(better_button_cross, 3, 3, 1, cross_bits);
X
XPRIVATE	short	handle_bits[] = {
X#include	"images/handle.icon"
X			  };
Xmpr_static(handle_pix, 8, 16, 1, handle_bits);
X
XPRIVATE	short	nohandle_bits[] = {
X#include	"images/nohandle.icon"
X			  };
Xmpr_static(nohandle_pix, 8, 16, 1, nohandle_bits);
X
XPRIVATE	short	beep_0_bits[] = {
X#include	"images/beep_0.icon"
X			  };
Xmpr_static(beep_0_pix, 16, 16, 1, beep_0_bits);
X
XPRIVATE	short	beep_1_bits[] = {
X#include	"images/beep_1.icon"
X			  };
Xmpr_static(beep_1_pix, 16, 16, 1, beep_1_bits);
X
XPRIVATE	short	beep_2_bits[] = {
X#include	"images/beep_2.icon"
X			  };
Xmpr_static(beep_2_pix, 34, 16, 1, beep_2_bits);
X
XPRIVATE	short	beep_3_bits[] = {
X#include	"images/beep_3.icon"
X			  };
Xmpr_static(beep_3_pix, 52, 16, 1, beep_3_bits);
X
XPRIVATE	short	beep_4_bits[] = {
X#include	"images/beep_4.icon"
X			  };
Xmpr_static(beep_4_pix, 70, 16, 1, beep_4_bits);
X
XPRIVATE	short	open_bits[] = {
X#include	"images/open.icon"
X			  };
Xmpr_static(open_pix, 16, 16, 1, open_bits);
X
XPRIVATE	short	close_bits[] = {
X#include	"images/close.icon"
X			  };
Xmpr_static(close_pix, 16, 16, 1, close_bits);
X
XPRIVATE	short	flash_bits[] = {
X#include	"images/flash.icon"
X			  };
Xmpr_static(flash_pix, 16, 16, 1, flash_bits);
X
XPRIVATE	short	noflash_bits[] = {
X#include	"images/noflash.icon"
X			  };
Xmpr_static(noflash_pix, 16, 16, 1, noflash_bits);
X
XPRIVATE	short	save_bits[] = {
X#include	"images/save.icon"
X			  };
Xmpr_static(save_pix, 16, 16, 1, save_bits);
X
XPRIVATE	short	nosave_bits[] = {
X#include	"images/nosave.icon"
X			  };
Xmpr_static(nosave_pix, 16, 16, 1, nosave_bits);
X
XPRIVATE	short	stamp_bits[] = {
X#include	"images/stamp.icon"
X			  };
Xmpr_static(stamp_pix, 16, 16, 1, stamp_bits);
X
XPRIVATE	short	nostamp_bits[] = {
X#include	"images/nostamp.icon"
X			  };
Xmpr_static(nostamp_pix, 16, 16, 1, nostamp_bits);
X
XPRIVATE	short	single_bits[] = {
X#include	"images/single.icon"
X			  };
Xmpr_static(single_pix, 16, 16, 1, single_bits);
X
XPRIVATE	short	range_bits[] = {
X#include	"images/range.icon"
X			  };
Xmpr_static(range_pix, 16, 16, 1, range_bits);
X
XPRIVATE	short	stopsign_bits[] = {
X#include	"images/stopsign.icon"
X			  };
Xmpr_static(stopsign_pix, 64, 64, 1, stopsign_bits);
END_OF_FILE
if test 3383 -ne `wc -c <'images.c'`; then
    echo shar: \"'images.c'\" unpacked with wrong size!
fi
# end of 'images.c'
fi
if test -f 'misc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'misc.c'\"
else
echo shar: Extracting \"'misc.c'\" \(4723 characters\)
sed "s/^X//" >'misc.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	<ctype.h>
X
X#include	"contool.h"
X
X/************************************************************************/
XEXPORT	int	getline(stream, string, max)
X
XFILE	*stream;
Xchar	*string;
Xint	max;
X
X{	register	int	i, j;
X
X	i = (int) fgets(string, max, stream);
X	if (i == NULL)
X	   return(EOF);
X	j = strlen(string);
X	if (j > 0 && string[j - 1] == '\n')
X	   string[--j] = '\0';
X	return(j);
X}
X
X/************************************************************************/
XPRIVATE	delarg(argc, argv)
X
Xint	*argc;
Xchar	**argv;
X
X{	char	*p;
X
X	while (*argv = *(argv+1))
X	   argv++;
X	(*argc)--;
X}
X
X/************************************************************************/
XEXPORT	char	getopt(argc, argv, opts, parm)
X
Xint	*argc;
Xchar	**argv;
Xchar	*opts;
Xchar	**parm;
X
X{	char	c, *p, *strcpy(), *index();
X	int	killed;
X
X	*parm = NULL;
X	while (*argv && ((**argv != '-') || (*(*argv+1) == '\0')))
X	   argv++;
X	if (*argv == NULL)
X	   return(EOF);
X	c = *(*argv+1);
X	*++(*argv) = '-';
X	if (killed = (*(*argv+1) == '\0'))
X	   delarg(argc, argv);
X	if ((p = index(opts, c)) == NULL)
X	   c = '\0';
X	else if (*(p+1) == ':') {
X	   *parm = killed ? *argv : *argv+1;
X	   delarg(argc, argv);
X	   }
X	return(c);
X}
X
X/************************************************************************/
XEXPORT	int	verify(source, valid)
X
Xchar	*source;
Xchar	*valid;
X
X{	register	char	*s;
X
X	for ( ; *source; source++) {
X	   for (s = valid; *s && *s != *source; s++)
X	      ;
X	   if (*s == '\0')
X	      return(0);
X	   }
X	return(1);
X}
X
X/************************************************************************/
XEXPORT	char	**saveargs(argc, argv)
X
Xint	argc;
Xchar	**argv;
X
X{	int	i;
X	char	**copy;
X
X	copy = (char **) malloc((argc + 1) * sizeof(char *));
X	for (i = 0; i < argc; i++)
X	   strcpy(copy[i] = (char *) malloc(strlen(argv[i]) + 1), argv[i]);
X	copy[i] = (char *) 0;
X	return(copy);
X}
X
X#define		SIZE_INCREMENT		8
X
X/************************************************************************/
XEXPORT	char	**tokenize(line, argc)
X
Xchar	*line;
Xint	*argc;
X
X{	char	match, **argv, *buf, *p;
X	int	limit;
X
X	buf = (char *) malloc(strlen(line) + 1);
X	*argc = 0;
X	argv = (char **) malloc((limit = SIZE_INCREMENT) * sizeof(char *));
X	while (*line) {
X	   while (isspace(*line))
X	      line++;
X	   switch (*line) {
X	      case '"'  :
X	      case '\'' : match = *line++; /* remove the quote mark */
X	      		  for (p = buf; *line && (*line != match); )
X	      		     *p++ = *line++;
X	      		  if (*line)
X	      		     line++; /* wipe out quote mark */
X	      		  break;
X	      default   : for (p = buf; *line && !isspace(*line) && (*line != '"') && (*line != '\''); )
X	      		     *p++ = *line++;
X	      		  break;
X	      }
X	   *p = '\0';
X	   if (*buf) {
X	      argv[(*argc)++] = strsave(buf);
X	      if (*argc == limit)
X	         argv = (char **) realloc(argv, (limit += SIZE_INCREMENT) * sizeof(char *));
X	      }
X	   }
X	free(buf);
X	argv[*argc] = (char *) 0;
X	return(argv);
X}
X
X#define		P_POS		5
X#define		L_POS		8
X#define		D_POS		9
X
X#define		PATH		"/dev/ptyp0"
X#define		LETTERS		"pqr"
X#define		DIGITS		"0123456789abcdef"
X
XPRIVATE	char	path[12];
X
X/************************************************************************/
XEXPORT	char	*open_psuedo_tty(master, m_mode, slave, s_mode)
X
XFILE	**master;
Xchar	*m_mode;
XFILE	**slave;
Xchar	*s_mode;
X
X{	char	*s, *t;
X
X	strcpy(path, PATH);
X	for (s = LETTERS; *s && *master == NULL; s++) {
X	   path[L_POS] = *s;
X	   for (t = DIGITS; *t && *master == NULL; t++) {
X	      path[D_POS] = *t;
X	      *master = fopen(path, m_mode);
X	      }
X	   }
X	if (*master != NULL) {
X	   path[P_POS] = 't';
X	   *slave = fopen(path, s_mode);
X	   path[P_POS] = 'p';
X	   }
X	return(path);
X}
END_OF_FILE
if test 4723 -ne `wc -c <'misc.c'`; then
    echo shar: \"'misc.c'\" unpacked with wrong size!
fi
# end of 'misc.c'
fi
if test -f 'regexp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'regexp.c'\"
else
echo shar: Extracting \"'regexp.c'\" \(3246 characters\)
sed "s/^X//" >'regexp.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	"contool.h"
X
XPRIVATE	regexp_error();
X
X#define		INIT			register char *expbuf = ep, *sp = instring;
X#define		GETC()			(*sp++)
X#define		PEEKC()			(*sp)
X#define		UNGETC(c)		(--sp)
X#define		RETURN(p)		{bcopy(expbuf, sp = (char *) malloc(p - expbuf), p - expbuf); return(sp);}
X#define		ERROR(val)		{regexp_error(val, instring); return(NULL);}
X
X#include	<regexp.h>
X
XPRIVATE	char	error_message[512];
X
X/************************************************************************/
XEXPORT	int	match_exp(exp, circ, str)
X
Xchar	*exp;
Xint	circ;
Xchar	*str;
X
X{
X	circf = circ;
X	return(step(str, exp));
X}
X
X/************************************************************************/
XPRIVATE	regexp_error(val, string)
X
Xint	val;
Xchar	*string;
X
X{	char	*msg;
X
X	switch (val) {
X	   case 11 : msg = "range endpoint too large";
X	   case 16 : msg = "bad number";
X	   case 25 : msg = "\"\\digit\" out of range";
X	   case 36 : msg = "illegal or missing delimiter";
X	   case 41 : msg = "no remembered search string";
X	   case 42 : msg = "\\(\\) imbalance";
X	   case 43 : msg = "too many \\(";
X	   case 44 : msg = "more than 2 numbers given in \\{\\}";
X	   case 45 : msg = "} expected after \\";
X	   case 46 : msg = "first number exceeds second in \\{\\}";
X	   case 49 : msg = "[] imbalance";
X	   case 50 : msg = "regular expression overflow";
X	   default : msg = "regular expression error";
X	   }
X	sprintf(error_message, "%s in\n\t%s", msg, string);
X}
X
X/************************************************************************/
XEXPORT	char	*compile_exp(filter, start, end)
X
Xf_ptr	filter;
Xchar	*start;
Xchar	*end;
X
X{	char	rbuf[1024], *sre, *ere;
X	int	sc, ec;
X
X	sre = ere = NULL;
X	if ((sre = compile(start, rbuf, rbuf+1024, '\0')) == NULL)
X	   return(error_message);
X	sc = circf;
X	if (end) {
X	   if ((ere = compile(end, rbuf, rbuf+1024, '\0')) == NULL) {
X	      free(sre);
X	      return(error_message);
X	      }
X	   ec = circf;
X	   }
X	if (filter) {
X	   filter->start = start;
X	   filter->end = end;
X	   filter->start_re = sre;
X	   filter->end_re = ere;
X	   filter->scircf = sc;
X	   filter->ecircf = ec;
X	   }
X	else {
X	   free(sre);
X	   if (ere)
X	      free(ere);
X	   }
X	return(NULL);
X}
END_OF_FILE
if test 3246 -ne `wc -c <'regexp.c'`; then
    echo shar: \"'regexp.c'\" unpacked with wrong size!
fi
# end of 'regexp.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
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