[comp.sources.sun] v02i023: Contool 3.0, Part04/06

mcgrew@aramis.rutgers.edu (Charles Mcgrew) (09/26/90)

Submitted-by: chuck@trantor.harris-atd.com (Chuck Musciano)
Posting-number: Volume 2, Issue 23
Archive-name: contool3.0/part04


#! /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 4 (of 6)."
# Contents:  contool.c
# Wrapped by chuck@melmac on Fri Aug 17 10:00:53 1990
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'\" \(19504 characters\)
sed "s/^X//" >'contool.c' <<'END_OF_FILE'
X/************************************************************************/
X/*	Copyright 1988-1990 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/************************************************************************/
X/*									*/
X/*	contool.c	main contool driver				*/
X/*									*/
X/************************************************************************/
X
X#include	<stdio.h>
X#include	<fcntl.h>
X#include	<strings.h>
X#include	<sys/ioctl.h>
X#include	<sys/file.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<sys/param.h>
X
X#include	<X11/Xlib.h>
X
X#include	<xview/xview.h>
X#include	<xview/icon.h>
X#include	<xview/panel.h>
X#include	<xview/textsw.h>
X#include	<xview/xv_xrect.h>
X
X#include	"manifest.h"
X#include	"contool.h"
X#include	"contool_ui.h"
X
X#define		update_value(old, new)		((old) = ((new) > (old))? (new) : (old))
X
X#define		INPUT_BUFFER_SIZE		4096
X
XEXPORT	Attr_attribute	INSTANCE;
X
XEXPORT	contool_base_objects	*contool_base;
XEXPORT	char			*filter_file;
X
XPUBLIC	Server_image		load_icon();
X
XPRIVATE	short	good_bits[]  = {
X#include	"icons/default_good.icon"
X			       };
XPRIVATE	short	bad_bits[]   = {
X#include	"icons/default_bad.icon"
X			       };
XPRIVATE	short	flash_bits[] = {
X#include	"icons/default_flash.icon"
X			       };
XPRIVATE	short	mask_bits[] = {
X#include	"icons/mask.icon"
X			       };
X
XPRIVATE	char			*ct_usage = "usage: contool [-c <file>] [-l] [-L <file>]\n";
X
XPRIVATE	Server_image		default_good_icon, good = NULL;
XPRIVATE	Server_image		default_bad_icon, bad = NULL;
XPRIVATE	Server_image		default_flash_icon, flash = NULL;
XPRIVATE	Server_image		icon_mask;
X
XPRIVATE	int			bad_is_up;
XPRIVATE	int			beep_count;
XPRIVATE	int			blinking = FALSE;
XPRIVATE	FILE			*command = NULL;
XPRIVATE	Filter			*curr_filter = NULL;
XPRIVATE	int			event_in_progress = FALSE;
XPRIVATE	int			explicit_filters = FALSE;
XPRIVATE	int			masking_works;
XPRIVATE	FILE			*master = NULL;
XPRIVATE	int			old_time = 0;
XPRIVATE	char			*program;
XPRIVATE	FILE			*slave = NULL;
X
XPRIVATE	struct	itimerval	timer = {{0, 500000}, {0, 500000}};
X
X/************************************************************************/
X/*	Manage piping console output to a command 			*/
X/************************************************************************/
X
X/************************************************************************/
XPRIVATE	start_command(cmd)
X
Xchar	*cmd;
X
X{
X	if (command)
X	   pclose(command);
X	if ((command = popen(cmd, "w")) == NULL)
X	   internal_error("could not execute \"%s\"", cmd);
X}
X
X/************************************************************************/
XPRIVATE	continue_command(buf)
X
Xchar	*buf;
X
X{
X	if (command)
X	   fprintf(command, buf);
X}
X
X/************************************************************************/
XPRIVATE	end_command()
X
X{
X	if (command)
X	   pclose(command);
X}
X
X/************************************************************************/
X/*	Some basic console utility routines	 			*/
X/************************************************************************/
X
X/************************************************************************/
XEXPORT	acquire_console()
X
X{
X	if (ioctl(fileno(slave), TIOCCONS, NULL) == -1)
X	   abend("%s: could not attach to /dev/console", program);
X}
X
X/************************************************************************/
XEXPORT	stop_blinking()
X
X{	Icon	icon;
X
X	notify_set_itimer_func(contool_base->base, NULL, ITIMER_REAL, NULL, NULL);
X	icon = (Icon) xv_get(contool_base->base, FRAME_ICON);
X	xv_set(icon, ICON_IMAGE, good, NULL);
X	xv_set(contool_base->base, FRAME_ICON, icon, 0);
X	blinking = FALSE;
X}
X
X/************************************************************************/
XEXPORT	filters_changed()
X
X{
X	curr_filter = NULL;
X	xv_set(contool_base->base, FRAME_LEFT_FOOTER, "", NULL);
X	end_command();
X}
X
X/************************************************************************/
X/*	Various small features						*/
X/************************************************************************/
X
X/************************************************************************/
XEXPORT	Menu_item	print_messages(item, op)
X
XMenu_item	item;
XMenu_generate	op;
X
X{	int	size;
X	char	*buf;
X	FILE	*cmd;
X
X	if (op == MENU_NOTIFY) {
X	   if (is_empty(defaults.print_filter))
X	      error("You must specify a printer command in the Properties dialog");
X	   else if ((cmd = popen(defaults.print_filter, "w")) == NULL)
X	      error("Could not execute %s", defaults.print_filter);
X	   else {
X	      xv_set(contool_base->base, FRAME_BUSY, TRUE, NULL);
X	      size = (int) xv_get(contool_base->display, TEXTSW_LENGTH);
X	      buf = (char *) malloc(size);
X	      xv_get(contool_base->display, TEXTSW_CONTENTS, 0, buf, size);
X	      if (fwrite(buf, 1, size, cmd) != size)
X	         error("Could not write console contents to printer");
X	      pclose(cmd);
X	      xv_set(contool_base->base, FRAME_BUSY, FALSE, NULL);
X	      }
X	   }
X	return item;
X}
X
X/************************************************************************/
XEXPORT	Menu_item	become_console(item, op)
X
XMenu_item	item;
XMenu_generate	op;
X
X{
X	if (op == MENU_NOTIFY)
X	   acquire_console();
X	return item;
X}
X
X/************************************************************************/
XEXPORT	Menu_item	clear_messages(item, op)
X
XMenu_item	item;
XMenu_generate	op;
X
X{
X	if (op == MENU_NOTIFY) {
X	   textsw_reset(contool_base->display, 0, 0);
X	   old_time = 0;
X	   }
X	return item;
X}
X
X/************************************************************************/
XEXPORT	Menu_item	reset_filter(item, op)
X
XMenu_item	item;
XMenu_generate	op;
X
X{
X	if (op == MENU_NOTIFY)
X	   filters_changed();
X	return item;
X}
X
X/************************************************************************/
XPRIVATE	change_icon(image, use_mask)
X
XServer_image	image;
Xint		use_mask;
X
X{	Icon	icon;
X
X	icon = (Icon) xv_get(contool_base->base, FRAME_ICON);
X	xv_set(icon,
X		  ICON_IMAGE, image,
X		  XV_WIDTH, (int) xv_get(image, XV_WIDTH),
X		  XV_HEIGHT, (int) xv_get(image, XV_HEIGHT),
X	       NULL);
X	if (masking_works && use_mask)
X	   xv_set(icon, ICON_MASK_IMAGE, icon_mask, NULL);
X	xv_set(contool_base->base, FRAME_ICON, icon, NULL);
X}
X
X/************************************************************************/
XEXPORT	update_icons()
X
X{	char	msg[1024];
X
X	if (good && good != default_good_icon)
X	   xv_destroy(good);
X	if (bad && bad != default_bad_icon)
X	   xv_destroy(bad);
X	if (flash && flash != default_flash_icon)
X	   xv_destroy(flash);
X
X	good  = (defaults.good_icon  == NULL)? default_good_icon  : load_icon(defaults.good_icon, msg);
X	bad   = (defaults.bad_icon   == NULL)? default_bad_icon   : load_icon(defaults.bad_icon, msg);
X	flash = (defaults.flash_icon == NULL)? default_flash_icon : load_icon(defaults.flash_icon, msg);
X
X	if (!blinking)
X	   change_icon(good, good == default_good_icon);
X}
X
X/************************************************************************/
X/*	Now, filter  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[1024];
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[1024];
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{	struct	stat	sb;
X	static	int	load_time = 0;
X
X	if (access(filter_file, R_OK) == -1) {
X	   if (explicit_filters && load_time == 0) {
X	      internal_error("filter file %s cannot be accessed", filter_file);
X	      load_time = 1;
X	      }
X	   }
X	else if (stat(filter_file, &sb) == 0 && sb.st_mtime > load_time)
X	   if (lex_init(filter_file)) {
X	      yyparse();
X	      if (!parse_errors_occured) {
X	         free_list(filters);
X	         free(parsed_defaults);
X	         filters = parsed_filters;
X	         internal_message("*** filters loaded from %s\n", filter_file);
X	         load_time = sb.st_mtime;
X	         }
X	      }
X	   else {
X	      internal_error("error accessing configuration file %s", filter_file);
X	      load_time = 1;
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(contool_base->base);
X	   beep_count--;
X	   }
X	if (blinking) {
X	   if (bad_is_up)
X	      change_icon(flash, flash == default_flash_icon);
X	   else
X	      change_icon(bad, bad == default_bad_icon);
X	   bad_is_up = !bad_is_up;
X	   }
X	if (beep_count == 0 && !blinking)
X	   notify_set_itimer_func(contool_base->base, 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{
X	event_in_progress = TRUE;
X	if (event_action(event) == ACTION_OPEN && blinking) {
X	   notify_set_itimer_func(contool_base->base, blink_proc, ITIMER_REAL, NULL, NULL);
X	   change_icon(good, good = default_good_icon);
X	   blinking = FALSE;
X	   }
X	event_in_progress = FALSE;
X	return(notify_next_event_func(frame, event, arg, type));
X}
X
X/************************************************************************/
XPRIVATE	Notify_value	destroy_proc(frame, status)
X
XFrame	frame;
XDestroy_status	status;
X
X{
X	if (status == DESTROY_CHECKING) {
X	   textsw_reset(contool_base->display, 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	do_insertion(buf, len)
X
Xchar	*buf;
Xint	len;
X
X{	int	first, last, sw_len;
X	char	*temp;
X
X	while ((int) xv_get(contool_base->display, TEXTSW_LENGTH) + len > defaults.max_size) {
X	   first = 1;
X	   last = TEXTSW_INFINITY;
X	   if (textsw_find_bytes(contool_base->display, &first, &last, "\n<<<", 4, 0) == -1)
X	      if (textsw_find_bytes(contool_base->display, &first, &last, "\n", 1, 0) == -1)
X	         first = defaults.delete_amount;
X	   textsw_erase(contool_base->display, 0, first + 1);
X	   sw_len = (int) xv_get(contool_base->display, TEXTSW_LENGTH);
X	   temp = (char *) malloc((unsigned) sw_len);
X	   xv_get(contool_base->display, TEXTSW_CONTENTS, 0, temp, sw_len);
X	   textsw_reset(contool_base->display, 0, 0);
X	   textsw_insert(contool_base->display, temp, sw_len);
X	   free(temp);
X	   }
X	xv_set(contool_base->display, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
X	textsw_insert(contool_base->display, 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 >= defaults.stamp_resolution) {
X	      xv_set(contool_base->display, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
X	      pos = (int) xv_get(contool_base->display, TEXTSW_LENGTH);
X	      if (pos != 0) {
X	         xv_get(contool_base->display, 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, buf[1024];
X	Filter	*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 (!defaults.log_after)
X	         write_log(t);
X	      if (curr_filter == NULL) {
X	         load_filters();
X	         for (f = filters; f; f = f->next)
X	            if (f->start_re && match_exp(f->start_re, f->start_circf, t)) {
X	               if (f->save) {
X	                  update_value(do_blink, f->flash);
X	                  update_value(beep_count, f->beep);
X	                  update_value(do_open, f->open);
X	                  if (f->stamp)
X	                     time_stamp();
X	                  do_insertion(t, strlen(t));
X	                  if (f->command) {
X	                     start_command(f->command);
X	                     continue_command(t);
X	                     if (f->stop == NULL)
X	                        end_command();
X	                     }
X	                  if (defaults.log_after)
X			     write_log(t);
X	                  }
X	               if (f->stop) {
X	                  curr_filter = f;
X	                  sprintf(buf, "Filtering \"%s\"...", f->start);
X	                  xv_set(contool_base->base, FRAME_LEFT_FOOTER, buf, NULL);
X	                  }
X	               break;
X	               }
X	         if (f == NULL) {
X	            if (defaults.stamp)
X	               time_stamp();
X	            if (defaults.command) {
X	               start_command(defaults.command);
X	               continue_command(t);
X	               end_command();
X	               }
X		    if (defaults.log_after)
X	               write_log(t);
X	            do_insertion(t, strlen(t));
X	            update_value(do_blink, defaults.flash);
X	            update_value(do_open, defaults.open);
X	            update_value(beep_count, defaults.beep);
X	            }
X	         }
X	      else {
X	         if (curr_filter->save) {
X	            if (curr_filter->stamp)
X	               time_stamp();
X		    if (defaults.log_after)
X	               write_log(t);
X		    do_insertion(t, strlen(t));
X		    if (curr_filter->command)
X		       continue_command(t);
X	            }
X	         if (match_exp(curr_filter->stop_re, curr_filter->stop_circf, t)) {
X	            xv_set(contool_base->base, FRAME_LEFT_FOOTER, "", NULL);
X	            if (curr_filter->command)
X	               end_command();
X	            curr_filter = NULL;
X	            }
X	         }
X	      }
X	   }
X	xv_set(contool_base->display, TEXTSW_UPDATE_SCROLLBAR, 0);
X	if (do_open)
X	   xv_set(contool_base->base, FRAME_CLOSED, FALSE, 0);
X	if (do_blink)
X	   if (xv_get(contool_base->base, FRAME_CLOSED) && !blinking) {
X	      change_icon(bad, bad == default_bad_icon);
X	      xv_set(contool_base->base, WIN_SHOW, TRUE, 0);
X	      blinking = TRUE;
X	      bad_is_up = TRUE;
X	      notify_set_itimer_func(contool_base->base, blink_proc, ITIMER_REAL, &timer, NULL);
X	      }
X	if (beep_count > 0 || blinking)
X	   notify_set_itimer_func(contool_base->base, 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, path[1024], *log_file = NULL;
X	int	log = FALSE;
X
X	sprintf(path, "%s/.contool", getenv("HOME"));
X	filter_file = strsave(path);
X
X	while ((c = getopt(argc, argv, "c:lL:?", &s)) != EOF)
X	   switch (c) {
X	      case 'c' : filter_file = expand_tilde(s);
X	      		 explicit_filters = TRUE;
X	      		 break;
X	      case 'l' : log = TRUE;
X	      		 break;
X	      case 'L' : log_file = expand_tilde(s);
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	if (lex_init(filter_file)) {
X	   yyparse();
X	   if (parsed_defaults)
X	      defaults = *parsed_defaults;
X	   if (log_file)
X	      defaults.log_file = log_file;
X	   if (log)
X	      enable_logging();
X	   }
X	else if (explicit_filters)
X	   error("Could not read configuration file %s", filter_file);
X}
X
X/************************************************************************/
Xmain(argc, argv)
X
Xint	argc;
Xchar	**argv;
X
X{	char	buf[1024], *path, *open_psuedo_tty();
X	int	i;
X	XWindowAttributes	attr;
X
X	program = strsave(argv[0]);
X
X	path = open_psuedo_tty(&master, "r", &slave, "w");
X	if (master == NULL)
X	   abend("%s: couldn't open any psuedo-tty", program);
X	if (slave == NULL)
X	   abend("%s: couldn't open slave side of %s", program, path);
X
X	i = fcntl(fileno(master), F_GETFL, 0);
X	i |= FNDELAY;
X	if (fcntl(fileno(master), F_SETFL, i) == -1)
X	   abend("%s: could not force %s to non-blocking i/o", program);
X
X	acquire_console(path);
X
X	xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
X	INSTANCE = xv_unique_key();
X
X	contool_base = contool_base_objects_initialize(NULL, NULL);
X	default_good_icon  = (Server_image) xv_create(NULL, SERVER_IMAGE,
X							 XV_WIDTH, 64,
X							 XV_HEIGHT, 64,
X							 SERVER_IMAGE_BITS, good_bits,
X						      NULL);
X	default_bad_icon   = (Server_image) xv_create(NULL, SERVER_IMAGE,
X							 XV_WIDTH, 64,
X							 XV_HEIGHT, 64,
X							 SERVER_IMAGE_BITS, bad_bits,
X						      NULL);
X	default_flash_icon = (Server_image) xv_create(NULL, SERVER_IMAGE,
X							 XV_WIDTH, 64,
X							 XV_HEIGHT, 64,
X							 SERVER_IMAGE_BITS, flash_bits,
X						      NULL);
X	icon_mask          = (Server_image) xv_create(NULL, SERVER_IMAGE,
X							 XV_WIDTH, 64,
X							 XV_HEIGHT, 64,
X							 SERVER_IMAGE_BITS, mask_bits,
X						      NULL);
X	disable_logging(contool_base);
X
X	XGetWindowAttributes(xv_get(contool_base->base, XV_DISPLAY), xv_get(xv_get(contool_base->base, XV_ROOT), XV_XID), &attr);
X	masking_works = (attr.depth > 1);
X
X	parse_options(&argc, argv);
X	load_filters();
X	update_icons();
X
X	notify_set_input_func(contool_base->base, input_func, fileno(master));
X	notify_interpose_destroy_func(contool_base->base, destroy_proc);
X	notify_interpose_event_func(contool_base->base, close_proc, NOTIFY_SAFE);
X
X	xv_main_loop(contool_base->base);
X	exit(0);
X}
END_OF_FILE
if test 19504 -ne `wc -c <'contool.c'`; then
    echo shar: \"'contool.c'\" unpacked with wrong size!
fi
# end of 'contool.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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}

I'm glad you asked, son.  Being popular
	is the most important thing in the world.	-- Homer Simpson