#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Goban.c
#	Goban.doc
#	Goban.h
#	GobanP.h
#	Imakefile
#	Makefile.hand
#	Makefile.sun
#	README
#	XIgc.ad
#	blackstone.bm
#	board.c
#	filter.c
#	filter.h
#	igscomm.c
#	igscomm.h
#	patchlevel.h
#	pipes.c
#	sample_xigcrc
#	shared.h
#	sound.note
#	stipple.bm
#	stipple2.bm
#	stonemask.bm
#	whitestone.bm
#	xigc.c
#	xigc.man
# This archive created: Wed Jan  6 23:02:31 1993
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Goban.c'
then
	echo shar: "will not over-write existing file 'Goban.c'"
else
cat << \SHAR_EOF > 'Goban.c'
/* Goban.c
 * S.Coffin     USWAT   7/92
 *
 * adapted from the below
 */

/****************************************************************************************************************
 *
 *  Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behaviour
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    dumesnil@etca.fr   or to:
 *       
 *       Antoine de Maricourt
 *       ETCA CREA-SP
 *       16 bis, avenue Prieur de la Cote d'Or
 *       94114 Arcueil Cedex
 *       France
 */

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>

#include "GobanP.h"

#include "whitestone.bm"
#include "blackstone.bm"
#include "stonemask.bm"
#include "stipple.bm"
#include <stdio.h>

#define offset(field) XtOffset (GobanWidget, goban.field)
static Position lastx = (-1), lasty;
static GbPointState lastcolor;
extern char stippleflag;

static XtResource resources[] = {
  { XtNautoRedisplay,
    XtCAutoRedisplay,
    XtRBoolean,
    sizeof (Boolean),
    offset (auto_redisplay),
    XtRImmediate,
    (caddr_t) TRUE },
  { XtNviewBottom,
    XtCPosition,
    XtRPosition,
    sizeof (Position),
    offset (bottom),
    XtRImmediate,
    (caddr_t) 1 },
  { XtNcursor,
    XtCCursor,
    XtRInt,
    sizeof (int),
    offset (cursor),
    XtRImmediate,
    (caddr_t) GbCBlackStone },
  { XtNfont,
    XtCFont,
    XtRFontStruct,
    sizeof (XFontStruct *),
    offset (font),
    XtRString,
    "fixed" },
  { XtNforeground,
    XtCForeground,
    XtRPixel,
    sizeof (Pixel),
    offset (foreground),
    XtRString,
    XtDefaultForeground },
  { XtNgameSize,
    XtCSize,
    XtRDimension,
    sizeof (Dimension),
    offset (game_size),
    XtRImmediate,
    (caddr_t) 19 },
  { XtNviewLeft,
    XtCPosition,
    XtRPosition,
    sizeof (Position),
    offset (left),
    XtRImmediate,
    (caddr_t) 1 },
  { XtNdisplayCoordinates,
    XtCDisplayCoordinates,
    XtRBoolean,
    sizeof (Boolean),
    offset (display_coordinates),
    XtRImmediate,
    (caddr_t) TRUE },
  { XtNpointSize,
    XtCSize,
    XtRDimension,
    sizeof (Dimension),
    offset (point_size),
    XtRImmediate,
    (caddr_t) 26 },
  { XtNstipple,
    XtCSize,
    XtRBoolean,
    sizeof (Boolean),
    offset (stipple),
    XtRImmediate,
    (caddr_t) FALSE },
  { XtNviewRight,
    XtCPosition,
    XtRPosition,
    sizeof (Position),
    offset (right),
    XtRImmediate,
    (caddr_t) 19 },
  { XtNviewTop,
    XtCPosition,
    XtRPosition,
    sizeof (Position), 
    offset (top),
    XtRImmediate,
    (caddr_t) 19 },
  { XtNwhiteStoneForeground,
    XtCForeground,
    XtRPixel,
    sizeof (Pixel),
    offset (white_fg),
    XtRString,
    "black" },
  { XtNwhiteStoneBackground,
    XtCBackground,
    XtRPixel,
    sizeof (Pixel),
    offset (white_bg),
    XtRString,
    "white" },
  { XtNwhiteStoneBorder,
    XtCBorderColor,
    XtRPixel,
    sizeof (Pixel),
    offset (white_bd),
    XtRString,
    "black" },
  { XtNblackStoneForeground,
    XtCForeground,
    XtRPixel,
    sizeof (Pixel),
    offset (black_fg),
    XtRString,
    "white" },
  { XtNblackStoneBackground,
    XtCBackground,
    XtRPixel,
    sizeof (Pixel),
    offset (black_bg),
    XtRString,
    "black" },
  { XtNblackStoneBorder,
    XtCBorderColor,
    XtRPixel,
    sizeof (Pixel),
    offset (black_bd),
    XtRString,
    "black" },
};

static void    ClassInitialize ();
static void    Initialize      ();
static void    Redisplay       ();
static void    Realize         ();
static void    Destroy         ();
static void    Resize          ();
static void    DrawPoint       ();
static Boolean SetValues       ();

GobanClassRec gobanClassRec = {
  { /* core fields */
    /* superclass		*/	(WidgetClass) &widgetClassRec,
    /* class_name		*/	"Goban",
    /* widget_size		*/	sizeof (GobanRec),
    /* class_initialize		*/	ClassInitialize,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions			*/	NULL,
    /* num_actions		*/	0,
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber (resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	Destroy,
    /* resize			*/	Resize,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	NULL,
    /* query_geometry		*/	XtInheritQueryGeometry,
    /* display_accelerator	*/	XtInheritDisplayAccelerator,
    /* extension		*/	NULL
  }
};

WidgetClass gobanWidgetClass = (WidgetClass) &gobanClassRec;
 
/****************************************************************************************************************
 */

void GbRedisplayBoard (w)
Widget w;
{
  GobanWidget gw      = (GobanWidget) w;
  Dimension   width   = w->core.width;
  Dimension   height  = w->core.height;

  if (XtIsRealized (w))
    XCopyArea (XtDisplay (w), gw->goban.picture, XtWindow (w), gw->goban.copy_gc, 0, 0, width, height, 0, 0);
}

/****************************************************************************************************************
 */

void GbClearBoard (w)
Widget w;
{
  GobanWidget gw        = (GobanWidget) w;
  Boolean     redisplay = gw->goban.auto_redisplay;
  Position    x;
  Position    y;

  gw->goban.auto_redisplay = FALSE;

  for (x = 1; x <= (Position)gw->goban.game_size; x++)
    for (y = 1; y <= (Position)gw->goban.game_size; y++)
      GbSetPoint( w, x, y, GbEmptyPoint, TRUE );

  gw->goban.auto_redisplay = redisplay;

  if( redisplay == TRUE ) GbRedisplayBoard( w );
}

/****************************************************************************************************************
 */

void GbClearMarks (w)
Widget w;
{
  GobanWidget gw        = (GobanWidget) w;
  Boolean     redisplay = gw->goban.auto_redisplay;
  Position    x;
  Position    y;

  gw->goban.auto_redisplay = FALSE;

  for (x = 1; x <= (Position)gw->goban.game_size; x++)
    for (y = 1; y <= (Position)gw->goban.game_size; y++) {

      gw->goban.points[x][y].mark1 = 0;
      gw->goban.points[x][y].mark2 = 0;
      gw->goban.points[x][y].num   = 0;
    
      if (x >= gw->goban.left && y >= gw->goban.bottom && x <= gw->goban.right && y <= gw->goban.top)
	if (gw->goban.points[x][y].free == 1)
	  DrawPoint (w, x, y, GbEmptyPoint, FALSE);
	else
	  if (gw->goban.points[x][y].black == 1)
	    DrawPoint (w, x, y, GbBlackStone, FALSE);
	  else
	    DrawPoint (w, x, y, GbWhiteStone, FALSE);
    }

  gw->goban.auto_redisplay = redisplay;

  if (redisplay == TRUE)
    GbRedisplayBoard (w);
}

/****************************************************************************************************************
 */

/* ARGSUSED */

void GbSetPoint( w, x, y, color, flag )
Widget       w;
Position     x;
Position     y;
GbPointState color;
unsigned char flag;
{
  GobanWidget gw = (GobanWidget) w;

  if (x >= 1 && y >= 1 && x <= (Position)gw->goban.game_size &&
		y <= (Position)gw->goban.game_size) {
    switch (color) {

    case GbBlackStone :
      gw->goban.points[x][y].free  = 0;
      gw->goban.points[x][y].black = 1;
      break;

    case GbWhiteStone :
      gw->goban.points[x][y].free  = 0;
      gw->goban.points[x][y].black = 0;
      break;

    case GbEmptyPoint :
      gw->goban.points[x][y].free  = 1;
      break;
    }
    
    gw->goban.points[x][y].num   = 0;
    gw->goban.points[x][y].mark1 = 0;
    gw->goban.points[x][y].mark2 = 0;

    if( x >= gw->goban.left && y >= gw->goban.bottom &&
	x <= gw->goban.right && y <= gw->goban.top ) {
      if( lastx >= 0 ) DrawPoint( w, lastx, lasty, lastcolor, FALSE );
      DrawPoint( w, x, y, color, flag );
      lastx = x;
      lasty = y;
      lastcolor = color;
    }
  }
}

/****************************************************************************************************************
 */

/* ARGSUSED */

Boolean GbGetPositionFromStone (w, x, y)
GobanWidget   w;
Position     *x;
Position     *y;
{
  if (*x >= w->goban.left && *y >= w->goban.bottom && *x <= w->goban.right && *y <= w->goban.top) {
	
    *x = (Position)((w->goban.x_offset + w->goban.point_size * *x) * (Position)2 + w->goban.point_size) / (Position)2;
    *y = (Position)((w->goban.y_offset - w->goban.point_size * *y) * (Position)2 + w->goban.point_size) / (Position)2;
    
    return TRUE;
  }
  
  else 
    return FALSE;
}

/****************************************************************************************************************
 */

/* ARGSUSED */

Boolean GbGetStoneFromPosition (w, x, y)
Widget     w;
Position  *x;
Position  *y;
{
  GobanWidget gw         = (GobanWidget) w;
  Dimension   point_size = gw->goban.point_size;
  Position    xmin       = gw->goban.x_offset + point_size * gw->goban.left + 1;
  Position    ymin       = gw->goban.y_offset - point_size * gw->goban.top  + 1;
  Position    xmax       = gw->goban.x_offset + point_size * (gw->goban.right  + 1) - 1;
  Position    ymax       = gw->goban.y_offset - point_size * (gw->goban.bottom - 1) - 1;

  if (*x > xmin && *x < xmax && *y > ymin && *y < ymax) {

    *x = (Position)(*x - gw->goban.x_offset - 1) / (Position)point_size;
    *y = (Position)(gw->goban.y_offset - *y + point_size + 1) / (Position)point_size;

    return TRUE;
  }

  return FALSE;
}

/****************************************************************************************************************
 */

void GbSetNum (w, x, y, num)
Widget      w;
Position    x;
Position    y;
int         num;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);
  GC           draw_gc;
  GC           undraw_gc;
  XCharStruct  extent;
  XExposeEvent event;
  int          ascent;
  int          descent;
  int          direction;
  int          X;
  int          Y;
  char         s[3];
  int          len = 0;

  if (num >= 0 && num <= 999 && (int)x >= 1 && (int)y >= 1  && (int)x <= (int)gw->goban.game_size && (int)y <= (int)gw->goban.game_size) {
	
    gw->goban.points[x][y].num   = num;
    gw->goban.points[x][y].mark1 = 0;
    gw->goban.points[x][y].mark2 = 0;
    
    if (x >= gw->goban.left && y >= gw->goban.bottom && x <= gw->goban.right && y <= gw->goban.top) {
      
      if (gw->goban.points[x][y].free == 0) {
	
	if (num == 0) {
	  if (gw->goban.points[x][y].black == 1)
	    DrawPoint (w, x, y, GbBlackStone, FALSE);
	  else
	    DrawPoint (w, x, y, GbWhiteStone, FALSE);
	}
	
	else {
	  if (gw->goban.points[x][y].black == 1) {
	    draw_gc   = gw->goban.black_fg_gc;
	    undraw_gc = gw->goban.black_bg_gc;
	  } else {
	    draw_gc   = gw->goban.white_fg_gc;
	    undraw_gc = gw->goban.white_bg_gc;
	  }
	  
	  X = (gw->goban.x_offset + gw->goban.point_size * x) * 2 + gw->goban.point_size;
	  Y = (gw->goban.y_offset - gw->goban.point_size * y) * 2 + gw->goban.point_size;
	  
	  if (num > 99)
	    s[len++] = '0' + (num % 1000) / 100;
	  if (num > 9)
	    s[len++] = '0' + (num % 100) / 10;
	  s[len++] = '0' + num % 10;
	  
	  XQueryTextExtents (display, XGContextFromGC (draw_gc),
			     s, len, &direction, &ascent, &descent, &extent);
	  
	  if (extent.width + extent.descent + extent.ascent < (int)gw->goban.point_size - 1) {
	    XFillArc (display, gw->goban.picture, undraw_gc, 
		      (int) (X - gw->goban.point_size) / 2 + 2, (int) (Y - gw->goban.point_size) / 2 + 2, 
		      (unsigned int) gw->goban.point_size - 4, (unsigned int) gw->goban.point_size - 4, 
		      0, 360 * 64);
	    XDrawString (display, gw->goban.picture, draw_gc,
			 (X - extent.width) / 2 - extent.lbearing + 1, 
			 (Y + extent.ascent - extent.descent) / 2 + 1, s, len);
	  }
	
	  if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
	    event.x      = (int)(X - gw->goban.point_size) / 2;
	    event.y      = (int)(Y - gw->goban.point_size) / 2;
	    event.width  = gw->goban.point_size;
	    event.height = gw->goban.point_size;
	    
	    Redisplay (w, &event, (Region) NULL);
	  }
	}
      }
    }
  }
}

/****************************************************************************************************************
 */

void GbSetMark( w, x, y, c1, c2 )
	Widget        w;
	Position      x;
	Position      y;
	unsigned char c1;
	unsigned char c2;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);
  int          len     = 0;
  XCharStruct  extent;
  XExposeEvent event;
  int          ascent;
  int          descent;
  int          direction;
  int          X;
  int          Y;
  int          radius;
  char         s[2];
  XSegment     segment[4];
  GC           mark_gc;
  GC           erase_gc;

  if( (int)x >= 1 &&
      (int)y >= 1 &&
      (int)x <= (int)gw->goban.game_size &&
      (int)y <= (int)gw->goban.game_size) {
   
    if( c1 != 0 || c2 != 0 ) GbSetMark( w, x, y, 0, 0 );
     
    gw->goban.points[x][y].mark1 = c1;
    gw->goban.points[x][y].mark2 = c2;
    gw->goban.points[x][y].num   = 0;

    if( x >= gw->goban.left && y >= gw->goban.bottom &&
	x <= gw->goban.right && y <= gw->goban.top) {
      
      if (c1 == 0 && c2 == 0) {
	if (gw->goban.points[x][y].free == 0)
	  if (gw->goban.points[x][y].black == 1)
	    DrawPoint( w, x, y, GbBlackStone, FALSE );
	  else
	    DrawPoint( w, x, y, GbWhiteStone, FALSE );
	else
	  DrawPoint( w, x, y, GbEmptyPoint, FALSE );
      }
      
      else {
	X = (gw->goban.x_offset + gw->goban.point_size * x) * 2 +
			gw->goban.point_size;
	Y = (gw->goban.y_offset - gw->goban.point_size * y) * 2 +
			gw->goban.point_size;
	  	    
	if (gw->goban.points[x][y].free == 0)
	  if (gw->goban.points[x][y].black == 1) {
	    mark_gc  = gw->goban.black_fg_gc;
	    erase_gc = gw->goban.black_bg_gc;
	  }
	  else {
	    mark_gc  = gw->goban.white_fg_gc;
	    erase_gc = gw->goban.white_bg_gc;
	  }

	else {
	  mark_gc  = gw->goban.foreground_gc;
	  erase_gc = gw->goban.background_gc;
	}
	
	if (c1 == 0) {
	  radius = 10 * (int)gw->goban.point_size / 15;
	  
	  if (gw->goban.points[x][y].free == 0)
	      XFillArc (display, gw->goban.picture, erase_gc, 
			(int) (X - gw->goban.point_size) / 2 + 2,
			(int) (Y - gw->goban.point_size) / 2 + 2, 
			(unsigned int) gw->goban.point_size - 4,
			(unsigned int) gw->goban.point_size - 4, 
			0, 360 * 64);
	  else
	    XFillArc (display, gw->goban.picture, erase_gc,
		      (int) (X - radius) / 2, (int) (Y - radius) / 2, 
		      (unsigned int) radius, (unsigned int) radius, 
		      0, 360 * 64);

	  switch( c2 ) {
	    
	  case GbMTriangleMark :
	    radius -= 4;

	    segment[0].x1 = (short) X / 2;
	    segment[0].x2 = (short) (X / 2 + (86 * radius + 100) / 200);
	    segment[0].y1 = (short) (Y / 2 - (radius - 1) / 2);
	    segment[0].y2 = (short) (Y / 2 + (radius + 4) / 4);
	    
	    segment[1].x1 = (short) segment[0].x2;
	    segment[1].x2 = (short) (X / 2 - (86 * radius + 100) / 200);
	    segment[1].y1 = (short) segment[0].y2;
	    segment[1].y2 = (short) (Y / 2 + (radius + 4) / 4);
	    
	    segment[2].x1 = (short) segment[1].x2;
	    segment[2].x2 = (short) segment[0].x1;
	    segment[2].y1 = (short) segment[1].y2;
	    segment[2].y2 = (short) segment[0].y1;

	    XDrawSegments (display, gw->goban.picture, mark_gc, segment, 3);
	    break;

	  case GbMSquareMark  :
	    radius = 10 * radius / 14 - 2;
	    
	    XDrawRectangle (display, gw->goban.picture, mark_gc, 
			    (X - radius) / 2, (Y - radius) / 2, 
			    (unsigned int) radius, (unsigned int) radius);
	    break;
    
	  case GbMDCrossMark  :
	    radius = 10 * radius / 14 - 2;

	    segment[0].x1 = (short) (X - radius) / 2;
	    segment[0].x2 = (short) segment[0].x1    + radius;
	    segment[0].y1 = (short) (Y - radius) / 2;
	    segment[0].y2 = (short) segment[0].y1    + radius;

	    segment[1].x1 = (short) (X - radius) / 2 + radius;
	    segment[1].x2 = (short) segment[1].x1    - radius;
	    segment[1].y1 = (short) (Y - radius) / 2;
	    segment[1].y2 = (short) segment[1].y1    + radius;
	    
	    XDrawSegments (display, gw->goban.picture, mark_gc, segment, 2);
	    break;
	    
	  case GbMVCrossMark  :
	    radius -= 4;

	    segment[0].x1 = (short) X / 2;
	    segment[0].x2 = (short) segment[0].x1;
	    segment[0].y1 = (short) (Y - radius) / 2;
	    segment[0].y2 = (short) segment[0].y1 + radius;

	    segment[1].x1 = (short) (X - radius) / 2;
	    segment[1].x2 = (short) segment[1].x1 + radius;
	    segment[1].y1 = (short) Y / 2;
	    segment[1].y2 = (short) segment[1].y1;
	    
	    XDrawSegments (display, gw->goban.picture, mark_gc, segment, 2);
	    break;

	  case GbMDiamondMark :
	    radius -= 4;

	    segment[0].x1 = (short) X / 2;
	    segment[0].x2 = (short) segment[0].x1 + radius / 2;
	    segment[0].y1 = (short) (Y - radius) / 2;
	    segment[0].y2 = (short) segment[0].y1 + radius / 2;

	    segment[1].x1 = (short) segment[0].x2;
	    segment[1].x2 = (short) segment[0].x1;
	    segment[1].y1 = (short) segment[0].y2;
	    segment[1].y2 = (short) segment[1].y1 + radius / 2;
	    
	    segment[2].x1 = (short) segment[1].x2;
	    segment[2].x2 = (short) segment[2].x1 - radius / 2;
	    segment[2].y1 = (short) segment[1].y2;
	    segment[2].y2 = (short) segment[1].y1;
	    
	    segment[3].x1 = (short) segment[2].x2;
	    segment[3].x2 = (short) segment[0].x1;
	    segment[3].y1 = (short) segment[2].y2;
	    segment[3].y2 = (short) segment[0].y1;
	    
	    XDrawSegments (display, gw->goban.picture, mark_gc, segment, 4);
	    break;
	  }
	}
	
	else {
	  s[len++] = c1;
	  if( c2 != 0 ) s[len++] = c2;
	  
	  XQueryTextExtents (display, XGContextFromGC (mark_gc), s, len,
				&direction, &ascent, &descent, &extent);
	  
	  radius = extent.width + extent.descent + extent.ascent;
	  
	  if (radius < (int)gw->goban.point_size - 1) {
	    if (gw->goban.points[x][y].free == 0)
	      XFillArc (display, gw->goban.picture, erase_gc, 
			(int) (X - gw->goban.point_size) / 2 + 2,
			(int) (Y - gw->goban.point_size) / 2 + 2, 
			(unsigned int) gw->goban.point_size - 4,
			(unsigned int) gw->goban.point_size - 4, 
			0, 360 * 64);
	    else
	      XFillArc (display, gw->goban.picture, erase_gc,
			(int) (X - radius) / 2, (int) (Y - radius) / 2, 
			(unsigned int) radius, (unsigned int) radius, 
			0, 360 * 64);
	    
	    XDrawString (display, gw->goban.picture, mark_gc,
			 (X - extent.width) / 2 - extent.lbearing + 1, 
			 (Y + extent.ascent - extent.descent) / 2 + 1, s, len);
	  }
	}
      
	if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
	  event.x      = (int)(X - gw->goban.point_size) / 2;
	  event.y      = (int)(Y - gw->goban.point_size) / 2;
	  event.width  = gw->goban.point_size;
	  event.height = gw->goban.point_size;
	  
	  Redisplay (w, &event, (Region) NULL);
	}
      }
    }
  }
}

/****************************************************************************************************************
 */

/* ARGSUSED */

static void Redisplay (w, event, region)
Widget        w;
XExposeEvent *event;
Region        region;
{
  GobanWidget gw     = (GobanWidget) w;
  Position    x      = event->x;
  Position    y      = event->y;
  Dimension   width  = event->width;
  Dimension   height = event->height;

  XCopyArea (XtDisplay (w), gw->goban.picture, XtWindow (w), gw->goban.copy_gc, x, y, width, height, x, y);
}

/****************************************************************************************************************
 */

/* ARGSUSED */

static void CvtStringToCursor (args, num_args, fromVal, toVal)
XrmValuePtr   args;		/* unused */
Cardinal     *num_args;	/* unused */
XrmValuePtr   fromVal;
XrmValuePtr   toVal;
{
  static int       cursor;
  static XrmQuark  QWhiteStone;
  static XrmQuark  QBlackStone;
  XrmQuark         quark;
  char             lowerName[256];
  static Boolean   inited = FALSE;
    
  if (inited == FALSE) {
    QWhiteStone  = XrmStringToQuark (XtEgbWhiteStone);
    QBlackStone  = XrmStringToQuark (XtEgbBlackStone);
    inited       = TRUE;
  }

  XmuCopyISOLatin1Lowered  (lowerName, (String) fromVal->addr);
  quark = XrmStringToQuark (lowerName);

  if (quark == QWhiteStone)
    cursor = GbCWhiteStone;
  else if (quark == QBlackStone)       
    cursor = GbCBlackStone;
  else {
    toVal->size = 0;
    toVal->addr = NULL;
    return;
  }

  toVal->size = sizeof (cursor);
  toVal->addr = (caddr_t) &cursor;
}

/****************************************************************************************************************
 */

static void ClassInitialize()
{
  XtAddConverter (XtRString, XtRInt, (XtConverter) CvtStringToCursor, NULL, 0);
}

/****************************************************************************************************************
 */

static void InitializePixmap (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);
  Drawable     window  = RootWindowOfScreen (XtScreen (w));
  Dimension    width   = w->core.width;
  Dimension    height  = w->core.height;

  gw->goban.board   = XCreatePixmap (display, window, width, height, (unsigned int) DefaultDepthOfScreen (XtScreen (w)));
  gw->goban.picture = XCreatePixmap (display, window, width, height, (unsigned int) DefaultDepthOfScreen (XtScreen (w)));
}

/****************************************************************************************************************
 */

static void InitializeGC (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);
  XtGCMask     mask    = GCForeground | GCBackground | GCFont;
  XGCValues    values;

  values.font             = gw->goban.font->fid;
  values.background       = w->core.background_pixel;

  values.foreground       = gw->goban.white_fg;
  gw->goban.white_fg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  values.foreground       = gw->goban.white_bg;
  gw->goban.white_bg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  values.foreground       = gw->goban.white_bd;
  gw->goban.white_bd_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);

  values.foreground       = gw->goban.black_fg;
  gw->goban.black_fg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  values.foreground       = gw->goban.black_bg;
  gw->goban.black_bg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  values.foreground       = gw->goban.black_bd;
  gw->goban.black_bd_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);

  values.foreground       = gw->goban.foreground;
  gw->goban.foreground_gc = XCreateGC  (display, gw->goban.picture, mask, &values);
  gw->goban.copy_gc       = XCreateGC  (display, gw->goban.picture, (XtGCMask) 0, (XGCValues *) NULL);

  if( !stippleflag ) {
    if( gw->goban.stipple ) stippleflag = TRUE;
  }
  else {
    if( gw->goban.stipple ) stippleflag = FALSE;
  }

  if( stippleflag ) {
    values.stipple           = XCreatePixmapFromBitmapData (display,
				gw->goban.picture,
				(char *)stipple_bits, stipple_width,
				stipple_height,
				BlackPixel (display, DefaultScreen (display)),
				WhitePixel (display, DefaultScreen (display)),
				1);
    values.fill_style     = FillOpaqueStippled;
    mask                 |= GCStipple | GCFillStyle;
  }

  values.foreground       = w->core.background_pixel;
  values.background       = gw->goban.foreground;
  gw->goban.background_gc = XCreateGC  (display, gw->goban.picture, mask, &values);
}

/*******************************************************************/ 
static void InitializeCursor (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);
  Drawable     window  = RootWindowOfScreen (XtScreen (w));
  Pixel        black   = BlackPixel (display, DefaultScreen (display));
  Pixel        white   = WhitePixel (display, DefaultScreen (display));

  static XColor black_color = { 0,    0,     0,     0  };  /* black */
  static XColor white_color = { 0, 65535, 65535, 65535 };  /* white */

  /* Some teminals invert the mask with BlackPixel and WhitePixel     */
  /* should use black and white instead of 1 and 0 but depth is 1 ... */
  /* will probably have trouble with some special colormaps           */

  gw->goban.white_stone = XCreatePixmapFromBitmapData
    (display, window, (char *)whitestone_bits, whitestone_width, whitestone_height, 1, 0, 1);
  gw->goban.black_stone = XCreatePixmapFromBitmapData
    (display, window, (char *)blackstone_bits, blackstone_width, blackstone_height, 1, 0, 1);
  gw->goban.mouse_mask  = XCreatePixmapFromBitmapData
    (display, window, (char *)stonemask_bits , stonemask_width , stonemask_height , 1, 0, 1);

  gw->goban.white_cursor = 
    XCreatePixmapCursor (display, gw->goban.white_stone, gw->goban.mouse_mask, 
			 &black_color, &white_color, whitestone_x_hot, whitestone_y_hot);
  gw->goban.black_cursor = 
    XCreatePixmapCursor (display, gw->goban.black_stone, gw->goban.mouse_mask, 
			 &black_color, &white_color, blackstone_x_hot, blackstone_y_hot);

  gw->goban.font_cursor  = XCreateFontCursor (display, XC_question_arrow);
}
  
/****************************************************************************************************************
 */

static void DestroyPixmap (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);

  XFreePixmap (display, gw->goban.picture);
  XFreePixmap (display, gw->goban.board  );
}

/****************************************************************************************************************
 */

static void DestroyGC (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);

  XFreeGC (display, gw->goban.black_fg_gc  );
  XFreeGC (display, gw->goban.black_bg_gc  );
  XFreeGC (display, gw->goban.black_bd_gc  );
  XFreeGC (display, gw->goban.white_fg_gc  );
  XFreeGC (display, gw->goban.white_bg_gc  );
  XFreeGC (display, gw->goban.white_bd_gc  );
  XFreeGC (display, gw->goban.foreground_gc);
  XFreeGC (display, gw->goban.background_gc);
  XFreeGC (display, gw->goban.copy_gc      );
}

/****************************************************************************************************************
 */

static void Destroy (w)
Widget w;
{
  GobanWidget  gw      = (GobanWidget) w;
  Display     *display = XtDisplay (w);

  DestroyPixmap (w);
  DestroyGC     (w);

  XFreePixmap (display, gw->goban.white_stone  );
  XFreePixmap (display, gw->goban.black_stone  );
  XFreePixmap (display, gw->goban.gray_stone   );
  XFreePixmap (display, gw->goban.mouse_mask   );

  XFreeCursor (display, gw->goban.white_cursor );
  XFreeCursor (display, gw->goban.black_cursor );
  XFreeCursor (display, gw->goban.gray_cursor  );
  XFreeCursor (display, gw->goban.font_cursor  );
}

/****************************************************************************************************************
 */

static void Realize (w, valuemaskp, attr)
Widget                w;
XtValueMask          *valuemaskp;
XSetWindowAttributes *attr;
{
  GobanWidget  gw      = (GobanWidget) w;
  
  *valuemaskp |= CWCursor;

  switch (gw->goban.cursor) {
  case GbCBlackStone : attr->cursor = gw->goban.black_cursor; break;
  case GbCWhiteStone : attr->cursor = gw->goban.white_cursor; break;
  default            : attr->cursor = gw->goban.font_cursor ; break;
  }
  
  XtCreateWindow (w, InputOutput, (Visual *) CopyFromParent, *valuemaskp, attr);
}

/****************************************************************************************************************
 */

static char *stars[18] = {
  "",				/*  2  */  
  "",				/*  3  */  
  "",				/*  4  */  
  "",				/*  5  */  
  "",				/*  6  */  
  "",				/*  7  */  
  "cccffcff",			/*  8  */    
  "cccgeegcgg",			/*  9  */  
  "ccchhchh",			/* 10  */  
  "cccfcifcfffiicifii",		/* 11  */  
  "dddiidii",			/* 12  */  
  "dddjggjdjj",			/* 13  */  
  "dddkkdkk",			/* 14  */  
  "dddhdlhdhhhlldlhll",		/* 15  */  
  "dddmmdmm",			/* 16  */  
  "dddidnidiiinndninn",		/* 17  */  
  "dddoodoo",			/* 18  */  
  "dddjdpjdjjjppdpjpp",		/* 19  */  
};

static void DrawBoard (w)
Widget w;
{
  GobanWidget  gw         = (GobanWidget) w;
  Display     *display    = XtDisplay (w);
  XSegment     segment[44];
  int          segc;
  Position     game_size  = (Position) gw->goban.game_size;
  Position     point_size = (Position) gw->goban.point_size;
  Position     star_size  = 4;
  Position     xbase      = gw->goban.x_offset + point_size / 2;
  Position     ybase      = gw->goban.y_offset - point_size / 2;
  Position     xmin       = gw->goban.x_offset + point_size * gw->goban.left + 1;
  Position     ymin       = gw->goban.y_offset - point_size * gw->goban.top  + 1;
  Position     xmax       = gw->goban.x_offset + point_size * (gw->goban.right  + 1) - 1;
  Position     ymax       = gw->goban.y_offset - point_size * (gw->goban.bottom - 1) - 1;
  char        *star;
  int          x;
  int          y;

  XFillRectangle (display, gw->goban.board, gw->goban.background_gc, 0, 0, w->core.width, w->core.height);

  if (point_size > 0) {
    segc = 0;
    for (y = gw->goban.bottom - 1; y < gw->goban.top; y++, segc++) {
      segment[segc].x1 = (short) Max ((int) xbase + point_size , xmin);
      segment[segc].x2 = (short) Min ((int) xbase + point_size * game_size, xmax);
      segment[segc].y1 = (short) (ybase - point_size * y);
      segment[segc].y2 = (short) (ybase - point_size * y);
    }
    
    for (x = gw->goban.left; x <= gw->goban.right; x++, segc++) {
      segment[segc].x1 = (short) (xbase + point_size * x);
      segment[segc].x2 = (short) (xbase + point_size * x);
      segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1), ymin);
      segment[segc].y2 = (short) Min (ybase, ymax);
    }
    
    if (gw->goban.top == gw->goban.game_size) {
      segment[segc].x1 = (short) Max (xbase + point_size - 1, xmin);
      segment[segc].x2 = (short) Min (xbase + point_size * game_size + 1, xmax);
      segment[segc].y1 = (short) (ybase - point_size * (game_size - 1) - 1);
      segment[segc].y2 = (short) (ybase - point_size * (game_size - 1) - 1);
      segc++;
    }
    
    if (gw->goban.bottom == 1) {
      segment[segc].x1 = (short) Max (xbase + point_size - 1, xmin);
      segment[segc].x2 = (short) Min (xbase + point_size * game_size + 1, xmax);
      segment[segc].y1 = (short) (ybase + 1);
      segment[segc].y2 = (short) (ybase + 1);
      segc++;
    }
    
    if (gw->goban.left == 1) {
      segment[segc].x1 = (short) (xbase + point_size - 1);
      segment[segc].x2 = (short) (xbase + point_size - 1);
      segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1) - 1, ymin); 
      segment[segc].y2 = (short) Min (ybase + 1, ymax);
      segc++;
    }
    
    if (gw->goban.right == gw->goban.game_size) {
      segment[segc].x1 = (short) (xbase + point_size * game_size + 1);
      segment[segc].x2 = (short) (xbase + point_size * game_size + 1);
      segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1) - 1, ymin);
      segment[segc].y2 = (short) Min (ybase + 1, ymax);
      segc++;
    }
    
    XDrawSegments (display, gw->goban.board, gw->goban.foreground_gc, segment, segc);
    
    if (point_size > 8) {
      star_size = (point_size > 10) ? 4 : 2;
      star      = stars[game_size - 2];
      
      while (*star != '\0') {
	x = *star++ - 'a' + 1;
	y = *star++ - 'a' + 1;
	
	if (x >= gw->goban.left && x <= gw->goban.right && y >= gw->goban.bottom && y <= gw->goban.top) {
	  x = gw->goban.x_offset + (point_size * (2 * x + 1)) / 2;
	  y = gw->goban.y_offset - (point_size * (2 * y - 1)) / 2;
	  
	  XDrawArc (display, gw->goban.board, gw->goban.foreground_gc, 
		    (int) x - star_size / 2, (int) y - star_size / 2, 
		    (unsigned int) star_size, (unsigned int) star_size, 
		    0, 64 * 360);
	  XFillArc (display, gw->goban.board, gw->goban.foreground_gc, 
		    (int) x - star_size / 2, (int) y - star_size / 2, 
		    (unsigned int) star_size, (unsigned int) star_size, 
		    0, 64 * 360);
	}
      }
    }
  }

  XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, 0, 0, 
	     w->core.width, w->core.height, 0, 0);
}

/****************************************************************************************************************
 */

static void DrawCoordinates (w)
Widget w;
{
  GobanWidget  gw         = (GobanWidget) w;
  Display     *display    = XtDisplay (w);
  XCharStruct  extent;
  int          point_size = gw->goban.point_size;
  char         s[2];
  int          len;
  int          ascent;
  int          descent;
  int          direction;
  int          xbase;
  int          ybase;
  int          x;
  int          y;
  unsigned int width;
  unsigned int height;

  s[0] = s[1] = '8';
  XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
		     s, 2, &direction, &ascent, &descent, &extent);

  if ((point_size > extent.width + 2) && (point_size > extent.ascent + extent.descent + 2)) {
    xbase = 2 * gw->goban.x_offset + point_size;
    ybase = 2 * gw->goban.y_offset - point_size;

    if (gw->goban.display_coordinates == TRUE) {
    
      for (x = gw->goban.left; x <= gw->goban.right; x++) {
	s[0] = 'A' - 1 + ((x > 8) ? (x + 1) : x);
	XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
			   s, 1, &direction, &ascent, &descent, &extent);

	XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
		     (xbase - extent.width) / 2 + point_size * x - extent.lbearing + 1, 
		     (ybase + extent.ascent - extent.descent) / 2 - point_size * gw->goban.top + 1, s, 1);
	XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
		     (xbase - extent.width) / 2 + point_size * x - extent.lbearing + 1, 
		     (ybase + extent.ascent - extent.descent) / 2 - point_size * (gw->goban.bottom - 2) + 1, s, 1);
      }
    }

    x      = gw->goban.x_offset + point_size * gw->goban.left;
    y      = gw->goban.y_offset - point_size * (gw->goban.top + 1);
    width  = point_size * (gw->goban.right - gw->goban.left + 1);
    height = point_size;
    
    if (gw->goban.display_coordinates == FALSE)
      XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
    XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);

    y      = gw->goban.y_offset - point_size * (gw->goban.bottom - 1);

    if (gw->goban.display_coordinates == FALSE)
      XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
    XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
    
    ybase += 2 * point_size;

    for (y = gw->goban.bottom; y <= gw->goban.top; y++) {
      if (gw->goban.display_coordinates == TRUE) {
	len = 0;
	if (y > 9)
	  s[len++] = '1';
	s[len++] = '0' + y % 10;
	XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
			   s, len, &direction, &ascent, &descent, &extent);

	XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
		     (xbase - extent.width) / 2 + point_size * (gw->goban.left  - 1) - extent.lbearing + 1, 
		     (ybase + extent.ascent - extent.descent) / 2 - point_size * y + 1, s, len);
	XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
		     (xbase - extent.width) / 2 + point_size * (gw->goban.right + 1) - extent.lbearing + 1, 
		     (ybase + extent.ascent - extent.descent) / 2 - point_size * y + 1, s, len);
      }
    }

    x      = gw->goban.x_offset + point_size * (gw->goban.left  - 1);
    y      = gw->goban.y_offset - point_size * gw->goban.top;
    width  = point_size;
    height = point_size * (gw->goban.top - gw->goban.bottom + 1);;
    
    if (gw->goban.display_coordinates == FALSE)
      XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
    XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);

    x      = gw->goban.x_offset + point_size * (gw->goban.right + 1);
    
    if (gw->goban.display_coordinates == FALSE)
      XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
    XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
  }

}

/****************************************************************************************************************
 */

static void InitializeSize (w)
Widget w;
{  
  GobanWidget  gw        = (GobanWidget) w;
  Position     bottom    = Min (gw->goban.bottom, gw->goban.top  );
  Position     left      = Min (gw->goban.left  , gw->goban.right);
  Position     top       = Max (gw->goban.bottom, gw->goban.top  );
  Position     right     = Max (gw->goban.left  , gw->goban.right);
  Dimension    game_size = gw->goban.game_size;
  Dimension    width;
  Dimension    height;

  game_size = (game_size > 1      && game_size <  20       ) ? game_size : 19;
  bottom    = (bottom    > 0      && bottom    <  (Position)game_size) ? bottom    : 1;
  left      = (left      > 0      && left      <  (Position)game_size) ? left      : 1;
  top       = (top       > bottom && top       <= (Position)game_size) ? top       : game_size;
  right     = (right     > left   && right     <= (Position)game_size) ? right     : game_size;

  width     = right - left   + 3;
  height    = top   - bottom + 3;

  if ((w->core.height == 0) && (w->core.width == 0)) {
    w->core.width  = gw->goban.point_size * width ;
    w->core.height = gw->goban.point_size * height;
  } 
 
  else 
    gw->goban.point_size = Min ((int)w->core.width / (int)width, (int)w->core.height / (int)height);

  gw->goban.game_size = game_size;
  gw->goban.bottom    = bottom;
  gw->goban.left      = left;
  gw->goban.top       = top;
  gw->goban.right     = right;
  gw->goban.x_offset  = (int) (w->core.width  - gw->goban.point_size * (width  + 2 * left - 2)) / 2;
  gw->goban.y_offset  = (int) (w->core.height - gw->goban.point_size * (height - 2 * top  - 2)) / 2;
}

/****************************************************************************************************************
 */

/* ARGSUSED */

static void Initialize (request, new)
Widget request;
Widget new;
{
	GobanWidget   gw      = (GobanWidget) new;
	gw->goban.left = 1;
	gw->goban.right = 19;
	gw->goban.top = 1;
	gw->goban.bottom = 19;

  InitializeSize   (new);
  InitializePixmap (new);
  InitializeGC     (new);
  InitializeCursor (new);
  DrawBoard        (new);
  DrawCoordinates  (new);
  GbClearBoard     (new);
}

/****************************************************************************************************************
 */

static void DrawPoint (w, x, y, color, flag)
Widget      w;
int         x;
int         y;
GbPointState color;
Boolean flag;	/*SC  TRUE to mark as "Last"  FALSE to just draw stone */
{
  GobanWidget   gw      = (GobanWidget) w;
  Display      *display = XtDisplay (w);
  unsigned int  size    = (unsigned int) gw->goban.point_size - 2;
  XExposeEvent  event;
  int           X, XX;
  int           Y, YY;

  if (size > 1) {
    X = gw->goban.x_offset + gw->goban.point_size * x + 1;
    Y = gw->goban.y_offset - gw->goban.point_size * y + 1;
    XX = X + size/4 +1;
    YY = Y + size/4 +1;

    
    switch (color)
      {
      case GbBlackStone :
	XFillArc (display, gw->goban.picture, gw->goban.black_bg_gc, X, Y,
			size, size, 0, 360 * 64);
	XDrawArc (display, gw->goban.picture, gw->goban.black_bd_gc, X, Y,
			size, size, 0, 360 * 64);
	if( flag ) {
	   XFillArc( display, gw->goban.picture, gw->goban.black_fg_gc,
			 XX, YY, size/2, size/2, 0, 360*64 );
	   lastx = X;
	   lasty = Y;
           lastcolor = color;
       }

	else XDrawArc (display, gw->goban.picture, gw->goban.black_fg_gc,
			X + (int) size / 6, Y + (int) size / 6, 
		  	(size * 2) / 3, (size * 2) / 3, -15 * 64, -60 * 64);
	break;
      case GbWhiteStone :
	XFillArc (display, gw->goban.picture, gw->goban.white_bg_gc, X, Y,
			size, size, 0, 360 * 64);
	XDrawArc (display, gw->goban.picture, gw->goban.white_bd_gc, X, Y,
			size, size, 0, 360 * 64);
	if( flag ) {
	    XFillArc( display, gw->goban.picture, gw->goban.white_fg_gc,
			XX, YY, size/2, size/2, 0, 360*64 );
	    lastx = X;
	    lasty = Y;
	    lastcolor = color;
	}
	else XDrawArc (display, gw->goban.picture, gw->goban.white_fg_gc,
			X + (int) size / 6, Y + (int) size / 6, 
		  	(size * 2) / 3, (size * 2) / 3, -15 * 64, -60 * 64);
	break;
      case GbEmptyPoint :
	XCopyArea (XtDisplay (w), gw->goban.board, gw->goban.picture,
			gw->goban.copy_gc, X, Y, gw->goban.point_size,
			gw->goban.point_size, X, Y); 
	break;
      }
    
    if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
      event.x      = X - 1;
      event.y      = Y - 1;
      event.width  = gw->goban.point_size;
      event.height = gw->goban.point_size;

      Redisplay (w, &event, (Region) NULL);
    }
  }
}

/****************************************************************************************************************
 */

static void RedrawStones (w)
Widget w;
{
  GobanWidget  gw         = (GobanWidget) w;
  Boolean      redisplay  = gw->goban.auto_redisplay;
  Position     x;
  Position     y;

  gw->goban.auto_redisplay = FALSE;

  for (x = gw->goban.left; x <= gw->goban.right; x++)
    for (y = gw->goban.bottom; y <= gw->goban.top; y++) {
      if (gw->goban.points[x][y].free == 0) {
	if (gw->goban.points[x][y].black == 1) {
	  DrawPoint (w, x, y, GbBlackStone, FALSE);
	}
	else {
	  DrawPoint (w, x, y, GbWhiteStone, FALSE);
	}
	if (gw->goban.points[x][y].num > 0)
	  GbSetNum (w, x, y, (int) gw->goban.points[x][y].num);
      }

      if (gw->goban.points[x][y].mark1 != 0 || gw->goban.points[x][y].mark2 != 0)
	GbSetMark (w, x, y, gw->goban.points[x][y].mark1, gw->goban.points[x][y].mark2);
    }

  gw->goban.auto_redisplay = redisplay;

  if (redisplay == TRUE) GbRedisplayBoard (w);
}

/****************************************************************************************************************
 */

static void Resize (w)
Widget w;
{
  DestroyPixmap    (w);
  DestroyGC        (w);
  InitializeSize   (w);
  InitializePixmap (w);
  InitializeGC     (w);
  DrawBoard        (w);
  DrawCoordinates  (w);
  RedrawStones     (w);
}

/****************************************************************************************************************
 */

/* ARGSUSED */

static Boolean SetValues (current, request, new)
Widget current;
Widget request;
Widget new;
{
  GobanWidget gnew      = (GobanWidget) new;
  GobanWidget gcurrent  = (GobanWidget) current;
  Boolean     redisplay = FALSE;

  if (gnew->goban.point_size != gcurrent->goban.point_size)
    gnew->goban.point_size = gcurrent->goban.point_size;

  if (XtIsRealized (new)) {
    if (gnew->goban.cursor != gcurrent->goban.cursor) {

      switch (gnew->goban.cursor) {

      case GbCBlackStone : 
	XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.black_cursor);
	break;
      case GbCWhiteStone : 
	XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.white_cursor);
	break;
      default :
	XFreeCursor (XtDisplay (new), gnew->goban.font_cursor );
	gnew->goban.font_cursor = XCreateFontCursor (XtDisplay (new), (unsigned int) gnew->goban.cursor);
	XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.font_cursor);
      }
    }
  }

  if (gnew->goban.game_size != gcurrent->goban.game_size) 
    if (gnew->goban.game_size > 1 && gnew->goban.game_size < 20) {

      gnew->goban.bottom = 1;
      gnew->goban.left   = 1;
      gnew->goban.top    = gnew->goban.game_size;
      gnew->goban.right  = gnew->goban.game_size;
      
      InitializeSize   (new);
      DrawBoard        (new);
      DrawCoordinates  (new);
      GbClearBoard     (new);
      
      redisplay = TRUE;
    }
    else
      gnew->goban.game_size = gcurrent->goban.game_size;

  else if (gnew->goban.top    != gcurrent->goban.top   ||
	   gnew->goban.left   != gcurrent->goban.left  ||
	   gnew->goban.right  != gcurrent->goban.right ||
	   gnew->goban.bottom != gcurrent->goban.bottom) {

    InitializeSize  (new);
    DrawBoard       (new);
    DrawCoordinates (new);
    RedrawStones    (new);

    redisplay = TRUE;
  }

  else if (new->core.background_pixel != current->core.background_pixel || 
           gnew->goban.foreground     != gcurrent->goban.foreground     ||
           gnew->goban.white_fg       != gcurrent->goban.white_fg       ||
           gnew->goban.white_bg       != gcurrent->goban.white_bg       ||
           gnew->goban.white_bd       != gcurrent->goban.white_bd       ||
           gnew->goban.black_fg       != gcurrent->goban.black_fg       ||
           gnew->goban.black_bg       != gcurrent->goban.black_bg       ||
           gnew->goban.black_bd       != gcurrent->goban.black_bd       ) {

    DestroyGC        (new);
    InitializeGC     (new);
    DrawBoard        (new);
    DrawCoordinates  (new);
    RedrawStones     (new);

    redisplay = TRUE;
  }

  if (gnew->goban.display_coordinates != gcurrent->goban.display_coordinates) {
    DrawCoordinates (new);

    redisplay = TRUE;
  }

  return (gnew->goban.auto_redisplay == True) ? redisplay : False;
}

/****************************************************************************************************************
 */
SHAR_EOF
fi
if test -f 'Goban.doc'
then
	echo shar: "will not over-write existing file 'Goban.doc'"
else
cat << \SHAR_EOF > 'Goban.doc'
Goban Widget 
------------

 The Goban widget displays a full or partial go board within a rectangular area and 
 allows an application to put or remove stones on it. The application can also draw 
 numbers on stones, and marks (consisting of a one or two characters string) on stones 
 or empty points. It has no knowledge of the game and thus doesn't remove dead stones 
 if any (it is the application's responsability).

 For every position specification, the coordinate system uses an x axis going from left
 to right, and an y axis going from bottom to top.

Resources
---------

 Name		       Class		  RepType		Default Value
 ----		       -----		  -------		-------------
 autoRedisplay         AutoRedisplay      Boolean         True
 background	       Background	  Pixel		  XtDefaultBackground
 blackStoneBackground  Background	  Pixel		  black
 blackStoneBorder      BorderColor	  Pixel		  black
 blackStoneForeground  Foreground	  Pixel		  white
 border		       BorderColor	  Pixel		  XtDefaultForeground
 borderWidth	       BorderWidth	  Dimension	  1
 cursor                Cursor             Integer         GbGrayCursor
 destroyCallback       Callback		  Pointer	  NULL
 displayCoordinates    DisplayCoordinates Boolean	  True
 font                  Font               XFontStruct*    fixed
 foreground            Foreground         Pixel           XtDefaultForeground
 gameSize              Size               Dimension       19
 height		       Height		  Dimension	  computed at create
 mappedWhenManaged     MappedWhenManaged  Boolean	  True
 pointSize             Size               Dimension       24
 sensitive	       Sensitive	  Boolean	  True
 viewBottom            Position           Position        computed at create
 viewLeft              Position           Position        computed at create
 viewRight             Position           Position        computed at create
 viewTop               Position           Position        computed at create
 whiteStoneBackground  Background	  Pixel		  white
 whiteStoneBorder      BorderColor	  Pixel		  black
 whiteStoneForeground  Foreground	  Pixel		  black
 width		       Width		  Dimension	  computed at create
 x		       Position		  Position	  0
 y		       Position		  Position	  0

 autoRedisplay	      If this resource is True, then all changes on the widget (put or remove
		      stones, put numbers or marks) will be immediatly flushed to the screen.
		      This can be set to False in conjonction with GbRedisplay in order to 
		      improve the speed when displaying a position.

 background	      As usual.
 backgroundPixmap     As usual.

 blackStoneBackground This color will be used to fill the black stones (usually black)
 blackStoneBorder     This color will be used to draw a circle arround the black stones. This is
                      usefull with white stones to delimit the circumference of the stone.
 blackStoneForeground This color will be used to draw marks and numbers on black stones.

 border		      As usual.
 borderWidth	      As usual.


 cursor		      The cursor that will be displayed : should be GbCGrayStone, GbCWhiteStone
		      or GbCBlackStone or a valid cursorFont ID.

 destroyCallback      As usual.

 font		      The font that will be used to put numbers and marks on the board and to
		      display the coordinate marks.

 foreground	      As usual.

 gameSize	      The board size : board is always square and its size must range between
		      2 and 19.

 height		      As usual.

 mappedWhenManaged    As usual.

 displayCoordinates   If this resource is True, then the coordinate marks will be displayed 
		      around the board.

 pointSize	      The distance in pixels between points.
     
 sensitive	      As usual.

 viewBottom           The bottom of the partial goban that is viewed. Must range between 1 and
		      gameSize - 1.

 viewLeft	      The left of the partial goban that is viewed. Must range between 1 and
		      gameSize - 1.

 viewRight	      The right of the partial goban that is viewed. Must range between 
		      viewLeft + 1 and gameSize.

 viewTop	      The top of the partial goban that is viewed. Must range between
		      viewBottom + 1 and gameSize.

 width		      As usual.

 whiteStoneBackground This color will be used to fill the white stones (usually white)
 whiteStoneBorder     This color will be used to draw a circle arround the white stones.
 whiteStoneForeground This color will be used to draw marks and numbers on white stones.

 x		      As usual.
 y		      As usual.


Procedures provided for application
-----------------------------------  

void GbRedisplayBoard (w)
GobanWidget w;

 Redisplay the entire board <w> on the screen.

void GbClearBoard (w)
GobanWidget w;

 Remove all stones of the board <w> and call GbRedisplayBoard.
 

typedef enum { GbEmptyPoint, GbBlackStone, GbWhiteStone, } GbPointState;

void GbSetPoint (w, x, y, color)     
GobanWidget  w;
Position     x;
Position     y; 
GbPointState color;

 Put a stone of color <color> at location <x><y> on the board <w>.
 If color is GbEmptyPoint, then the stone (if any) is removed from location <x><y>.
 All marks on this point are removed.
 If autoRedisplay if set to False the change will not be visible on the screen until
 the application calls GbRedisplay.


void GbSetNum (w, x, y, num)
GobanWidget  w;
Position     x;
Position     y;
unsigned int num;

 Draw the number <num> on the stone at location <x><y> on the board <w>.
 <num> must range between 0 and 999 and no number is displayed if there is no stone
 at this location.
 If <num> is equal to 0, all previous num (if any) is removed from stone.
 When the representation of <num> is to bigger than the stone size (according to font size) 
 no number is displayed.


void GbSetMark (w, x, y, mark1, mark2)
GobanWidget   w;
Position      x;
Position      y;
unsigned char mark1;
unsigned char mark2;

 Draw the two characters mark at location <x><y> on the board <w>.
 <x><y> may be an empty point.
 If <mark1> and <mark2> are equal to 0, the previous mark (if any) is removed from point.
 If <mark2> is equal to 0, only one character will be displayed.
 If <mark1> is equal to 0, <mark2> can be one of GbMSquareMark, GbMTriangleMark, GbMVCrossMark, 
 GbMDCrossMark or GbMDiamondMark. In this case, geometric marks are drawn.
 When the representation of the mark is to bigger than the stone size (according to font size) 
 no mark is displayed.
 GbRemoveMark(w,x,y) is defined as a macro call for GbSetMark(w,x,y,0,0).


Boolean GbGetStoneFromPosition (w, x, y)
GobanWidget   w;
Position     *x;
Position     *y;

 Provide a way to know on what point occurs a mouse event.
 If the event occurs on a valid point on the board, GbGetStoneFromEvent returns TRUE,
 and <x> <y> variables are set to the coordinates of that point.
 If not, GbGetStoneFromEvent returns FALSE and <event> is unchanged.


Boolean GbGetPositionFromStone (w, x, y)
GobanWidget   w;
Position     *x;
Position     *y;

 Provide a way to know what are the coordinates (in pixel) for the center of a given 
 point. It works as GbGetStoneFromPosition.
 Those functions are not reverse of each other ...

SHAR_EOF
fi
if test -f 'Goban.h'
then
	echo shar: "will not over-write existing file 'Goban.h'"
else
cat << \SHAR_EOF > 'Goban.h'
/****************************************************************************************************************
 *
 *  Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behaviour
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    dumesnil@etca.fr   or to:
 *       
 *       Antoine de Maricourt
 *       ETCA CREA-SP
 *       16 bis, avenue Prieur de la Cote d'Or
 *       94114 Arcueil Cedex
 *       France
 */

#ifndef _Goban_h
#define _Goban_h

/* Resources:

 Name		       Class		  RepType		Default Value
 ----		       -----		  -------		-------------
 autoRedisplay         AutoRedisplay      Boolean         True
 background	       Background	  Pixel		  XtDefaultBackground
 blackStoneBackground  Background	  Pixel		  black
 blackStoneBorder      BorderColor	  Pixel		  black
 blackStoneForeground  Foreground	  Pixel		  white
 border		       BorderColor	  Pixel		  XtDefaultForeground
 borderWidth	       BorderWidth	  Dimension	  1
 cursor                Cursor             Integer         GbGrayCursor
 destroyCallback       Callback		  Pointer	  NULL
 displayCoordinates    DisplayCoordinates Boolean	  True
 font                  Font               XFontStruct*    fixed
 foreground            Foreground         Pixel           XtDefaultForeground
 gameSize              Size               Dimension       19
 height		       Height		  Dimension	  computed at create
 mappedWhenManaged     MappedWhenManaged  Boolean	  True
 pointSize             Size               Dimension       24
 sensitive	       Sensitive	  Boolean	  True
 viewBottom            Position           Position        computed at create
 viewLeft              Position           Position        computed at create
 viewRight             Position           Position        computed at create
 viewTop               Position           Position        computed at create
 whiteStoneBackground  Background	  Pixel		  white
 whiteStoneBorder      BorderColor	  Pixel		  black
 whiteStoneForeground  Foreground	  Pixel		  black
 width		       Width		  Dimension	  computed at create
 x		       Position		  Position	  0
 y		       Position		  Position	  0
*/

/* define any special resource names here that are not in <X11/StringDefs.h> */

#define XtNautoRedisplay         "autoRedisplay"
#define XtNviewBottom            "viewBottom"

#ifndef XtNcursor
#define XtNcursor                "cursor"
#endif

#define XtNgameSize              "gameSize"
#define XtNviewLeft              "viewLeft"
#define XtNdisplayCoordinates    "displayCoordinates"
#define XtNpointSize             "pointSize"
#define XtNstipple               "stipple"
#define XtNviewRight             "viewRight"
#define XtNviewTop               "viewTop"
#define XtNblackStoneBorder      "blackStoneBorder"
#define XtNblackStoneForeground  "blackStoneForeground"
#define XtNblackStoneBackground  "blackStoneBackground"
#define XtNwhiteStoneBorder      "whiteStoneBorder"
#define XtNwhiteStoneForeground  "whiteStoneForeground"
#define XtNwhiteStoneBackground  "whiteStoneBackground"

#define XtCAutoRedisplay         "AutoRedisplay"
#define XtCDisplayCoordinates    "DisplayCoordinates"
#define XtCSize                  "Size"
#define XtCStipple               "Stipple"

#define XtEgbWhiteStone          "white"
#define XtEgbBlackStone          "black"
#define XtEgbGrayStone           "gray"

/* declare specific GobanWidget class and instance datatypes */

typedef struct _GobanClassRec*	 GobanWidgetClass;
typedef struct _GobanRec*	 GobanWidget;

/* declare the class constant */

extern WidgetClass gobanWidgetClass;

/* cursors */

#define GbCGrayStone         256
#define GbCBlackStone        257
#define GbCWhiteStone        258

/* special marks */

#define GbMSquareMark        1
#define GbMTriangleMark      2
#define GbMVCrossMark        3
#define GbMDCrossMark        4
#define GbMDiamondMark       5

/* colors */

typedef enum { GbEmptyPoint, GbBlackStone, GbWhiteStone } GbPointState;

/* user functions */

#define GbRemoveMark(w,x,y)  GbSetMark (w, x, y, 0, 0)

extern void GbRedisplayBoard ( /* Widget w */ );
extern void GbClearBoard     ( /* Widget w */ );
extern void GbSetPoint       ( /* Widget w, Position x, Position y, GbPointState color */ );
extern void GbSetNum         ( /* Widget w, Position x, Position y, int num   */ );
extern void GbSetMark        ( /* Widget w, Position x, Position y, unsigned char mark1, unsigned char mark2 */ );

extern Boolean GbGetPositionFromStone ( /* Widget w, Position *x, Position *y */ );
extern Boolean GbGetStoneFromPosition ( /* Widget w, Position *x, Position *y */ );

#endif /* _Goban_h */

SHAR_EOF
fi
if test -f 'GobanP.h'
then
	echo shar: "will not over-write existing file 'GobanP.h'"
else
cat << \SHAR_EOF > 'GobanP.h'
/****************************************************************************************************************
 *
 *  Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behaviour
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    dumesnil@etca.fr   or to:
 *       
 *       Antoine de Maricourt
 *       ETCA CREA-SP
 *       16 bis, avenue Prieur de la Cote d'Or
 *       94114 Arcueil Cedex
 *       France
 */

#ifndef _GobanP_h
#define _GobanP_h

#include "Goban.h"

/* include superclass private header file */
#include <X11/CoreP.h>

/* define unique representation types not found in <X11/StringDefs.h> */

#define XtRGobanResource "GobanResource"

typedef struct {
    int empty;
} GobanClassPart;

typedef struct _GobanClassRec {
    CoreClassPart	core_class;
    GobanClassPart	goban_class;
} GobanClassRec;

extern GobanClassRec gobanClassRec;

typedef struct {
  unsigned int free  : 1;
  unsigned int black : 1;
  unsigned int mark1 : 8;
  unsigned int mark2 : 8;
  unsigned int num   : 10;
} PointState;

typedef struct {
    /* resources */

  Boolean       auto_redisplay;
  Position      bottom;
  int           cursor;
  XFontStruct  *font;
  Pixel         foreground;
  Dimension     game_size;
  Position      left;
  Boolean       display_coordinates;
  Dimension     point_size;
  Boolean       stipple;
  Position      right;
  Position      top;

    /* private state */

  PointState    points[20][20];
  Position      x_offset;
  Position      y_offset;

  Pixmap        black_stone;
  Pixmap        board;
  Pixmap        gray_stone;
  Pixmap        mouse_mask;
  Pixmap        picture;
  Pixmap        white_stone;

  GC            background_gc;
  GC            foreground_gc;
  GC            black_fg_gc;
  GC            black_bg_gc;
  GC            black_bd_gc;
  GC            white_fg_gc;
  GC            white_bg_gc;
  GC            white_bd_gc;
  GC            copy_gc;

  Cursor        black_cursor;
  Cursor        gray_cursor;
  Cursor        white_cursor;
  Cursor        font_cursor;

  Pixel         white_bg;
  Pixel         white_fg;
  Pixel         white_bd;
  Pixel         black_bg;
  Pixel         black_fg;
  Pixel         black_bd;
} GobanPart;

typedef struct _GobanRec {
    CorePart    core;
    GobanPart	goban;
} GobanRec;

#define Min(x,y)      ((x) > (y) ? (y) : (x))
#define Max(x,y)      ((x) > (y) ? (x) : (y))

#endif /* _GobanP_h */
SHAR_EOF
fi
if test -f 'Imakefile'
then
	echo shar: "will not over-write existing file 'Imakefile'"
else
cat << \SHAR_EOF > 'Imakefile'
/* Imakefile for xigc v2.1
 * S.Coffin    USWAT   1/93
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behaviour
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

LOCAL_LIBRARIES = XawClientLibs
SRCS1= Goban.c xigc.c filter.c pipes.c board.c
OBJS1= Goban.o xigc.o filter.o pipes.o board.o

SRCS2= igscomm.c
OBJS2= igscomm.o

PROGRAMS = xigc igscomm

ComplexProgramTarget_1 (xigc, $(LOCAL_LIBRARIES), )
ComplexProgramTarget_2 (igscomm,, )
InstallAppDefaults(XIgc)
InstallManPage(xigc,$(MANDIR))
SHAR_EOF
fi
if test -f 'Makefile.hand'
then
	echo shar: "will not over-write existing file 'Makefile.hand'"
else
cat << \SHAR_EOF > 'Makefile.hand'
# Makefile.hand
# S.Coffin  USWAT  12/92
#
# this is a hand-created makefile for xigc v2.1
# if your machine does not have "imake" or "xmkmf"
# you may be able to hack this up to adapt it to your system
# good luck

CFLAGS= -O -I/usr/include/X11
XLIBS= -L/usr/lib -lXaw -lXmu -lXt -lXext -lX11 -lm
 
SRCS1= Goban.c xigc.c filter.c pipes.c board.c
OBJS1= Goban.o xigc.o filter.o pipes.o board.o
HEAD1= filter.h Goban.h GobanP.h patchlevel.h shared.h

SRCS2= igscomm.c
OBJS2= igscomm.o
HEAD2= igscomm.h

all: xigc igscomm

xigc:	$(OBJS1)
	cc -o xigc $(OBJS1) $(XLIBS)

igscomm:	$(OBJS2)
	cc -o igscomm $(OBJS2)

clean:
	rm -f $(OBJS1) $(OBJS2) core xigc igscomm

$(OBJS1):	$(HEAD1)

$(OBJS2):	$(HEAD2)
SHAR_EOF
fi
if test -f 'Makefile.sun'
then
	echo shar: "will not over-write existing file 'Makefile.sun'"
else
cat << \SHAR_EOF > 'Makefile.sun'
# This is a sample Makefile for xigc v2.1, generated by "xmkmf"
# for the Sun SparcStation, SunOS 4.1.2, X11R5 pl 18
# You will probably not be able to use this without modification =SC 1/93

# Makefile generated by imake - do not edit!
# $XConsortium: imake.c,v 1.72 92/09/14 11:44:22 rws Exp $
#
# The cpp used on this machine replaces all newlines and multiple tabs and
# spaces in a macro expansion with a single space.  Imake tries to compensate
# for this, but is not always successful.
#

# -------------------------------------------------------------------------
# Makefile generated from "Imake.tmpl" and <Imakefile>
# $XConsortium: Imake.tmpl,v 1.139 91/09/16 08:52:48 rws Exp $
#
# Platform-specific parameters may be set in the appropriate <vendor>.cf
# configuration files.  Site-specific parameters should be set in the file
# site.def.  Full rebuilds are recommended if any parameters are changed.
#
# If your C preprocessor does not define any unique symbols, you will need
# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
# "make World" the first time).
#

# -------------------------------------------------------------------------
# site-specific configuration parameters that need to come before
# the platform-specific parameters - edit site.def to change

# site:  $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $

# -------------------------------------------------------------------------
# platform-specific configuration parameters - edit sun.cf to change

# platform:  $XConsortium: sun.cf,v 1.71 91/12/20 11:18:34 rws Exp $

# operating system:  SunOS 4.1.1

# $XConsortium: sunLib.rules,v 1.7 91/12/20 11:19:47 rws Exp $

# -------------------------------------------------------------------------
# site-specific configuration parameters that go after
# the platform-specific parameters - edit site.def to change

# site:  $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $

            SHELL = /bin/sh

              TOP = .
      CURRENT_DIR = .

               AR = ar cq
  BOOTSTRAPCFLAGS =
               CC = cc
               AS = as

         COMPRESS = compress
              CPP = /lib/cpp $(STD_CPP_DEFINES)
    PREPROCESSCMD = cc -E $(STD_CPP_DEFINES)
          INSTALL = install
               LD = ld
             LINT = lint
      LINTLIBFLAG = -C
         LINTOPTS = -axz
               LN = ln -s
             MAKE = make
               MV = mv
               CP = cp

           RANLIB = ranlib
  RANLIBINSTFLAGS =

               RM = rm -f
            TROFF = psroff
         MSMACROS = -ms
              TBL = tbl
              EQN = eqn
     STD_INCLUDES =
  STD_CPP_DEFINES =
      STD_DEFINES =
 EXTRA_LOAD_FLAGS =
  EXTRA_LIBRARIES =
             TAGS = ctags

    SHAREDCODEDEF = -DSHAREDCODE
         SHLIBDEF = -DSUNSHLIB

    PROTO_DEFINES =

     INSTPGMFLAGS = -s

     INSTBINFLAGS = -m 0755
     INSTUIDFLAGS = -m 4755
     INSTLIBFLAGS = -m 0644
     INSTINCFLAGS = -m 0444
     INSTMANFLAGS = -m 0444
     INSTDATFLAGS = -m 0444
    INSTKMEMFLAGS = -g kmem -m 2755

      PROJECTROOT = /usr/local/X11

     TOP_INCLUDES = -I$(INCROOT)

      CDEBUGFLAGS = -O
        CCOPTIONS = -pipe

      ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(STD_INCLUDES)
       ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(EXTRA_DEFINES) $(PROTO_DEFINES) $(DEFINES)
           CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES)
        LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES)

           LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)

        LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) $(LOCAL_LDFLAGS) -L$(USRLIBDIR)

   LDCOMBINEFLAGS = -X -r
      DEPENDFLAGS =

        MACROFILE = sun.cf
           RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut

    IMAKE_DEFINES =

         IRULESRC = $(CONFIGDIR)
        IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES)

     ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \
			$(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \
			$(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES)

# -------------------------------------------------------------------------
# X Window System Build Parameters
# $XConsortium: Project.tmpl,v 1.138 91/09/10 09:02:12 rws Exp $

# -------------------------------------------------------------------------
# X Window System make variables; this need to be coordinated with rules

          PATHSEP = /
        USRLIBDIR = /usr/local/X11/lib
           BINDIR = /usr/local/X11/bin
          INCROOT = /usr/local/X11/include
     BUILDINCROOT = $(TOP)
      BUILDINCDIR = $(BUILDINCROOT)/X11
      BUILDINCTOP = ..
           INCDIR = $(INCROOT)/X11
           ADMDIR = /usr/adm
           LIBDIR = $(USRLIBDIR)/X11
        CONFIGDIR = $(LIBDIR)/config
       LINTLIBDIR = $(USRLIBDIR)/lint

          FONTDIR = $(LIBDIR)/fonts
         XINITDIR = $(LIBDIR)/xinit
           XDMDIR = $(LIBDIR)/xdm
           TWMDIR = $(LIBDIR)/twm
          MANPATH = /usr/local/X11/man
    MANSOURCEPATH = $(MANPATH)/man
        MANSUFFIX = 1
     LIBMANSUFFIX = 3
           MANDIR = $(MANSOURCEPATH)$(MANSUFFIX)
        LIBMANDIR = $(MANSOURCEPATH)$(LIBMANSUFFIX)
           NLSDIR = $(LIBDIR)/nls
        PEXAPIDIR = $(LIBDIR)/PEX
      XAPPLOADDIR = $(LIBDIR)/app-defaults
       FONTCFLAGS = -t

     INSTAPPFLAGS = $(INSTDATFLAGS)

            IMAKE = imake
           DEPEND = makedepend
              RGB = rgb

            FONTC = bdftopcf

        MKFONTDIR = mkfontdir
        MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier

        CONFIGSRC = $(TOP)/config
       DOCUTILSRC = $(TOP)/doc/util
        CLIENTSRC = $(TOP)/clients
          DEMOSRC = $(TOP)/demos
           LIBSRC = $(TOP)/lib
          FONTSRC = $(TOP)/fonts
       INCLUDESRC = $(TOP)/X11
        SERVERSRC = $(TOP)/server
          UTILSRC = $(TOP)/util
        SCRIPTSRC = $(UTILSRC)/scripts
       EXAMPLESRC = $(TOP)/examples
       CONTRIBSRC = $(TOP)/../contrib
           DOCSRC = $(TOP)/doc
           RGBSRC = $(TOP)/rgb
        DEPENDSRC = $(UTILSRC)/makedepend
         IMAKESRC = $(CONFIGSRC)
         XAUTHSRC = $(LIBSRC)/Xau
          XLIBSRC = $(LIBSRC)/X
           XMUSRC = $(LIBSRC)/Xmu
       TOOLKITSRC = $(LIBSRC)/Xt
       AWIDGETSRC = $(LIBSRC)/Xaw
       OLDXLIBSRC = $(LIBSRC)/oldX
      XDMCPLIBSRC = $(LIBSRC)/Xdmcp
      BDFTOSNFSRC = $(FONTSRC)/bdftosnf
      BDFTOSNFSRC = $(FONTSRC)/clients/bdftosnf
      BDFTOPCFSRC = $(FONTSRC)/clients/bdftopcf
     MKFONTDIRSRC = $(FONTSRC)/clients/mkfontdir
         FSLIBSRC = $(FONTSRC)/lib/fs
    FONTSERVERSRC = $(FONTSRC)/server
     EXTENSIONSRC = $(TOP)/extensions
         XILIBSRC = $(EXTENSIONSRC)/lib/xinput
      PHIGSLIBSRC = $(EXTENSIONSRC)/lib/PEX

# $XConsortium: sunLib.tmpl,v 1.14.1.1 92/03/17 14:58:46 rws Exp $

SHLIBLDFLAGS = -assert pure-text
PICFLAGS = -pic

  DEPEXTENSIONLIB =
     EXTENSIONLIB = -lXext

          DEPXLIB = $(DEPEXTENSIONLIB)
             XLIB = $(EXTENSIONLIB) -lX11

        DEPXMULIB = $(USRLIBDIR)/libXmu.sa.$(SOXMUREV)
       XMULIBONLY = -lXmu
           XMULIB = -lXmu

       DEPOLDXLIB =
          OLDXLIB = -loldX

      DEPXTOOLLIB = $(USRLIBDIR)/libXt.sa.$(SOXTREV)
         XTOOLLIB = -lXt

        DEPXAWLIB = $(USRLIBDIR)/libXaw.sa.$(SOXAWREV)
           XAWLIB = -lXaw

        DEPXILIB =
           XILIB = -lXi

        SOXLIBREV = 4.10
          SOXTREV = 4.10
         SOXAWREV = 5.0
        SOOLDXREV = 4.10
         SOXMUREV = 4.10
        SOXEXTREV = 4.10
      SOXINPUTREV = 4.10

      DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
         XAUTHLIB =  -lXau
      DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a
         XDMCPLIB =  -lXdmcp

        DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a
           PHIGSLIB =  -lphigs

       DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a
          XBSDLIB =  -lXbsd

 LINTEXTENSIONLIB = $(LINTLIBDIR)/llib-lXext.ln
         LINTXLIB = $(LINTLIBDIR)/llib-lX11.ln
          LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln
        LINTXTOOL = $(LINTLIBDIR)/llib-lXt.ln
          LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln
           LINTXI = $(LINTLIBDIR)/llib-lXi.ln
        LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln

          DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)

         DEPLIBS1 = $(DEPLIBS)
         DEPLIBS2 = $(DEPLIBS)
         DEPLIBS3 = $(DEPLIBS)

# -------------------------------------------------------------------------
# Imake rules for building libraries, programs, scripts, and data files
# rules:  $XConsortium: Imake.rules,v 1.123 91/09/16 20:12:16 rws Exp $

# -------------------------------------------------------------------------
# start of Imakefile

LOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
SRCS1= Goban.c xigc.c filter.c pipes.c board.c
OBJS1= Goban.o xigc.o filter.o pipes.o board.o

SRCS2= igscomm.c
OBJS2= igscomm.o

PROGRAMS = xigc igscomm

 OBJS = $(OBJS1) $(OBJS2) $(OBJS3)
 SRCS = $(SRCS1) $(SRCS2) $(SRCS3)

all:: $(PROGRAMS)

xigc: $(OBJS1) $(DEPLIBS1)
	$(RM) $@
	$(CC) -o $@ $(LDOPTIONS) $(OBJS1)  $(LOCAL_LIBRARIES) $(LDLIBS)   $(EXTRA_LOAD_FLAGS)

install:: xigc
	@if [ -d $(DESTDIR)$(BINDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(BINDIR)); fi
	$(INSTALL) -c $(INSTPGMFLAGS)  xigc $(DESTDIR)$(BINDIR)

install.man:: xigc.man
	@if [ -d $(DESTDIR)$(MANDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(MANDIR)); fi
	$(INSTALL) -c $(INSTMANFLAGS) xigc.man $(DESTDIR)$(MANDIR)/xigc.$(MANSUFFIX)

saber_xigc:: $(SRCS1)
	# load $(ALLDEFINES) $(SRCS1)  $(LOCAL_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)

osaber_xigc:: $(OBJS1)
	# load $(ALLDEFINES) $(OBJS1)  $(LOCAL_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)

depend::
	$(DEPEND) $(DEPENDFLAGS) -s "# DO NOT DELETE" -- $(ALLDEFINES) -- $(SRCS)

lint:
	$(LINT) $(LINTFLAGS) $(SRCS) $(LINTLIBS)
lint1:
	$(LINT) $(LINTFLAGS) $(FILE) $(LINTLIBS)

clean::
	$(RM) $(PROGRAMS)

igscomm: $(OBJS2) $(DEPLIBS2)
	$(RM) $@
	$(CC) -o $@ $(LDOPTIONS) $(OBJS2)  $(LDLIBS)   $(EXTRA_LOAD_FLAGS)

saber_igscomm:: $(SRCS2)
	# load $(ALLDEFINES) $(SRCS2)  $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)

osaber_igscomm:: $(OBJS2)
	# load $(ALLDEFINES) $(OBJS2)  $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)

install:: igscomm
	@if [ -d $(DESTDIR)$(BINDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(BINDIR)); fi
	$(INSTALL) -c $(INSTPGMFLAGS)  igscomm $(DESTDIR)$(BINDIR)

install.man:: igscomm.man
	@if [ -d $(DESTDIR)$(MANDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(MANDIR)); fi
	$(INSTALL) -c $(INSTMANFLAGS) igscomm.man $(DESTDIR)$(MANDIR)/igscomm.$(MANSUFFIX)

install:: XIgc.ad
	@if [ -d $(DESTDIR)$(XAPPLOADDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(XAPPLOADDIR)); fi
	$(INSTALL) -c $(INSTAPPFLAGS) XIgc.ad $(DESTDIR)$(XAPPLOADDIR)/XIgc

install.man:: xigc.man
	@if [ -d $(DESTDIR)$(MANDIR) ]; then set +x; \
	else (set -x; $(MKDIRHIER) $(DESTDIR)$(MANDIR)); fi
	$(INSTALL) -c $(INSTMANFLAGS) xigc.man $(DESTDIR)$(MANDIR)/xigc.$(MANSUFFIX)

# -------------------------------------------------------------------------
# common rules for all Makefiles - do not edit

emptyrule::

clean::
	$(RM_CMD) "#"*

Makefile::
	-@if [ -f Makefile ]; then set -x; \
	$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
	else exit 0; fi
	$(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)

tags::
	$(TAGS) -w *.[ch]
	$(TAGS) -xw *.[ch] > TAGS

saber:
	# load $(ALLDEFINES) $(SRCS)

osaber:
	# load $(ALLDEFINES) $(OBJS)

# -------------------------------------------------------------------------
# empty rules for directories that do not have SUBDIRS - do not edit

install::
	@echo "install in $(CURRENT_DIR) done"

install.man::
	@echo "install.man in $(CURRENT_DIR) done"

Makefiles::

includes::

# -------------------------------------------------------------------------
# dependencies generated by makedepend

SHAR_EOF
fi
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
This is xigc Release v2.1 of 1/93

========================================================================

See "xigc.man" for full documentation and installation instructions.
Use "nroff -man xigc.man" to look at the file at your terminal, or
something like "troff -man xigc.man | lpr" to print it at your printer.

Installation instructions:

After unpacking the source distribution, use "xmkmf" followed by
"make depend" to generate a Makefile for your environment.  
If you do not have "xmkmf" or "imake," you may be able to adapt the file
"Makefile.hand," and use it as a Makefile for your system.  Then type
"make" and then "make install" to install xigc and igscomm in your
standard locations.

Make sure the file "XIgc.ad" is placed in your standard place for X11
application defaults (and named "XIgc") or added to your ".Xdefaults."
You can also do "xrdb -merge XIgc.ad" after you start X but before
running xigc.  You must do one of these things or xigc will not run!
"make install" should install this file correctly.

========================================================================
	
Known Bugs and Major Problems:
	1.  This release includes several patches to help solve the "spinning
		telnet" or "hanging server" problem.  BUT:  There are still
		pathological cases where xigc can die leaving the telnet
		process running.  I STRONGLY recommend that you use igscomm
		instead of telnet as your communications program with xigc,
		as igscomm is not subject to this serious problem.
	2.  Sometimes a move is lost during Refresh(Host):  move 29 and/or 62,
		92, 128.  Never other moves apparently.  This only happens
		with telnet, and is another reason to use igscomm instead
		of telnet.
	3.  xigc should compile and run correctly with any installation of
		MIT X11R4 or X11R5 on any machine (including VMS!).  However,
		it seems that some IBM and DEC versions of X do not include
		the libXaw (Arrogant IBM thinks that their stupid Motif
		widgets replace the Athena widgets).  Also, xigc may not
		compile or run on X11R3 or earlier releases of X, or on some
		versions of SVR3 for 386 machines.  I have also heard some
		problems compiling on AIX 3.1, though 3.15 and 3.2 should
		work if you have the Athena widgets.  In any case, you should
		try building xigc anyway; it might work....
	4.  The second-by-second timer is a LOCAL timer in the xigc
		application.  It is only an approximation of the official
		time, which is kept by the server.  The time display may
		differ by a few seconds from the official time under some
		conditions.
	5.  Some systems are set up with a gateway, so that your machine
		is not directly connected to the internet.  Many universities
		and large businesses do this.  In this case, the local
		version of telnet connects first to the gateway, then out
		over the internet to IGS.  If you have this type of setup,
		you will not be able to use igscomm.  Normally when this
		happens xigc will just end immediately, possibly with a
		message like "host 128... not found."  If this happens to
		you, you will have to use telnet for your communications
		program with xigc.  You can continue to use the xigc "-c"
		command-line option, or place your communications command
		line in your .xigcrc file.  See xigc.man for more information.
		You might also be able to use "rlogin" or "cu" to connect to
		your gateway machine, and then run igscomm from there.
	6.  Some systems have some problems with the feature that allows
		you to type to the IGS command processor while the mouse
		cursor is over the board or menu window.  If you get an
		error message like this when you start xigc:

		X Error of failed request: BadAccess (attempt to access
			private resource denied)
		Major opcode of failed request:  33 (X_GrabKey)
		Serial number of failed request:  xxx
		Current serial number in output stream:  xxx

		If you see this message, you will have to recompile xigc.
		Edit the file xigc.c, and uncomment the line

		#ifndef NOKEYGRAB

		near the top of xigc.c.  Then recompile.  This will disable
		the feature, but will allow xigc to run on your machine.
	7.  If you have the board size too small (smaller than about 400
		pixels), the end-of-game scoring will not appear.  This is
		an automatic feature of the Goban widget.  To see the scoring
		marks, you can use a larger board or select a smaller font
		in your application defaults.

=======================================================================

Other Bugs, New Features and Improvements Needed:
	1.  Get passwd (cntrl-P) handling for xterm window
		integrate chars coming in via stdin with chars coming in
		via X
	2.  stipple in config file or X resource?
		1.  All config stuff in X resources?
	3.  thist output sometimes munged.
	4.  Better sgf save of button 3 variations?
	5.  Display komi and player rank in xigc menu
	6.  Beep or other warning at 1 minute before time runs out?
		Or user can set beep interval in config file?
	7.  Board size in app defaults; support other than 9, 13, and 19 lines?
	8.  observeoff in menu; switch game with "observe n" so observeoff
		not always required?
	9.  Include komi in final end-of-game point count?

=======================================================================

Changes in xigc from v2.0 to v2.1:
	1.  Fix so xigc does not try to change game numbers automatically.
	2.  Fix several minor bugs.
	3.  Remove last move dot for "status" display.
	4.  Fix several bugs in sgf save format.
	5.  Upgrade support for "status" "look" and "translate" to chase
		the latest IGS changes.
	6.  Fix a bug that occasionally caused xigc to exit unexpectedly
		during "Refresh (Host)" of games with more than about
		180 moves.
	7.  Force 7-bit characters so xigc works correctly with 8-bit
		communications programs and modems.

Changes in xigc from v1.9 to v2.0:
	1.  Fix several minor bugs.
	2.  Fix bug that caused multiple undos that include replacing
		captured stones to not redraw screen correctly.
	3.  Fix problem with move numbering when saving games with
		"Save to Current"
	4.  Improve file handling during Save Game.
	5.  Add more app-defaults to control window size, font, etc,
		for the Menu window.

Changes in xigc from v1.8 to v1.9:
	1.  Fix bug that caused real incoming moves to participate in
		captures during button 3 sequences.
	2.  Fix Imakefile problem that caused NullParameter error during
		make on X11R4 systems.
	3.  Fix bug that prevented setting sgf format in .xigcrc file.
	4.  Upgrade end-of-game processing to show final board with
		scored points marked.
	5.  Fix several minor bugs.

Changes in xigc from v1.0 to v1.8:
	1.  Add explicit kill for comm program when xigc exits, and several
		other fixes related to the "spinning telnet" or "hanging
		server" problem.  But, I strongly recommend that "igscomm"
		is used instead of telnet for communications with xigc.
		igscomm is not subject to the hanging server problem, since
		it exits when xigc exits.
	2.  Fix many minor bugs.
	3.  Remove gameSize default from XIgc.ad.  It is hardcoded to
		default to 19.
	4.  Add second-by-second timer.
	5.  Add ability to type to IGS command processor while mouse is in
		board or menu windows.  You can also type CNTRL-P to shut off
		echoing for a line (this allows passwords to not print).
		The CNTRL-P feature currently only works when the cursor is
		over the board or menu, NOT when the cursor is in the text
		window.  Thanks to loganj@byu.edu for providing some sample
		code implementing this feature.
	6.  Upgrade to latest version of the Goban widget.  This fixes some
		cases where the cursor was an empty circle inside a square,
		rather than an image of white or black stone.
	7.  Add a config file to put comm command line, so it is not required
		on xigc command line or compiled in.
	8.  Add ability to save game in text format or SGF format.
	9.  Much improved game analysis functions, including the ability to
		step through games move-by-move, to add stones to the board
		from any move position, and to refresh to the current "step"
		or to the current "real" game position.
	10. Much improved end-of-game and scoring support.
	11. Support for the IGS "status" command.  You can now look at the
		current board position of another game while playing or
		observing.


Changes in xigc from v0.9 to v1.0:
	
	1.  Fix a bug where dead stones were not always picked up correctly
		on the first "refresh" after xigc started.
	2.  Add an app default to select whether button 3 moves are
		saved locally or not.
	3.  Fix handling of "Pass" during games.
	4.  Get rid of junk line that was printed when Bell is enabled at IGS.
	5.  Fix some char passing problems in igscomm.
	6.  Add the ability for igscomm to suppress local echo.
	7.  Add code to make "refresh" command do something useful.
	8.  Make "Pass" and "undo" moves appear in "Last:" window item.


Changes in xigc from v0.8 to v0.9:

	1.  Add a simple Makefile so that users without imake or xmkmf have
		a chance.
	2.  Fix a bug associated with getopt() on the IBM RS6000.
	3.  Change the default command from "telnet lacerta.unm.edu 6969"
		to "telnet 129.24.14.70 6969".
	4.  Clear and refresh the board when starting to play a game.
	5.  Button 3 sequences are no longer saved as part of the game, and
		are cleared with "Refresh (Local)".  This also means that
		they are not saved to a file with "Save Moves".
	6.  Change the "highlite" on the last-played stone so it stays
		centered better for all board dimensions.
	7.  Disable the "Quit" menu item when the "-c" command-line option is
		used, since xigc will not know how to exit cleanly from any
		random user-specified communications command.
	8.  Add a stipple-gray board background selected by command-line
		option or app default.  You have a compile-time choice of
		either of two stipple patterns.
	9.  Fix the declaration of "time_t" so it compiles on SGI machines.

=======================================================================
SHAR_EOF
fi
if test -f 'XIgc.ad'
then
	echo shar: "will not over-write existing file 'XIgc.ad'"
else
cat << \SHAR_EOF > 'XIgc.ad'
XIgc*goban*foreground         : black
XIgc*goban*blackStoneBackground         : black
XIgc*goban*blackStoneForeground         : white
XIgc*goban*whiteStoneBackground         : white
XIgc*goban*whiteStoneForeground         : black
XIgc*goban*blackStoneBorder   : black
XIgc*Goban*whiteStoneBorder   : black
XIgc*goban*autoRedisplay      : true
XIgc*goban*background         : tan1
XIgc*goban*stipple	      : false
XIgc*goban*borderWidth        : 2
XIgc*goban*displayCoordinates : true
XIgc*font                     : -adobe-new century schoolbook-bold-r-*-*-12-*-*-*-*-*-*-*
XIgc*goban*font               : -adobe-new century schoolbook-bold-r-*-*-12-*-*-*-*-*-*-*
XIgc*goban*pointSize          : 24
XIgc*goban*viewBottom         : 3
XIgc*goban*viewLeft           : 5
XIgc*goban*viewRight          : 9
XIgc*goban*width              : 400
XIgc*goban*height             : 400
XIgc*goban*viewTop            : 12
XIgc*board.geometry           : -1+1
XIgc*Goban.translations       : #augment \n\
			   	<Btn1Down> : inputStone() \n\
			   	<Btn2Down> : removeStone() \n\
			   	<Btn3Down> : addStone()

XIgc*geometry                 : -1-1
XIgc*background               : tan1
XIgc*Label*foreground         : black
XIgc*Command*foreground       : blue
XIgc*Command*width            : 148
XIgc*Label*width              : 148
XIgc*lastw.width              : 302

XIgc*refresh.label            : Refresh (Host)
XIgc*cursorcolor.label        : Change Color
XIgc*clearb.label             : Clear
XIgc*stepf.label              : Step Forward
XIgc*stepb.label              : Step Back
XIgc*refreshstep.label        : Refresh to Step
XIgc*localrefresh.label       : Refresh (Local)
XIgc*size.label               : Change Size
XIgc*savegame.label           : Save Game
XIgc*savecurrent.label        : Save to Current
XIgc*coordinates.label        : Display Coordinates
XIgc*quit.label               : Quit

XIgc*hcapw.fromHoriz	      : gamew
XIgc*whitew.fromVert          : gamew
XIgc*blackw.fromVert          : gamew
XIgc*blackw.fromHoriz         : whitew
XIgc*captw.fromVert           : whitew
XIgc*captb.fromVert           : blackw
XIgc*captb.fromHoriz          : captw
XIgc*timew.fromVert           : captw
XIgc*timeb.fromVert           : captb
XIgc*timeb.fromHoriz          : timew
XIgc*lastw.fromVert           : timew

XIgc*refresh.fromVert         : lastw
XIgc*cursorcolor.fromVert     : refresh
XIgc*clearb.fromVert          : cursorcolor
XIgc*stepf.fromVert           : clearb
XIgc*stepb.fromVert           : stepf
XIgc*refreshstep.fromVert     : stepb
XIgc*localrefresh.fromVert    : lastw
XIgc*localrefresh.fromHoriz   : refresh
XIgc*size.fromVert            : localrefresh
XIgc*size.fromHoriz	      : cursorcolor
XIgc*savegame.fromVert        : size
XIgc*savegame.fromHoriz	      : clearb
XIgc*savecurrent.fromVert     : savegame
XIgc*savecurrent.fromHoriz    : stepf
XIgc*coordinates.fromVert     : savecurrent
XIgc*coordinates.fromHoriz    : stepb
XIgc*quit.fromVert            : coordinates
XIgc*quit.fromHoriz           : refreshstep
SHAR_EOF
fi
if test -f 'blackstone.bm'
then
	echo shar: "will not over-write existing file 'blackstone.bm'"
else
cat << \SHAR_EOF > 'blackstone.bm'
#define blackstone_width 16
#define blackstone_height 16
#define blackstone_x_hot 7
#define blackstone_y_hot 8
static unsigned char blackstone_bits[] = {
   0xc0, 0x03, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xef, 0xfe, 0x77, 0xfe, 0x7b,
   0xfc, 0x3c, 0xf8, 0x1f, 0xf0, 0x0f, 0xc0, 0x03};
SHAR_EOF
fi
if test -f 'board.c'
then
	echo shar: "will not over-write existing file 'board.c'"
else
cat << \SHAR_EOF > 'board.c'
/* board.c
 * S.Coffin	USWAT	1/93
 *
 * adapted from adrian@u.washington.edu [with significant changes]
 * keeps local copy of board state, dead stone removal, handicaps, etc
 */

#include <stdio.h>
#include <time.h>
#include "shared.h"
#include "filter.h"

extern int drawStone();
extern int move, currentmove;
extern int boardchanged, mouseflag;
extern int beep();
static int tt;
void removeStones();

typedef char boardtype[20][20];
int prisoners[2], stepprisoners[2];

struct movelist {
   int x, y;
   unsigned char flag;
};

static struct movelist realmovelist[MAXMOVE], stepmovelist[MAXMOVE];

boardtype board, stepboard;

#define boolean unsigned char
#define false 0
#define true 1

#define piece char

static int boardsize = 19;


clearboard( b, pris )
	boardtype b;
	int *pris;
{
	int i, j;
	pris[0] = pris[1] = 0;
	for (i = 0; i < boardsize; i++)
	for (j = 0; j < boardsize; j++)
	    b[i][j] = EMPTY;
}

clear_stepboard() {
	clearboard(stepboard, stepprisoners);
}

initboard( size )
	char size;
{
	boardsize = size;
	clearboard(board, prisoners);
	clearboard(stepboard, stepprisoners);
}

char *stamptime()
{
	char *asctime();                /* stuff to get timestamp */
	struct tm *localtime(), *tp;
	struct timeval tv;
	struct timezone tz;

	gettimeofday (&tv, &tz);                /* fill in timestamp */
	tp = localtime ((time_t *)&tv.tv_sec);
	return(asctime(tp));
}

/* save game in sgf format */
save_game_sgf( s, p1, p2, hcap, type )
	char *s;	/* file name to save to */
	char *p1, *p2;	/* player names */
	int hcap;	/* handicap stones or 0 */
	int type;	/* save REALMOVES or STEPMOVES */
{
	FILE *fp;
	int i, x, y;
	char *str;
	int m;
	struct movelist *ml;

	if( type == REALMOVE ) {
	    m = move;
	    ml = realmovelist;
	}
	else if( type == STEPMOVE ) {
	    m = currentmove;
	    ml = stepmovelist;
	}

	if( (fp = fopen( s, "a+" )) == NULL ) {
		perror( "savegame" );
		return( 0 );
	}
	fprintf( fp, "(\n;\nPlayerBlack[%s]\nPlayerWhite[%s]\n",
			p2, p1 );
	str = stamptime();
	str[strlen(str)-1] = '\0';
	fprintf( fp, "GaMe[1]\n" );
	fprintf( fp, "VieW[]\n" );
	fprintf( fp, "EVent[]\n" );
	fprintf( fp, "DaTe[%s]\n", str );
	fprintf( fp, "SiZe[%d]\n", boardsize );
	fprintf( fp, "PlaCe[IGS]\n", boardsize );
	if( hcap ) fprintf( fp, "HAndicap[%d]\n", hcap );
	fprintf( fp, "KoMi[??]\n" );
	fprintf( fp, "USer[File created by IGS and xigc]\n" );

	if( hcap != 0 ) {
	    sgf_hcap( fp, boardsize, hcap );
	    i = 1;
	}
	else i = 0;

	fprintf( fp, ";\n" );

	for( ; i <= m; ++i ) {
	    x = ml[i].x + 1;
	    y = ml[i].y + 1;
	    if( x < 0 ) {		/* pass */
	        fprintf( fp, "%s[tt]\n;\n", (i%2) ? "White" : "Black" );
	    }
	    else {			/* real move */
	        fprintf( fp, "%s[%c%c]\n;\n", (i%2) ? "White" : "Black",
				'a' + (char)x - 1,
				'a' + (char)(19 - y) );
	    }
	}

	fprintf( fp, ")\n" );

	fclose( fp );
	return( 1 );
}

/* save the moves in a file */
save_game( s, p1, p2, hcap, type )
	char *s;	/* file name to save to */
	char *p1, *p2;	/* player names */
	int hcap;	/* handicap stones or 0 */
	int type;	/* save REALMOVE or STEPMOVE */
{
	FILE *fp;
	int i, x, y;
	int m;
	struct movelist *ml;

	if( type == REALMOVE ) {
	   m = move;
	   ml = realmovelist;
	}
	else if( type == STEPMOVE ) {
	   m = currentmove;
	   ml = stepmovelist;
	}

	if( (fp = fopen( s, "a+" )) == NULL ) {
		perror( "savegame" );
		return( 0 );
	}

	fprintf( fp, "\n%s\n", stamptime() );
	fprintf( fp, "White: %s\nBlack: %s\n", p1, p2 );
	fprintf( fp, "Handicap: %d\n\n", hcap );

	if( hcap != 0 ) {
	    fprintf( fp, "  0 (B): Handicap %d\n", hcap );
	    i = 1;
	}
	else i = 0;

	for( ; i <= m; ++i ) {
	    x = ml[i].x + 1;
	    y = ml[i].y + 1;
	    fprintf( fp, "%3d (%c):  ", i, (i%2) ? 'W' : 'B' );
	    if( x < 0 ) fprintf( fp, "Pass\n" );
	    else fprintf( fp, "%c%d\n", 'A' + ((x > 8) ? x + 1 : x) - 1, y );
	}
	fclose( fp );
	return( 1 );
}

boolean inRange( i, j )
	int i, j;
{
   return i >= 0 && i < boardsize && j >= 0 && j < boardsize;
}

boolean alive0( b, m, i, j, t )
	boardtype b;
	boardtype m;
	int i, j;
	piece t;
{
	piece pt;

	pt = b[i][j];
	if ((pt != EMPTY && pt != t) || m[i][j] != EMPTY) return 0;
	m[i][j] = (pt == t) ? (piece) 1 : (piece) 2;
	if (pt == EMPTY) return 1;
	return( j < boardsize - 1 && alive0(b, m, i, j + 1, t)) ||
		(i < boardsize - 1 && alive0(b, m, i + 1, j, t)) ||
		(i && alive0(b, m, i - 1, j, t)) ||
		(j && alive0(b, m, i, j - 1, t));
}

/* Does group at i,j have liberties? */
boolean alive( b, i, j )
	boardtype b;
	int i, j;
{
	boardtype m;
	int p[2];

	clearboard(m, p);
	return( alive0(b, m, i, j, b[i][j]) );
}


void removeStones0( b, pris, i, j, t )
	boardtype b;
	int *pris;
	int i, j;
	piece t;
{
	if (b[i][j] != t) return;
	b[i][j] = EMPTY;

	if( tt == REALMOVE ) {
	    if( !boardchanged && !mouseflag ) {
		    drawStone( i+1, j+1, EMPTY, TRUE );
	    }
	}
	else if( tt == STEPMOVE ) {
	    if( boardchanged || mouseflag ) {
		    drawStone( i+1, j+1, EMPTY, TRUE );
	    }
	}

	pris[t - 1]++;
	if( j < boardsize - 1 ) removeStones0( b, pris, i, j + 1, t );
	if( i < boardsize - 1 ) removeStones0( b, pris, i + 1, j, t );
	if( i ) removeStones0( b, pris, i - 1, j, t );
	if( j ) removeStones0( b, pris, i, j - 1, t );
}

void get_prisoners( x, y )
	int *x, *y;
{
	*x = stepprisoners[0];
	*y = stepprisoners[1];
}

void set_prisoners( x, y )
	int x, y;
{
	stepprisoners[0] = x;
	stepprisoners[1] = y;
}

void update_prisoners( x, y )
	int x, y;
{
	stepprisoners[0] += x;
	stepprisoners[1] += y;
}

void score_it( i, j )
	int i, j;
{
	--i;
	--j;

	tt = STEPMOVE;
	boardchanged = TRUE;
	removeStones( stepboard, stepprisoners, i, j );
}

void removeStones( b, pris, i, j )
	boardtype b;
	int *pris;
	int i, j;
{
	removeStones0( b, pris, i, j, b[i][j] );
}

boolean tryKill( b, pris, i, j, t )
	boardtype b;
	int *pris;
	int i, j;
	piece t;
{
	piece w;

	if (!inRange(i, j)) return false;
	w = b[i][j];
	if (w != EMPTY && w != t && !alive(b, i, j)) {
	    removeStones(b, pris, i, j);
	    return true;
	}
	else return false;
}

boolean placeStone( b, pris, i, j, t )
	boardtype b;
	int *pris;
	int i, j;
	piece t;
{
	boolean ret = FALSE;

	if (inRange(i, j)) {
	    b[i][j] = t;
	    if (j) ret = tryKill(b, pris, i, j - 1, t);
	    if (j < boardsize - 1) ret |= tryKill(b, pris, i, j + 1, t);
	    if (i) ret |= tryKill(b, pris, i - 1, j, t);
	    if (i < boardsize - 1) ret |= tryKill(b, pris, i + 1, j, t);
	}
	return( ret );
}

/* return the info on move "num"  (real move) */
getmove( num, x, y, f )
	int num;
	int *x, *y, *f;
{
	*x = realmovelist[num].x+1;
	*y = realmovelist[num].y+1;
	*f = (int)realmovelist[num].flag;
	return( num );
}

/* delete the move "num" from the movetable */
removemove( num, type )
	int num, type;
{
	int x, y;

	if( type == REALMOVE ) {
	    x = realmovelist[num].x;
	    y = realmovelist[num].y;
	    board[x][y] = EMPTY;
	    realmovelist[num].x = 0;
	    realmovelist[num].y = 0;
	    realmovelist[num].flag = FALSE;
	}
	else if( type == STEPMOVE ) {
	    x = stepmovelist[num].x;
	    y = stepmovelist[num].y;
	    stepboard[x][y] = EMPTY;
	    stepmovelist[num].x = 0;
	    stepmovelist[num].y = 0;
	    stepmovelist[num].flag = FALSE;
	}
}

makemove( i, j, num, t, type )
	int i, j, num;
	piece t;
	int type;	/* update REALMOVE, STEPMOVE data? */
{
	int x, y, flag;

	tt = type;

	--i;
	--j;
	if( i < (-1) ) {		/* pass */
	    if( type == REALMOVE ) {
	        realmovelist[num].x = i;
	        realmovelist[num].y = j;
	        realmovelist[num].flag = FALSE;
	    }
	    if( type == STEPMOVE ) {
	        stepmovelist[num].x = i;
	        stepmovelist[num].y = j;
	        stepmovelist[num].flag = FALSE;
	    }
	}
	else {				/* place stone */
	    if( type == REALMOVE ) {
	        realmovelist[num].x = i;
	        realmovelist[num].y = j;
	        realmovelist[num].flag = placeStone( board, prisoners,
							i, j, t );
	    }
	    if( type == STEPMOVE ||
		(type == REALMOVE && (!boardchanged && !mouseflag)) ) {
	        stepmovelist[num].x = i;
	        stepmovelist[num].y = j;
	        stepmovelist[num].flag = placeStone( stepboard,
					stepprisoners, i, j, t );
	    }
	    if( type == REALMOVE ) {
		if( !boardchanged && !mouseflag ) drawStone( i+1, j+1, t, TRUE);
	        else beep();
	    }
	    if( type == STEPMOVE && (boardchanged || mouseflag) )
		drawStone( i+1, j+1, t, TRUE );
	}
}

static int verts[3][26] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 
	2, 0, 0, 0, 3, 0, 0, 0, 0, 0,  3, 0,  3, 0, 0, 0, 4},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 
	4, 0, 0, 0, 6, 0, 0, 0, 0, 0,  9, 0, 10, 0, 0, 0, 12},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 
	6, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 17, 0, 0, 0, 20},
};

/*
 * Set the handicap of "hand" stones on the board....
 * use "verts" table above....
 */
sethandicap( hand, type )
	int hand;
	int type;
{
	int top, mid, bot;
	piece t;

	top = verts[TOP][boardsize] +1;
	mid = verts[MID][boardsize] +1;
	bot = verts[BOT][boardsize] +1;

	/* 
	 * All of these drop through, '5' checks for odd points.
	 */
	t=1;
	switch (hand) {
	    case 9: 		/* taken care of by handi == 5 */
	    case 8: 
		makemove( mid, top, 0, t, type );
		makemove( mid, bot, 0, t, type );
	    case 7: 		/* taken care of by handi == 5 */
	    case 6: 
		makemove( bot, mid, 0, t, type );
		makemove( top, mid, 0, t, type );
	    case 5: 
		/* odd points, test because of drop through */
		if (hand & 0x1) {
		    makemove( mid, mid, 0, t, type );
		}
	    case 4: 
		makemove( bot, top, 0, t, type );
	    case 3: 
		makemove( top, bot, 0, t, type );
	    case 2: 
		makemove( bot, bot, 0, t, type );
		makemove( top, top, 0, t, type );
		break;
	    default: 
		break;
	}
}

sgf_hcap( f, s, h )
	FILE *f;
	int s, h;
{
	char *ss = NULL;

	switch( s ) {
	    case 19:
		switch( h ) {
		    case 2:
			ss = "AddBlack[dp][pd]";
			break;
		    case 3:
			ss = "AddBlack[dp][pd][dd]";
			break;
		    case 4:
			ss = "AddBlack[dd][dp][pd][pp]";
			break;
		    case 5:
			ss = "AddBlack[dd][dp][jj][pd][pp]";
			break;
		    case 6:
			ss = "AddBlack[dd][dj][dp][pd][pj][pp]";
			break;
		    case 7:
			ss = "AddBlack[dd][dj][dp][jj][pd][pj][pp]";
			break;
		    case 8:
			ss = "AddBlack[dd][dj][dp][jd][jp][pd][pj][pp]";
			break;
		    case 9:
			ss = "AddBlack[dd][dj][dp][jd][jj][jp][pd][pj][pp]";
			break;
		    default:
			break;
		}
		break;
	    case 13:
		switch( h ) {
		    case 2:
			ss = "AddBlack[dj][jd]";
			break;
		    case 3:
			ss = "AddBlack[dj][jd][dd]";
			break;
		    case 4:
			ss = "AddBlack[dd][dj][jd][jj]";
			break;
		    case 5:
			ss = "AddBlack[dd][dj][gg][jd][jj]";
			break;
		    default:
			break;
		}
		break;
	    case 9:
		switch( h ) {
		    case 2:
			ss = "AddBlack[cg][gc]";
			break;
		    case 3:
			ss = "AddBlack[cg][gc][cc]";
			break;
		    case 4:
			ss = "AddBlack[cc][cg][gc][gg]";
			break;
		    default:
			break;
		}
		break;
	    default:
		break;
	}

	if( ss != NULL ) fprintf( f, ";\n%s\n", ss );
}
SHAR_EOF
fi
if test -f 'filter.c'
then
	echo shar: "will not over-write existing file 'filter.c'"
else
cat << \SHAR_EOF > 'filter.c'
/* filter.c
 * S.Coffin	USWAT 1/93
 *
 * process I/O stream between user and igs
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

#include "filter.h"
#include "shared.h"
#include <signal.h>

static char kbd_str[LINESIZE];
char observeflag = FALSE;
static char infileflag = FALSE;
int move = (-1);
int stepmove = (-1);
extern int currentmove;
static char undoflag = FALSE;

extern int gameno, handicap;
extern int boardsize;
extern char player1[], player2[];
char splayer1[20], splayer2[20];
extern int p1_sec, p2_sec;
extern int p1_captured, p2_captured;
extern int p1_byoyomi, p2_byoyomi;
int sp1_sec, sp2_sec;
int sp1_captured, sp2_captured;
int sp1_byoyomi, sp2_byoyomi;
float sp1_komi;
int sp1_hcap;
int sgameno;
extern int colorflag;
extern int set_cursor_color();
extern int boardchanged, mouseflag;
extern unsigned char statusflag;

extern int dbg;
extern void catcher();
extern void score_it();
extern void setMark();
extern void do_refresh(), RefreshHost();
extern void clearit();
char *SCstrstr();

int setup_filter(exec_stdin, exec_stdout, exec_stderr )
	FILE **exec_stdin, **exec_stdout, **exec_stderr;
{
	char delim = ' ';
	int i, tpid;
	extern char cmdline[];

	/* handle signals carefully */
	for( i = 1; i <= SIGUSR2; ++i ) signal( i, catcher );
	signal( SIGWINCH, SIG_IGN );
	signal( SIGINT, SIG_IGN );
	signal( SIGQUIT, SIG_IGN );

	/* and exec, using FILE's for i/o  */
	tpid = rdwr_popen( exec_stdout, exec_stdin, exec_stderr, cmdline,
		NULL, delim );

	if( tpid < 0 ) {
	    fprintf( stderr, "FORK FAILED!\n" );
	    return( (-1) );
	}
	else if( dbg ) fprintf( stderr, "Fork succeeds; pid=%d\n", tpid );

	return( tpid );
}


/* this one parses input of interest from the comm channel, and
 * takes appropriate action to place stones on the board
 */

process_input( str )
	char *str;
{
	int i, j, len, ret, tt, t, c2, c4;
	float c3;
	int m, code, yloc;
	char xloc, color, tflag;
	static char s[LINESIZE];
	static int beenhere = FALSE;
	char *temp_str, *current_str;
	char p1[20], p2[20], r1[20];
	int x;

	if( !beenhere ) {
	    beenhere = TRUE;
	    for( j=0; j<LINESIZE; ++j ) s[j] = '\0';
	}

	if( dbg ) fprintf( stderr, "In process_input: str=>>%s<<\n", str );

	for( temp_str = str ;; ) {

	    /* find newline */
	    for( i=0; temp_str[i] != '\n' && temp_str[i] != '\0'; ++i );

	    /* no newline..... */
	    if( temp_str[i] == '\0' ) {
		if( i > 0 ) {
		    strcat( s, temp_str );
		}

		/* get code */
		ret = sscanf( s, "%d", &code );

		 /* no code, print it */
		if(  ret != 1 ) {
		    fprintf( stderr, "%s", s );
		    fflush( stderr );
		    for( j=0; j<LINESIZE; ++j ) s[j] = '\0';
		}
		return( 0 );
	    }

	    if( temp_str[i] == '\n' ) {

		len = strlen(s);
		strncat( s, temp_str, i );
		s[i+len+1] = '\0';

		/* get code */
		ret = sscanf( s, "%d", &code );

		/* no code, print it */
		if( ret != 1 ) {
		    	fprintf( stderr, "%s\n", s );
		    	fflush( stderr );
		}

		else {
		    /* find space */
		    for(j=0; s[j] != ' ' && s[j] != '\n' && s[j] != '\r'; ++j );
		    if( s[j] == ' ' ) current_str = &s[++j];
		    else if( s[j] == '\n' || s[j] == '\r' ) current_str = &s[j];
		    else current_str = s;

		    switch( code ) {
			case HELP:	/* has a "File" after code */
			case THIST:
			case STORED:
			case INFO:
			case MESSAGE:
			    /* scoring done under "INFO" msg */
			    if( observeflag == SCORING ) {
				ret = sscanf( current_str, "Removing @ %c%d",
						&xloc, &yloc );
				if( ret == 2 ) {
		        	    xloc = xloc - 'A' + 1;
		        	    if( xloc > 8 ) --xloc;
				    score_it( xloc, yloc );
				    get_prisoners( &p1_captured, &p2_captured );
				    if( !statusflag )
					update_status( gameno, player2,
					    player1, p2_captured, p1_captured,
					    p2_sec, p1_sec, p2_byoyomi,
					    p1_byoyomi );
				}
			    }
			    if( strncmp( current_str, "File", 4 ) == 0 ) {
				fprintf( stderr, "%s\n", &current_str[4] );
				if( infileflag ) infileflag = FALSE;
				else infileflag = TRUE;
			    }
			    else fprintf( stderr, "%s\n", current_str );
			    fflush( stderr );
			    break;
			case UNDO:	/* undo */
			    fprintf( stderr, "\n%s\n", current_str );
			    fflush( stderr );
			    move = undo( move );
			    break;
	    		case MOVE:	/* a move */
			    /* game number? */
			    ret = sscanf( current_str,
				    "Game %d: %s (%d %d %d) vs %s (%d %d %d)",
					&t, player1, &p1_captured, &p1_sec,
					&p1_byoyomi, player2, &p2_captured,
					&p2_sec, &p2_byoyomi );

			    if( ret == 9 ) {
				if( t != gameno ) {
				    gameno = t;
				    fprintf( stderr,
					"LOCAL: Changing game number to %d\n",
					gameno );
				}

				if( !statusflag )
				    update_status( gameno, player2,
					player1, p2_captured, p1_captured,
					p2_sec, p1_sec, p2_byoyomi,
					p1_byoyomi );
			    }

			    /* handicap? */
			    ret = sscanf( current_str, "%d(%c): Handicap %d", &m,
					&color, &tt );
			    if( ret == 3 ) {
				fprintf( stderr, "Handicap %d\n", tt );
				move = (-1);
				refreshboard();
				handicap = tt;
				sethandicap( tt, REALMOVE );
				update_handicap( handicap );
				if( !boardchanged && !mouseflag ) {
				    set_cursor_color( move+1 );
				}
				goto done;
			    }

			    /* its a move? */
	            	    ret = sscanf( current_str, "%d(%c): %c%d",
				&m, &color, &xloc, &yloc );
		            if( ret == 4 ) {
				if( stepmove >= move || stepmove == (-1) )
						stepmove = m;
				if( !boardchanged && !mouseflag )
					currentmove = m;

				move = m;

	                        if( dbg ) {
		                    fprintf( stderr,
			                "Move=%d, color=%c, xloc=%c, yloc=%d\n",
			                move, color, xloc, yloc );
		                }
		        	ret = xloc - 'A' + 1;
		        	if( ret > 8 ) --ret;
				if( !undoflag || observeflag != PLAYING ) {
		        	    if( color == 'W' ) {
		            	        makemove(ret, yloc, move,
							WHITE, REALMOVE );
				    }
		        	    else if( color == 'B' ) {
		            	        makemove( ret, yloc, move,
							BLACK, REALMOVE);
				    }
				}
				undoflag = FALSE;
				if( !boardchanged && !mouseflag ) {
				    set_cursor_color( move );
				}
				update_move( current_str );
		    	        fprintf( stderr, "%s\n", current_str );
			        fflush( stderr );
	            	    }

			    /* its a pass ?? */
			    else if( SCstrstr( current_str, "Pass" ) != NULL ) {
				makemove( (-1), (-1), ++move, EMPTY, REALMOVE );
				if( stepmove >= move-1 || stepmove == (-1) )
						stepmove = move;
				if( !boardchanged && !mouseflag )
					currentmove = m;
				update_move( current_str );
				set_cursor_color( colorflag+1 );
		    	        fprintf( stderr, "%s\n", current_str );
			        fflush( stderr );
			    }
				
			  done:
		    	    break;
			case PROMPT:	/* prompt */
			    sscanf( current_str, "%d", &c2 );
			    switch( c2 ) {
				case LOGON:
				    fprintf( stderr, "Login: " );
				    break;
				case PASSWORD:
				    fprintf( stderr, "Password: " );
				    break;
				case PASSWD_NEW:
				   fprintf( stderr, "New Password: " );
				   break;
				case PASSWD_CONFIRM:
				   fprintf( stderr, "Re-enter Password: " );
				   break;
				case WAITING:
				    fprintf( stderr, "igs> " );
				    observeflag = FALSE;
				    break;
				case PLAYING:
				    /* refresh board if just start playing */
				    if( observeflag != PLAYING )
					RefreshHost( NULL, NULL );
				    fprintf( stderr, "igs [p%d]> ", gameno );
				    observeflag = PLAYING;
				    break;
				case SCORING:
				    fprintf( stderr, "Remove dead group> " );
				    observeflag = SCORING;
				    break;
				case OBSERVING:
				    fprintf( stderr, "igs [o%d]> ", gameno );
				    observeflag = OBSERVING;
				    break;
				default:
		    	    	    fprintf( stderr, "%s\n", current_str );
				    observeflag = FALSE;
				    break;
			    }
			    fflush( stderr );
			    break;
			case SHOUT:
			    /* update game number if needed */
		    	    fprintf( stderr, "%s\n", current_str );
			    fflush( stderr );
			    break;
			case LOOK_M:
			case STATUS:	/* screen refresh of current display */
			    /* player (w in first line), rank, captured,
			     * time (sec), byoyomi stones, flag (T if byo),
			     * komi, hcap
			     */
			    ret = sscanf( current_str,
					"%s %s %d %d %d %c %f %d",
					p1, r1, &t, &tt, &c2, &tflag, &c3, &c4 );
			    if( ret == 8 ) {
				if( tflag == 'F' ) c2 = 0;
				if( !statusflag ) {
				    clearit();
				    boardchanged = TRUE;
				    highlight( TRUE );
				    statusflag = TRUE;
				    strcpy( splayer1, p1 );
				    sp1_captured = t;
				    sp1_sec = tt;
				    sp1_byoyomi = c2;
				    sp1_komi = c3;
				    sp1_hcap = c4;
				}
				else {
				    strcpy( splayer2, p1 );
				    sp2_captured = t;
				    sp2_sec = tt;
				    sp2_byoyomi = c2;
				    set_prisoners( sp2_captured, sp1_captured );
	    			    update_status( sgameno, splayer2, splayer1,
					sp2_captured, sp1_captured, sp2_sec,
					sp1_sec, sp2_byoyomi, sp1_byoyomi );
				    update_move( NULL );
				}
				break;
			    }
			    else {
			        ret = sscanf( current_str, "%d: %s\n", &x, p1 );
			        if( ret == 2 ) parse_line( x, p1 );
			    }
			    break;
			case UNKNOWN:	/* strip the code from these, but */
			case BOARD:	/* otherwise pass them untouched */
			case DOWN:
			case ERROR:
			case FIL:
			case GAMES:
			case LAST:
			case KIBITZ:
			case LOAD:
			case OBSERVE:
			case REFRESH:
			case SAVED:
			case SAY:
			case SCORE:
			case TELL:
			case TRANS:
			case SHOW:	/* what is this? */
			case TIM:
			case WHO:
			    if( strncmp( current_str, "File", 4 ) == 0 ) {
				fprintf( stderr, "%s\n", &current_str[4] );
				if( infileflag ) infileflag = FALSE;
				else infileflag = TRUE;
			    }
			    else fprintf( stderr, "%s\n", current_str );
			    fflush( stderr );
		            break;
			case BEEP:
			    if( current_str[0] == 0x07 ) {
				fprintf( stderr, "\007\n" );
			        fflush( stderr );
				break;
			    }
			    if( current_str[0] == '2' ) {
				fprintf( stderr, "\007" );
				current_str += 2;
			    }
			    fprintf( stderr, "%s\n", current_str );
			    fflush( stderr );
			    break;
			default:	/* print code if it is unexpected */
		    	    fprintf( stderr, "%d %s\n", code, current_str );
			    fflush( stderr );
		            break;
		    }
		}
	        
		/* reset active string */
		for( j=0; j<LINESIZE; ++j ) s[j] = '\0';
		temp_str = &temp_str[i+1];
		continue;
	    }
	}
}

/* examine user input from keyboard for commands of local interest
 *
 * return 0 = don't send original string to host
 * return 1 = send original string to host
 */
process_kbd( str, fp )
	char *str;
	FILE *fp;
{
	int i, t, ret;
	char s[40];

	if( dbg ) fprintf( stderr, "In process_kbd:  >>%s<<", str );

	for( i=0; str[i] != '\0'; ++i ) kbd_str[i] = tolower( str[i] );
	kbd_str[i] = '\0';

	if( strncmp( kbd_str, "gameno", 6 ) == 0 ) {
		sscanf( kbd_str, "gameno %d", &gameno );
		fprintf( stderr, "LOCAL:  Set game number to %d\n", gameno );
		fflush( stderr );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	}
	if( strncmp( kbd_str, "load ", 5 ) == 0 ) {
	    if( observeflag == SCORING || observeflag == PLAYING ) {
		fprintf( stderr, "LOCAL: cannot load while playing\n" );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    if( observeflag == OBSERVING ) {
		fprintf( stderr, "LOCAL: cannot load while observing;\n" );
		fprintf( stderr, "Use \"observeoff\" to stop observing\n" );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    else {
	        return( 1 );
	    }
	}
	if( strncmp( kbd_str, "look ", 5 ) == 0 ) {
	    if( observeflag == SCORING ) {
		fprintf( stderr, "LOCAL: cannot look while scoring\n" );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    else {
	        statusflag = FALSE;
	        return( 1 );
	    }
	}
	if( strncmp( kbd_str, "status ", 7 ) == 0 ) {
	    if( observeflag == SCORING ) {
		fprintf( stderr, "LOCAL: cannot get status while scoring\n" );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    else {
	        sscanf( kbd_str, "status %d", &sgameno );
	        statusflag = FALSE;
	        return( 1 );
	    }
	}
	else if( (strncmp( kbd_str, "moves", 4 ) == 0 && kbd_str[5] != ' ' ) ||
		 (strncmp( kbd_str, "refresh", 7 ) == 0 && kbd_str[7] != ' ') ) {
	    if( gameno < 0 ) {
		fprintf( stderr, "LOCAL: no current game to refresh\n" );
		fflush( stderr );
	        fprintf( fp, "\n" );
	        fflush( fp );
	    }
	    else {
	        move = stepmove = (-1);
		currentmove = (-1);
	        refreshboard();
	        fprintf( fp, "moves %d\n", gameno );
	        fflush( fp );
	    }
	    return( 0 );
	}
	else if( (strncmp( kbd_str, "moves", 4 ) == 0 && kbd_str[5] == ' ' ) ) {
		sscanf( kbd_str, "moves %d", &ret );
		if( observeflag && ret != gameno ) {
		    fprintf( stderr,
			"LOCAL: Can't get moves of another game while observing or playing;\n" );
		    fprintf( stderr, "Use \"status\" instead\n" );
		    fflush( stderr );
	            fprintf( fp, "\n" );
	            fflush( fp );
		    return( 0 );
		}
		else {
	            move = stepmove = (-1);
		    currentmove = (-1);
	            refreshboard();
		    return( 1 );
		}
	}
	else if( strncmp( kbd_str, "refresh ", 8 ) == 0 ) {
	        move = stepmove = (-1);
		currentmove = (-1);
		sscanf( kbd_str, "refresh %d", &t );
	        refreshboard();
	        fprintf( fp, "moves %d\n", t );
	        fflush( fp );
		return( 0 );
	}
	else if( strncmp( kbd_str, "observe ", 8 ) == 0 ) {
	    if( observeflag != FALSE ) {
		fprintf( stderr, "LOCAL: Already observing game %d;", gameno );
		fprintf( stderr, " can't observe multiple games!\n" );
		fprintf( stderr, "Use \"observeoff\" to stop observing\n" );
		fprintf( stderr, "or \"status n\" to see the current position of another game\n" );
		fflush( stderr );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    sscanf( kbd_str, "observe %d", &t );
	    gameno = t;
	    move = (-1);
	    refreshboard();
	    fprintf( fp, "observe %d\n", gameno );
	    fflush( fp );
	    sleep( 1 );
	    fprintf( fp, "moves %d\n", gameno );
	    fflush( fp );
	    return( 0 );
	}
	else if( strncmp( kbd_str, "observeoff", 10 ) == 0 ) {
	    if( observeflag == FALSE ) {
		fprintf( stderr, "LOCAL: Not currenty observing\n" );
		fflush( stderr );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	    fprintf( fp, "observe %d\n", gameno );
	    fflush( fp );
	    return( 0 );
	}
	else if( strncmp( kbd_str, "time", 4 ) == 0 && kbd_str[4] != ' ' ) {
	    if( observeflag ) {
		fprintf( fp, "time %d\n", gameno );
		fflush( fp );
		return( 0 );
	    }
	}
	else if( strncmp( kbd_str, "all", 3 ) == 0 && kbd_str[3] != ' ' ) {
	    if( observeflag ) {
		fprintf( fp, "all %d\n", gameno );
		fflush( fp );
		return( 0 );
	    }
	}
	else if( strncmp( kbd_str, "match", 5 ) == 0 ) {
	    if( observeflag == OBSERVING ) {
	        fprintf( fp, "observe %d\n", gameno );
	        fflush( fp );
	    }
	    else if( observeflag != FALSE ) {
		fprintf( stderr, "LOCAL: Already playing!\n" );
		fflush( stderr );
	        fprintf( fp, "\n" );
	        fflush( fp );
		return( 0 );
	    }
	}

	return( 1 );
}

/* signal handler to clean up on disasters */
void catcher( sig, code )
	int sig, code;
{
	extern void rdwr_pclose();

	if( dbg ) fprintf( stderr, "Signal catcher [sig=%d code=%d]\n",
			sig, code );

	rdwr_pclose( NULL, NULL, NULL );
	exit( code );
}

int undo( m )
	int m;
{
	int ret, yloc, flag;
	char s[40];
	int x, y;

	getmove( m, &x, &y, &flag );
	ret = x;
	yloc = y;

	if( ret > 8 ) ++ret;
	ret += 'A' - 1;
	sprintf( s, "UNDO: move %d, %c%d", m, (char)ret, yloc );
	removemove( m, REALMOVE );
	if( !boardchanged && !mouseflag ) {
	    if( flag ) do_refresh( move-1, NULL, REALMOVE );
	    else {
		drawStone( x, y, EMPTY, TRUE );
	        getmove( m-1, &ret, &yloc, &flag );
	        drawStone( ret, yloc, ((m-1)%2)+1, TRUE );
	    }
	    set_cursor_color( move-1 );
	}

	update_move( s );
	if( stepmove >= m || stepmove == (-1) ) stepmove = currentmove = m - 1;
	undoflag = TRUE;
	return( m - 1 );
}

/* Find the first occurrence of s2 in s1  */
char *SCstrstr( s1, s2 )
	char *s1, *s2;
{
	char c, sc;
	int len;

	if( (c = *s2++) != 0 ) {
	    len = strlen(s2);
	    do {
		do {
		    if ((sc = *s1++) == 0) return (NULL);
		} while (sc != c);
	    } while (strncmp(s1, s2, len) != 0);
	    s1--;
	}
	return( s1 );
}

parse_line( line, str )
	int line;
	char *str;
{
	int xloc, yloc;
	int len;
	int i;
	char c;

	len = strlen( str );
	while( str[len-1] == '\n' || str[len-1] == '\r' ) --len;
	str[len] == '\0';

	if( dbg )
	    fprintf( stderr, "In parse_line:  line=%d, str=>>%s<<\n",
					line, str );

	xloc = line + 1;

	for( i = 0; i < len; ++i ) {
	    yloc = len - i;
	    switch( str[i] ) {
		case '0':		/* black stone */
		    drawStone( xloc, yloc, BLACK, FALSE );
		    break;
		case '1':		/* white stone */
		    drawStone( xloc, yloc, WHITE, FALSE );
		    break;
		case '4':		/* White territory */
		    setMark( xloc, yloc, 'w' );
		    update_prisoners( 0, 1 );
		    break;
		case '5':		/* black territory */
		    setMark( xloc, yloc, 'b' );
		    update_prisoners( 1, 0 );
		    break;
		case '2':		/* empty point */
		case '3':		/* dame */
		case '6':		/* starpoint */
		case '7':		/* counted */
		    break;
		case '8':
		case '9':
		default:
		    fprintf( stderr,
			"ERROR IN PARSE_LINE: bad code = 0x%x\n", str[i] );
		    break;
	    }
	}
	if( xloc >= len ) {
	    get_prisoners( &sp2_captured, &sp1_captured );
	    /*XXX  include komi in final point count at game end  ?? */
	    update_status( sgameno, splayer2, splayer1, sp2_captured,
				sp1_captured, sp2_sec, sp1_sec, sp2_byoyomi,
				sp1_byoyomi );
	    update_handicap( sp1_hcap );
	}
}
SHAR_EOF
fi
if test -f 'filter.h'
then
	echo shar: "will not over-write existing file 'filter.h'"
else
cat << \SHAR_EOF > 'filter.h'
/* filter.h
 * S.Coffin	USWAT   1/93
 *
 * process I/O stream between user and igs
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
/*SC
#include <netinet/in.h>
#include <netdb.h>
SC*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include "patchlevel.h"

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define BLACK 1
#define WHITE 2
#define EMPTY 0

#define TIMEOUT 10
#define LINESIZE	2048

#define MAXMOVE	550

extern void exit();
extern unsigned sleep();
extern int errno;
extern int dbg;

#define TEXT	1
#define SGF	2

#define REALMOVE 1
#define STEPMOVE 2
SHAR_EOF
fi
if test -f 'igscomm.c'
then
	echo shar: "will not over-write existing file 'igscomm.c'"
else
cat << \SHAR_EOF > 'igscomm.c'
/* igscomm.c
 * S.Coffin   USWAT   1/93
 *
 * Simple socket-based comm program for calling the igs
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

#include "igscomm.h"

#define USAGE "Usage:  %s [-d] [-?] [-e] [-h host-address] [-p port-number]\n"

int dbg = FALSE;
void SCbcopy();
int port = PORT;
int echoflag = TRUE;

main( argc, argv )
	int argc;
	char *argv[];
{
	int i, j, sd, count, ret;
	char *r;
	struct hostent *hp;
	char *host = HOST;
	struct sockaddr_in sin;
	char str[MSG_SIZE+1];
	fd_set xx;
	struct timeval timeout;
	int yy = 32;
	extern int getopt();
	extern char *optarg;
	extern int optind;
	int c;
#ifdef BSD
	struct sgttyb tin, tout;
#else
	struct termio tin, tout;
#endif

	while( (c=getopt( argc, argv, "?h:p:de" )) != (-1) ) {
	    switch( c ) {
		case 'd':	/* debug mode */
		    dbg = TRUE;
		    break;
		case 'e':	/* disable echo */
		    echoflag = FALSE;
		    break;
		case 'p':	/* socket number */
		    port = atoi( optarg );
		    break;
		case 'h':	/* host id */
		    host = optarg;
		    break;
		case '?':
		default:
		    fprintf( stderr, "%s: Release %s\n", argv[0], PATCHLEVEL );
	    	    fprintf( stderr, USAGE, argv[0] );
		    exit( (-1) );
		    break;
	    }
	}

	if( optind != argc ) {
	    fprintf( stderr, "%s: Release %s\n", argv[0], PATCHLEVEL );
	    fprintf( stderr, USAGE, argv[0] );
	    exit( (-1) );
	}

	hp = gethostbyname( host );
	if( hp == NULL ) {
	    fprintf( stderr, "host >>%s<< not found!\n", host );
	    exit( 1 );
	}

	if( dbg ) fprintf( stderr, "hp->h_name= >>%s<<\n", hp->h_name );
	if( hp->h_aliases[0] != NULL ) {
	    if( dbg ) fprintf( stderr, "aliases:\n" );
	    for( i=0; hp->h_aliases[i] != NULL; ++i )
	        if( dbg )
		    fprintf( stderr, "\t%d. >>%s<<\n", i, hp->h_aliases[i] );
	}

	/* don't use bzero() or bcopy() since some systems don't have them */
	for( i=0; i<sizeof(sin); ++i ) *((char *)(&sin + i)) = 0; 
	SCbcopy( hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length );

	sin.sin_family = hp->h_addrtype;
	sin.sin_port = htons( port );

	if( (sd=socket( hp->h_addrtype, SOCK_STREAM, 0 ) ) < 0 ) {
	    perror( "socket" );
	    exit( 2 );
	}

	if( connect( sd, (char *)&sin, sizeof( sin ) ) < 0 ) {
	    perror( "connect" );
	    exit( 3 );
	}

	/* connected now */

	/* turn of echo */
	/*XXX  I don't know if this code is ok for ALL UNIX versions */
	if( !echoflag ) {
#ifdef BSD
	    ioctl( fileno(stdin), TIOCGETP, &tin );
	    tout = tin;
	    tout.sg_flags &= ~ECHO;
	    ioctl( fileno(stdin), TIOCSETP, &tout );
#else
	    ioctl( fileno(stdin), TCGETA, &tin );
	    tout = tin;
	    tout.c_lflag &= ~ECHO;
	    ioctl( fileno(stdin), TCSETAW, &tout );
#endif
	}

	for( ;; ) {
	    timeout.tv_sec = TIMEOUT;
	    timeout.tv_usec = 0L;
	    FD_ZERO( &xx );
	    FD_SET( sd, &xx );	/* listen on the socket */
	    FD_SET( 0, &xx );	/* listen for kbd input */

	    ret = select( yy, &xx, NULL, NULL, &timeout );

	    /* error ? */
	    if( ret < 0 ) {
	    	/* exit on interrupt ?? */
		if( errno == EINTR ) break;

	        /* any other interruption is an error! */
		else {
		    perror( "select" );
		    break;
		}
	    }

	    /* timeout */
	    else if( ret == 0 ) {
		if( dbg ) fprintf( stderr, "Timeout\n" );
		continue;
	    }

	    /* input from socket.... print it */
	    else if( FD_ISSET( sd, &xx ) ) {
		FD_CLR( sd, &xx );
	        if( (count=recv( sd, str, MSG_SIZE, 0 )) < 0 ) {
		    perror( "recv" );
		    break;
	        }
		if( count == 0 ) {
		    fprintf( stderr, "Connection closed by foreign host.\n" );
		    break;
		}

	        str[count] = '\0';
		for( j=0; j < count; ++j ) {
		    if( isascii( str[j] ) &&
			(isgraph( str[j] ) || isspace( str[j] ) ) ) {
				putchar( str[j] );
		    }
		}
		fflush( stdout );
		continue;
	    }

	    /* input from keyboard....  send it */
	    else if( FD_ISSET( 0, &xx ) ) {
		FD_CLR( 0, &xx );
	        if( (r = gets( str )) == NULL ) break;
	        j = strlen(str);
	        if( str[0] == '.' && j == 1 ) break;
	        str[j++] = '\n';
	        str[j+1] = '\0';

	        /* send a message to the server PORT on HOST */
	        if( send( sd, str, j, 0 ) < 0 ) {
		    perror( "send" );
		    break;
	        }
		continue;
	    }
	}

	/* close the socket connection */
	if( shutdown( sd, 2 ) < 0 ) {
		perror( "shutdown" );
		exit( 1 );
	}

	close( sd );
}

/* really crude, unsafe version of bcopy() */
void SCbcopy (b1, b2, length)
	register char *b1;
	register char *b2;
	register unsigned length;
{
	while (length-- > 0) *b2++ = *b1++;
}
SHAR_EOF
fi
if test -f 'igscomm.h'
then
	echo shar: "will not over-write existing file 'igscomm.h'"
else
cat << \SHAR_EOF > 'igscomm.h'
/*	igscomm.h
 *	S.Coffin   USWAT   1/93
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <string.h>

#ifdef BSD
#include <sgtty.h>
#else
#include <termio.h>
#endif

#include "patchlevel.h"

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

extern void exit();
extern unsigned sleep();

extern int dbg;
extern int errno;

#define TIMEOUT 	10	/* seconds to wait between samples */

#define HOST		"128.32.201.46"
#define PORT		6969
#define MSG_SIZE	1024
SHAR_EOF
fi
if test -f 'patchlevel.h'
then
	echo shar: "will not over-write existing file 'patchlevel.h'"
else
cat << \SHAR_EOF > 'patchlevel.h'
#define PATCHLEVEL "v2.1"
SHAR_EOF
fi
if test -f 'pipes.c'
then
	echo shar: "will not over-write existing file 'pipes.c'"
else
cat << \SHAR_EOF > 'pipes.c'
/*	rdwr_popen.c
 *	S.Coffin   USWAT  3/91
 *
 *	rdwr_popen: like popen, but return 3 FILEs, for in, out & err
 *	NOTE: you usually want to change the buffering on the returned
 *	FILEs (after they've been opened), probably via a setbuf( fp, NULL )
 *
 *	original for email-II	S.Coffin  7/86
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

#include <stdio.h>
#include "filter.h"

extern FILE *fdopen();
extern void exit ();
extern unsigned sleep ();
static void my_exec();

static int pid;

/* returns the pid we exec'ed or zero on error */
int rdwr_popen (fr, fw, ferr, cmd, env, envdelim )
	FILE **fr, **fw, **ferr;
	char *cmd, *env;
	char envdelim;
{
	int tries = 5;
	unsigned ZZs = 1;
	int fda [2], fdb [2], fdc [2];
	int i;
	char *e, *t;

	if( dbg ) fprintf( stderr, "in rdwr_popen  cmd=>>%s<<\n", cmd );

	/* Get all the pipes we need */
	if( pipe (fda) || pipe (fdb) || pipe (fdc) ) return( 0 );
		
	/* Try & fork 5 times, backing off 1, 2, 4 .. seconds each try */
	while ((pid = fork ()) < 0) {
		if (--tries == 0) return( 0 );
		(void) sleep (ZZs);
		ZZs <<= 1;
	}
	if (pid == 0) {			/* child */
		/* add the envstr to the real environment */
/*SC  xigc does not use the env arg; we comment this out since some
 *SC  systems do not have "putenv()"
		for( e = env ; e != NULL && e[0] != '\0'; e = ++t ) {
		    t = strchr( e, envdelim );
		    if( t != NULL ) *t = '\0';
		    if( dbg ) {
			fprintf( stderr, "env=>>%s<<\n", e );
			fflush( stderr );
		    }
		    putenv( e );
		    if( dbg ) {
			fprintf( stderr, "PUTENV DONE\n" );
			fflush( stderr );
		    }
		    if( t == NULL ) break;
		}
SC*/

		if( fda[0] != 0 ) {
			(void) close( 0 );
			i = dup (fda [0]);
			if( i != 0 ) exit( (-1) );
		}
		if( fdb[1] != 1 ) {
			(void)close (1);
			if (dup (fdb [1]) != 1) exit( (-1) );
		}
		if( fdc[1] != 2 ) {
			(void)close (2);
			if (dup (fdc [1]) != 2) exit( (-1) );
		}
			
		/* Make sure there are no inherited file descriptors */
		for (i = 3; i < NOFILE; i += 1) (void) close (i);

		/* and exec */
		my_exec( cmd );
		exit( 0 );
		/*NOTREACHED*/
	} else {
		/* Parent */
		if (fr && (*fr = fdopen (fdb [0], "r")) == NULL) return( (-1) );
		if (fw && (*fw = fdopen (fda [1], "w")) == NULL) return( (-1) );
		if (ferr && (*ferr = fdopen (fdc [0], "r")) == NULL) return( (-1) );
		(void) close (fdc [1]);
		(void) close (fdb [1]);
		(void) close (fda [0]);
		return( pid );
	}
}

/*ARGSUSED*/
rdwr_pclose (fin, fout, ferr)
	FILE *fin, *fout, *ferr;
{
	(void) kill (pid, SIGKILL);
	(void) wait ((int *)0);
}

static void my_exec (ccmd)
	char *ccmd;
{

/* Can only be MAXARGS arguments */
#define MAXARGS	64

	char *argv [MAXARGS];
	register char **argv_p, *cp;

	if( dbg ) {
	    fprintf( stderr, "my_exec  cmd=>>%s<<\n", ccmd );
	    fflush( stderr );
	}
	
	argv_p = argv;
	cp = ccmd;
	/* Scan up cmd, splitting arguments into argv. This is the
	 * child, so we can zap things in cmd safely */
	
	while (*cp != '\0') {
		/* Skip any white space */
		while (*cp && isspace (*cp)) cp += 1;
		if (*cp == '\0') break;
		*argv_p++ = cp;
		while (*cp && !isspace (*cp)) cp += 1;
		if (*cp == '\0') break;
		*cp++ = '\0';
	}
	*argv_p = NULL;
	execvp (ccmd, argv);
}
SHAR_EOF
fi
if test -f 'sample_xigcrc'
then
	echo shar: "will not over-write existing file 'sample_xigcrc'"
else
cat << \SHAR_EOF > 'sample_xigcrc'
# this is a sample version of the personal configuration file
# $HOME/.xigcrc

COMMAND igscomm -h 128.32.201.46 -p 6969
QUITCOMMAND .
# COMMAND telnet 128.32.201.46 6969
# QUITCOMMAND quit
SAVEFORMAT sgf
SHAR_EOF
fi
if test -f 'shared.h'
then
	echo shar: "will not over-write existing file 'shared.h'"
else
cat << \SHAR_EOF > 'shared.h'
/* shared.h
 * S.Coffin  USWAT   1/93
 *
 * bits for compatibility with the IGS
 *
 * adapted from tcasey@leo.unm.edu
 */

#ifndef SHARED_H
#define SHARED_H

#define MAX_BRD_SZ 25

typedef enum {
	UNKNOWN	=  0,
	BEEP	=  2, 	/* \7 telnet 		*/
	BOARD	=  3,	/* Board being drawn 	*/
	DOWN	=  4,	/* The server is going down */
	ERROR	=  5,	/* An error reported	*/
      	FIL	=  6,	/* File being sent	*/
	GAMES	=  7,	/* Games listing	*/
      	HELP	=  8,	/* Help file		*/
	INFO	=  9,	/* Generic info		*/
	LAST	= 10,	/* Last command		*/
      	KIBITZ	= 11,	/* Kibitz strings	*/
	LOAD	= 12,	/* Loading a game	*/
	LOOK_M	= 13,	/* Look 		*/
      	MESSAGE	= 14,	/* Message lising	*/
      	MOVE	= 15,	/* Move #:(B) A1	*/
	OBSERVE	= 16,	/* Observe report	*/
      	PROMPT	=  1,	/* A Prompt (never)	*/
	REFRESH	= 17,	/* Refresh of a board	*/
      	SAVED	= 18,	/* Stored command	*/
      	SAY	= 19,	/* Say string		*/
      	SCORE	= 20,	/* Score report		*/
      	SHOUT	= 21,	/* Shout string		*/
      	STATUS	= 22,	/* Current Game status	*/
	STORED	= 23,	/* Stored games		*/
      	TELL	= 24,	/* Tell string		*/
	THIST	= 25,	/* Thist report		*/
	TIM	= 26,	/* times command	*/
	WHO	= 27,	/* who command		*/
	UNDO	= 28,	/* Undo report		*/
	SHOW    = 29,
	TRANS   = 30   /* Translation info     <=== last value */
} MessageType;

#define LOGGEDON WAITING
typedef enum {
	LOGON		= 0,
	PASSWORD	= 1,
	PASSWD_NEW	= 2,
	PASSWD_CONFIRM	= 3, 
	REGISTER	= 4, 
	WAITING		= 5,
	PLAYING		= 6,
	SCORING		= 7,
	OBSERVING	= 8
} State;

#define NUM_RANKS num_ranks
#define NUM_SPECIAL 2

/*
 * verticies
 */
#define TOP 0
#define MID 1
#define BOT 2

#endif /* SHARED_H */
SHAR_EOF
fi
if test -f 'sound.note'
then
	echo shar: "will not over-write existing file 'sound.note'"
else
cat << \SHAR_EOF > 'sound.note'
From cherokee!csn!ub!zaphod.mps.ohio-state.edu!sdd.hp.com!swrinde!gatech!rutgers!network.ucsd.edu!sdcc12!cs!schraudo Mon Aug  3 09:04:34 MDT 1992
Article: 4285 of rec.games.go
Path: cherokee!csn!ub!zaphod.mps.ohio-state.edu!sdd.hp.com!swrinde!gatech!rutgers!network.ucsd.edu!sdcc12!cs!schraudo
From: schraudo@cs.ucsd.edu (Nici Schraudolph)
Newsgroups: rec.games.go
Subject: xigs software patch: kinder, gentler sound for Sparcstations
Message-ID: <36407@sdcc12.ucsd.edu>
Date: 3 Aug 92 09:27:22 GMT
Sender: news@sdcc12.ucsd.edu
Lines: 59
Nntp-Posting-Host: beowulf.ucsd.edu


Those of you using xigs on Sun Sparcstations to play on IGS may be
interested in the following patch.  It replaces the (to me) annoying
system beep at every move with a high-quality digital recording of a
slate stone hitting a $10,000 board... well OK, it's a bad recording
of me rapping on my desk, but still quite an improvement.  Here goes:

In the xigs source file filter.c, find the place where it says
"case BEEP:".  Replace the fprintf statement just below that with
the command "sound(stone);".  At the top of the file, include the
following, either directly or with a #include directive:

char stone[] = {
    0xae, 0xa9, 0x56, 0x2b, 0xcf, 0xa8, 0xba, 0x30, 0x2a, 0x3a,
    0x38, 0x35, 0x48, 0xbf, 0xa8, 0xab, 0xec, 0x34, 0xcd, 0xaf,
    0xce, 0x32, 0x26, 0x33, 0xc8, 0xaf, 0xbc, 0x3c, 0x34, 0x43,
    0x4b, 0x4e, 0xec, 0xe5, 0x44, 0x4f, 0xbf, 0xbe, 0xcc, 0xbf,
    0xbc, 0x7b, 0x4a, 0xfe, 0xcf, 0xd6, 0x52, 0x34, 0x31, 0x58,
    0xcf, 0xe0, 0x55, 0xc7, 0xbb, 0xce, 0xd0, 0xb8, 0xb7, 0xe9,
    0x40, 0x3f, 0x4f, 0xc8, 0xae, 0xad, 0xc6, 0x71, 0xd8, 0xe4,
    0x4e, 0x4d, 0x4a, 0x34, 0x2d, 0x3d, 0x7b, 0xfe, 0x4e, 0x4d,
    0x66, 0x61, 0x45, 0x45, 0xd5, 0xe0, 0x3d, 0x47, 0xc8, 0xbd,
    0xc6, 0xc8, 0xb8, 0xbb, 0x66, 0x4d, 0xdf, 0xca, 0xd1, 0xcf,
    0xc4, 0xc3, 0x7d, 0x40, 0x4a, 0xe9, 0x61, 0x3c, 0x43, 0xca,
    0xbb, 0xe6, 0x3d, 0x4d, 0xda, 0x49, 0x37, 0x5f, 0xbd, 0xd3,
    0x3f, 0x49, 0xcd, 0xc2, 0xc3, 0xcd, 0xeb, 0x74, 0xec, 0xe9,
    0x7d, 0x79, 0xd8, 0xc5, 0xbe, 0xc4, 0x5c, 0x34, 0x2f, 0x38,
    0x44, 0x3d, 0x42, 0xdc, 0xc8, 0xd0, 0xc9, 0xb5, 0xaf, 0xbd,
    0x5a, 0x40, 0x6a, 0xbb, 0xbd, 0x73, 0x45, 0x4b, 0x5c, 0xff,
    0xc6, 0xbe, 0x66, 0x35, 0x32, 0x36, 0x45, 0xdd, 0xcd, 0xe9,
    0x4d, 0x49, 0x52, 0xe3, 0xc9, 0xc3, 0xc7, 0xca, 0xc7, 0xbf,
    0xbd, 0xce, 0x61, 0xf9, 0xe5, 0x5c, 0x3f, 0x3f, 0x51, 0xe8,
    0xdf, 0x56, 0x48, 0x50, 0x63, 0x56, 0x5a, 0x5f, 0x69, 0xea,
    0xd0, 0xd7, 0xe0, 0xd6, 0xc9, 0xc8, 0xdb, 0xdf, 0xe2, 0xe9,
    0xd9, 0xce, 0x7f, 0x3b, 0x37, 0x4a, 0x53, 0x3c, 0x3d, 0x6a,
    0xc6, 0xb8, 0xb6, 0xc5, 0x5b, 0x41, 0x4a, 0xd0, 0xc4, 0xcf,
    0xd2, 0xdd, 0x65, 0x5c, 0xd6, 0xc7, 0xd2, 0x55, 0x45, 0x4c,
    0x72, 0xed, 0x62, 0x5c, 0xea, 0xd9, 0x63, 0x4e, 0x4f, 0x56,
    0x50, 0x54, 0xe7, 0xd8, 0xf2, 0x00
};

sound(s) char *s;
{
    FILE *fp;

    if (fp = fopen("/dev/audio", "w"))
    {
        fputs(s, fp);
        fclose(fp);
    }
}


Enjoy,
-- 
  Nicol N. Schraudolph, CSE Dept.  |
  Univ. of California, San Diego   |
  La Jolla, CA 92093-0114, U.S.A.  |
  nici%cs@ucsd.{edu,bitnet,uucp}   |   (this mind intentionally left blank)


SHAR_EOF
fi
if test -f 'stipple.bm'
then
	echo shar: "will not over-write existing file 'stipple.bm'"
else
cat << \SHAR_EOF > 'stipple.bm'
/* this is a 50% gray stipple */

#define stipple_width 2
#define stipple_height 2
static unsigned char stipple_bits[] = {
   0x01, 0x02};
SHAR_EOF
fi
if test -f 'stipple2.bm'
then
	echo shar: "will not over-write existing file 'stipple2.bm'"
else
cat << \SHAR_EOF > 'stipple2.bm'
/* This is a 12.5 % gray stipple */

#define stipple_width 4
#define stipple_height 4
static unsigned char stipple_bits[] = {
   0x0e, 0x0f, 0x0b, 0x0f};
SHAR_EOF
fi
if test -f 'stonemask.bm'
then
	echo shar: "will not over-write existing file 'stonemask.bm'"
else
cat << \SHAR_EOF > 'stonemask.bm'
#define stonemask_width 16
#define stonemask_height 16
#define stonemask_x_hot 7
#define stonemask_y_hot 8
static unsigned char stonemask_bits[] = {
   0xc0, 0x03, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f,
   0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xc0, 0x03};
SHAR_EOF
fi
if test -f 'whitestone.bm'
then
	echo shar: "will not over-write existing file 'whitestone.bm'"
else
cat << \SHAR_EOF > 'whitestone.bm'
#define whitestone_width 16
#define whitestone_height 16
#define whitestone_x_hot 7
#define whitestone_y_hot 8
static unsigned char whitestone_bits[] = {
   0xc0, 0x03, 0x30, 0x0c, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x02, 0x40,
   0x01, 0x80, 0x01, 0x80, 0x01, 0x90, 0x01, 0x90, 0x02, 0x48, 0x02, 0x44,
   0x04, 0x23, 0x08, 0x10, 0x30, 0x0c, 0xc0, 0x03};
SHAR_EOF
fi
if test -f 'xigc.c'
then
	echo shar: "will not over-write existing file 'xigc.c'"
else
cat << \SHAR_EOF > 'xigc.c'
/* xigc.c
 * S.Coffin	USWAT	1/93
 *
 * Main X11 program for displaying Goban widget, menus, and etc
 */

/*  Copyright (c) 1992 by Stephen Coffin.  All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behavior
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    scoffin@uswest.com
 */

/* uncomment this if you get X error "Attempt to access private resource
 * failed"  (XGrabKey)   =SC
 */
/*SC #define NOKEYGRAB SC*/

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Box.h>
#include "filter.h"
#include "shared.h"
#include "stipple.bm"

/* the default communications command to execute */
#define CMD "igscomm -h 128.32.201.46 -p 6969"
/* the command to kill the communications proc */
#define QUITCMD "."

/* Use of telnet not recommended =SC */
/* #define CMD "telnet 128.32.201.46 6969" */
/* #define QUITCMD "\nquit" */

/* #define CMD "rlogin uswat" */
/* #define QUITCMD "~." */

/* #define CMD "cu uswat" */
/* #define QUITCMD "~." */

#define USAGE "%s [x-arg-list] [-?] [-c \"command line to execute\"] [-d] [-s]\n"
#define TITLE "xigc Menu"
#define ICONTITLE "xigc Menu"
#define BOARDTITLE "xigc"
#define BOARDICON "xigc Board"

char cmdline[80];
extern int move;
extern int stepmove;
int currentmove;
char stippleflag = FALSE;
char *cmd[80], *quitcmd[80];
static void ClearBoard();

#include "Goban.h"
void SetCursor ();
void read_filter(), read_kbd();
int setup_filter();
int input0id, input1id, input2id;
XtAppContext   app_context;
int dbg = FALSE;
static int cmdflag = FALSE;
static int saveformat = (-1);
static int get_cmd();
int boardchanged = FALSE;
int mouseflag = FALSE;
unsigned char statusflag = FALSE;


/* these fp's are the std i/o when we EXEC a process */
FILE *exec_stdin=NULL, *exec_stdout=NULL, *exec_stderr=NULL;
int gameno=(-1);
int handicap = 0;
extern char observeflag;
int boardsize = 19;
char player1[20], player2[20];
int p1_sec, p2_sec;
int p1_captured, p2_captured;
int p1_byoyomi, p2_byoyomi;

Widget toplevel, bw, goban, refresh, clearb, form, size, coordinates;
Widget stepf, stepb, refreshstep, savecurrent;
Widget cursorcolor, savegame, localrefresh, quit;
Widget gamew, hcapw, whitew, blackw, captw, captb, timew, timeb, lastw;

#define MAXSIZE 19
int colorflag = BLACK;

beep() {
    XBell( XtDisplay(toplevel), 0 );
}

highlight( flag )
	int flag;
{
	static int ff = FALSE;
	int j;
	Arg args[2];
	Pixel fg, bg, xx;

	/* switch highlighting */
	if( (flag && !ff) || (!flag && ff) ) {
		j = 0;
		XtSetArg( args[j], XtNforeground, &fg ); ++j;
		XtSetArg( args[j], XtNbackground, &bg ); ++j;
		XtGetValues( localrefresh, args, j );
		xx = fg;
		fg = bg;
		bg = xx;
		j = 0;
		XtSetArg( args[j], XtNforeground, fg ); ++j;
		XtSetArg( args[j], XtNbackground, bg ); ++j;
		XtSetValues( localrefresh, args, j );

		ff = flag;
	}
}

clearit() {
	GbClearBoard( goban );
}

static void Quit( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	if( cmdflag ) {
	    beep();
	    fprintf( stderr,
		"\nLOCAL: you must log out of IGS and each intermedate system manually\n" );
	    fprintf( stderr, " when using the \"-c\" option\n" );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}

	fprintf( exec_stdin, "quit\n" );
	fflush( exec_stdin );
	sleep( 1 );

	if( quitcmd[0] == '\0' )
		fprintf( exec_stdin, "\n%s\n", QUITCMD );
	else
		fprintf( exec_stdin, "\n%s\n", quitcmd );
	fflush( exec_stdin );
	sleep( 1 );
	rdwr_pclose (NULL, NULL, NULL );
	exit( 0 );
}

static void SaveGame( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	char s[40], s2[40];
	int ret;
	struct stat sbuf;

	if( dbg )
	    fprintf( stderr, "IN SAVEGAME call_data=0x%x\n", client_data );

	if( (client_data == (XtPointer)REALMOVE && (gameno < 0 || move < 1) ) ||
		(client_data == (XtPointer)STEPMOVE && currentmove < 0 ) ) {
	    beep();
	    fprintf( stderr, "\nLOCAL:  No active game to save\n" );
	    fflush( stderr );
	}
	else {
	    if( (int)strlen( player1 ) <= 0 || (int)strlen( player2 ) <= 0 )
		strcpy( s, "no_players" );
	    else sprintf( s, "%s-%s", player1, player2 );

	    /* find an unused filename */
	    strcpy( s2, s );
	    for( ret = 1 ;; ++ret ) {
		if( stat( s2, &sbuf ) == 0 ) {
		    sprintf( s2, "%s.%d", s, ret );
		    continue;
		}
		else break;
	    }

	    if( saveformat == SGF )
	        ret = save_game_sgf( s2, player1, player2, handicap,
						client_data );
	    else
	        ret = save_game( s2, player1, player2, handicap, client_data );
	    if( ret ) {
	       fprintf( stderr, "\nLOCAL:  Game saved to %s\n", s2 );
	       fflush( stderr );
	    }
	}
	fprintf( exec_stdin, "\n" );
	fflush( exec_stdin );
	return;
}

set_cursor_color( m )
	int m;
{
	if( m % 2 ) {
	    colorflag = BLACK;
	    SetCursor( GbCBlackStone );
	}
	else {
	    colorflag = WHITE;
	    SetCursor( GbCWhiteStone );
	}
	return( colorflag );
}
		

void do_refresh( m, w, type )
	int m;
	Widget w;
	int type;
{
	int i, x, y, flag;

	GbClearBoard( goban );
	initboard( boardsize );

	/* handle handicap */
	fprintf( stderr, "\n" );
	if( handicap > 0 ) {
	    sethandicap( handicap, type );
	    update_handicap( handicap );
	    if( w != NULL )
		fprintf( stderr, "  0 (B):  Handicap %d\n", handicap );
	    i = 1;
	}
	else i = 0;

	for( ; i <= m; ++i ) {
	    getmove( i, &x, &y, &flag );
	    if( i%2 ) {
		makemove( x, y, i, GbCWhiteStone, type );
	    }
	    else {
		makemove( x, y, i, GbCBlackStone, type );
	    }
	    if( w != NULL ) {
		fprintf( stderr, "%3d (%c):  ", i, (i%2) ? 'W' : 'B' );
		if( x < 0 ) fprintf( stderr, "Pass\n" );
		else fprintf( stderr, "%c%d\n",
			'A' + ((x > 8) ? x + 1 : x) - 1, y );
	    }
	}

	set_cursor_color( m );

	fflush( stderr );
	fprintf( exec_stdin, "\n" );
	fflush( exec_stdin );
}

void RefreshStep( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	int i;
	int x, y;

	if( move < 0 || gameno < 0 ) {
	    beep();
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL:  No active game to refresh\n" );
	    fflush( stderr );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}
	else if( stepmove < 0 || statusflag ) {
	    beep();
	    return;
	}

	boardchanged = TRUE;
	mouseflag = FALSE;
	do_refresh( stepmove, NULL, STEPMOVE );
	currentmove = stepmove;
	if( stepmove >= move ) {
	    boardchanged = FALSE;
	    highlight( FALSE );
	}
}

void LocalRefresh( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	int i;
	int x, y;

	boardchanged = mouseflag = statusflag = FALSE;

	if( move < 0 || gameno < 0 ) {
	    beep();
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL:  No active game to refresh\n" );
	    fflush( stderr );
	    highlight( FALSE );
	    GbClearBoard( goban );
	    initboard( boardsize );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}

/*SC change "NULL" to "w" to restore print of move list on Refresh(Local) */
	do_refresh( move, NULL, REALMOVE );
	stepmove = currentmove = move;
	highlight( FALSE );
	update_status( gameno, player2, player1, p2_captured, p1_captured,
			p2_sec, p1_sec, p2_byoyomi, p1_byoyomi );
	update_handicap( handicap );
}

static char keyecho = TRUE;

/* This one processes keystrokes when the cursor is in the goban or menu
 *
 * adapted from code donated by loganj@byu.edu
 *
 * CNTRL-P causes echo to be suppressed until the next newline
 */

#ifndef NOKEYGRAB
static void keyevent( w, client_data, event, continue_flag ) 	/* BYU */
	Widget w;
	XtPointer client_data;
	XEvent *event;
	Boolean *continue_flag;
{
  int i;
  KeySym ks;
  XComposeStatus compose;
  KeySym mykey;
  static int tx = 0;
  static char bst[4] = { 8,32,8,0 };
  static char eol[3] = { 13,10,0 };
  static char keytext[32], sendtext[128];

  switch (event->type) {
    case KeyPress :
	i = XLookupString( &event->xkey, keytext, 32, &mykey,
			&compose );

	if( dbg ) fprintf( stderr,
	    "In keyevent KEYPRESS [i=%d, mykey=0x%x tx=%d]  keytext=>>%s<<\n",
				i, mykey, tx, keytext );

	if( i >= 1 && mykey >= 0 ) {
	    if( keytext[0] == '\n' || keytext[0] == '\r') {	/* newline */
		fputs( eol, stderr );

	        sendtext[tx++] = '\n';
	        sendtext[tx] = 0;

		/* got a line, now process it before sending */
		if( process_kbd( sendtext, exec_stdin ) != 0 ) {
	            fprintf( exec_stdin, "%s", sendtext );
	            fflush( exec_stdin );
		}
	        tx = 0;
	        keyecho = TRUE;			/* Allow 1 line of no echo */
	    }
	    else if( keytext[0] == 0x15 ) {	/* delete */
	        while( tx > 0 ) { 
	            tx--;
	            if( keyecho ) fputs( bst, stderr );
	        }
	    }
	    				/* backspace */
	    else if( keytext[0] == 0x08 || mykey == (KeySym)(-1) ) {
	        if( tx > 0 ) { 
	            tx--;
	            if( keyecho ) fputs( bst, stderr );
	        }
	    }
	    else if( keytext[0] == 0x10 ) {	/* CNTRL-P */
	        if( keyecho ) keyecho = FALSE;
	        else keyecho = TRUE;
	    }
	    else if( tx < 127 && keytext[0] >= 0x20 ) {	/* normal char */
	        sendtext[tx++] = keytext[0];
	        keytext[1] = 0;
	        if( keyecho ) fputs( keytext, stderr );
	    }
	}
        break;
    case MappingNotify:
        XRefreshKeyboardMapping (&(event->xmapping));
        break;
    default:
      if( dbg ) fprintf( stderr, "In keyevent Unknown Type 0x%x\n",
		event->type );
      break;
  } 
  fflush( stderr );
}
#endif /* NOKEYGRAB */

static void CursorColor( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	makemove( (-1), (-1), ++currentmove, EMPTY, STEPMOVE );
	boardchanged = mouseflag = TRUE;
	highlight( TRUE );
	set_cursor_color( colorflag+1 );
}

static void StepForward( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	int i, x, y, flag;

	if( move < 0 ) {
	    beep();
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL:  No active game to step\n" );
	    fflush( stderr );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}

	if( stepmove >= move || statusflag ) {
	    beep();
	    return;
	}
	else if( stepmove < 0 ) stepmove = 0;
	else {
	    ++stepmove;
	    currentmove = stepmove;
	}

	if( dbg )
	    fprintf( stderr, "StepForward entered [stepmove=%d, move=%d]\n",
			stepmove, move );

	boardchanged = TRUE;

	if( mouseflag ) {
	    do_refresh( stepmove, NULL, STEPMOVE );
	    mouseflag = FALSE;
	}
	else {
	    if( stepmove == 0 && handicap > 0 ) {
	        sethandicap( handicap, STEPMOVE );
	    }
	    else {
	        getmove( stepmove, &x, &y, &flag );
	        if( stepmove % 2 ) {
	            GbSetPoint( goban, x, y, GbWhiteStone, TRUE );
	    	    makemove( x, y, stepmove, GbWhiteStone, STEPMOVE );
		}
	        else {
	            GbSetPoint( goban, x, y, GbBlackStone, TRUE );
	    	    makemove( x, y, stepmove, GbBlackStone, STEPMOVE );
		}
	    }
	}

	if( stepmove < move ) boardchanged = TRUE;
	else boardchanged = FALSE;

	set_cursor_color( stepmove );
	if( stepmove >= move ) highlight( FALSE );
}

static void StepBack( w, client_data, call_data )
	GobanWidget w;
	XtPointer client_data, call_data;
{
	int x, y, flag;

	if( dbg ) fprintf( stderr, "StepBack entered [stepmove=%d, move=%d]\n",
			stepmove, move );

	if( move < 0 ) {
	    beep();
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL:  No active game to step\n" );
	    fflush( stderr );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}

	if( stepmove < 0 || statusflag ) {
	    beep();
	    return;
	}
	else if( stepmove > move ) stepmove = move;
	else if( stepmove == 0 ) ClearBoard();
	else {

	    boardchanged = TRUE;

	    /* only do full refresh if this move caused any captures, or if
	     * the board is dirty
	     */
	    getmove( stepmove, &x, &y, &flag );
	    if( !flag && !mouseflag ) {
	        GbSetPoint( goban, x, y, GbEmptyPoint, TRUE );
		removemove( stepmove, STEPMOVE );
	        getmove( stepmove-1, &x, &y, &flag );
	        GbSetPoint( goban, x, y, (((stepmove-1)%2)+1), TRUE );
	    }
	    else {
	        do_refresh( stepmove-1, NULL, STEPMOVE );
		mouseflag = FALSE;
	    }
	}

	--stepmove;
	currentmove = stepmove;
	set_cursor_color( stepmove );
	highlight( TRUE );
}

static void InputStone( w, event )
	GobanWidget w;
	XButtonEvent *event;
{
	Position x = event->x;
	Position y = event->y;

	if( GbGetStoneFromPosition( w, &x, &y ) == TRUE ) {
	    if( dbg ) fprintf( stderr, "Input stone at %c%d\n",
				'A' + (x > 8 ? x + 1 : x) - 1, y );
	}
	else {
	    beep();
	    return;
	}

	if( observeflag != PLAYING && observeflag != SCORING ) {
	    beep();
	    return;
	}

	fprintf( exec_stdin, "%c%d\n", 'A' + (x > 8 ? x + 1 : x) - 1, y );
	fflush( exec_stdin );
}

static void AlternateStone( w, event )
    GobanWidget w;
    XButtonEvent *event;
{
	int ob;
	Position x = event->x;
	Position y = event->y;

	if( GbGetStoneFromPosition( w, &x, &y ) == TRUE ) {
	    if( dbg ) fprintf( stderr, "Alternate stone at %c%d\n",
				'A' + (x > 8 ? x + 1 : x) - 1, y );
	}
	else {
	    beep();
	    return;
	}

	if( statusflag ) {
	    beep();
	    return;
	}

	++currentmove;
	if( gameno < 0 ) gameno = 0;
	boardchanged = mouseflag = TRUE;
	if( colorflag == BLACK ) {
	    GbSetPoint( goban, x, y, GbBlackStone, TRUE );
	    makemove( x, y, currentmove, GbBlackStone, STEPMOVE );
	}
	else {
	    GbSetPoint( goban, x, y, GbWhiteStone, TRUE );
	    makemove( x, y, currentmove, GbWhiteStone, STEPMOVE );
	}
	set_cursor_color( colorflag+1 );
	highlight( TRUE );
}


static void RemoveStone( w, event )
    GobanWidget w;
    XButtonEvent *event;
{
	Position x = event->x;
	Position y = event->y;

	if (GbGetStoneFromPosition (w, &x, &y) == TRUE) {
	    if( dbg ) fprintf ( stderr, "Remove stone at %c%d\n",
					'A' + (x > 8 ? x + 1 : x) - 1, y);
	}

	if( statusflag ) {
	    beep();
	    return;
	}

	/* XXX there is a slight glitch here: we do not remove stones
	 * from the board table, so they still interact when testing
	 * for dead stone removal and "Refresh(Local)"
	 */
	GbSetPoint( goban, x, y, GbEmptyPoint, TRUE );

	boardchanged = mouseflag = TRUE;
	highlight( TRUE );
}

void Ticker( client_data, timer )
	XtPointer client_data;
	XtIntervalId *timer;
{
	XtAppAddTimeOut( (XtAppContext)client_data, 1000, Ticker, client_data );
	if( move < 0 || !observeflag || statusflag ) return;

	else if( move % 2 ) {
	    if( dbg ) fprintf( stderr, "TIMER EVEN [B]\n" );
	    --p2_sec;
	    fix_btime( p2_sec, p2_byoyomi );
	}
	else {
	    if( dbg ) fprintf( stderr, "TIMER ODD [W]\n" );
	    --p1_sec;
	    fix_wtime( p1_sec, p1_byoyomi );
	}
}

void SetCursor ( cs )
	int cs;
{
	Arg args[1];

	switch (cs) {
	    case GbCBlackStone : 
		XtSetArg   (args[0], XtNcursor, GbCBlackStone);
		if( dbg ) fprintf ( stderr, "Set cursor to : Black \n"); 
		break;
	    case GbCWhiteStone : 
		XtSetArg   (args[0], XtNcursor, GbCWhiteStone );
		if( dbg ) fprintf ( stderr, "Set cursor to : White\n"); 
		break;
	    case XC_question_arrow :
		XtSetArg   (args[0], XtNcursor, XC_question_arrow );  
		if( dbg ) fprintf ( stderr, "Set cursor to : Question\n"); 
		break;
	}

	XtSetValues (goban, args, 1);
}

void RefreshHost( w, client_data, call_data )
    GobanWidget w;
    XtPointer client_data, call_data;
{
	if( gameno < 0 ) {
	    beep();
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL:  No active game to refresh\n" );
	    fflush( stderr );
	    highlight( FALSE );
	    GbClearBoard( goban );
	    initboard( boardsize );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	}
	else {
	    SetCursor ( GbCBlackStone );
	    move = (-1);
	    refreshboard();
	    fprintf( exec_stdin, "moves %d\n", gameno );
	    fflush( exec_stdin );
	}
}

int refreshboard() {
	if( gameno < 0 ) {
	    highlight( FALSE );
	    fprintf( stderr, "\nLOCAL: No active game to refresh\n" );
	    fflush( stderr );
	    fprintf( exec_stdin, "\n" );
	    fflush( exec_stdin );
	    return;
	}

	boardchanged = mouseflag = statusflag = FALSE;
	highlight( FALSE );
	GbClearBoard( goban );
	stepmove = (-1);
	currentmove = (-1);
	handicap = 0;
	update_handicap( 0 );
	initboard( boardsize );
}

static void ClearBoard() {
	GbClearBoard( goban );
	stepmove = (-2);
	currentmove = (-1);
	boardchanged = TRUE;
	mouseflag = FALSE;
	highlight( TRUE );
	set_cursor_color( 1 );
	clear_stepboard();
}

static void SetSize() {
	Arg       args[1];
	static int beenhere = FALSE;

	if( !beenhere ) {
	    boardsize = 13;
	    beenhere = TRUE;
	}

	switch( boardsize ) {
	case 9:
	    boardsize = 13;
	    break;
	case 13:
	    boardsize = 19;
	    break;
	case 19:
	default:
	    boardsize = 9;
	    break;
	}

	if( dbg ) fprintf ( stderr, "Set size to : %d\n", boardsize);

	set_cursor_color( 1 );

	XtSetArg( args[0], XtNgameSize, (Dimension)boardsize );
	XtSetValues( goban, args, 1 );
}

static void SetCoordinates() {
	Arg     args[1];
	Boolean coordinates;

	XtSetArg    (args[0], XtNdisplayCoordinates, &coordinates);
	XtGetValues (goban, args, 1);
	
	switch (coordinates) {
	    case FALSE : 
		XtSetArg (args[0], XtNdisplayCoordinates, TRUE) ; 
		if( dbg ) fprintf( stderr, "Set coordinates to : TRUE \n");
		break;
	    case TRUE  : 
		XtSetArg (args[0], XtNdisplayCoordinates, FALSE); 
		if( dbg ) fprintf( stderr, "Set coordinates to : FALSE \n");
		break;
	}

	XtSetValues (goban, args, 1);
}

static void SetupBoard() {
	char s[40];
	
	XtPopup (bw, XtGrabNone);
	SetSize();
	set_cursor_color( 1 );
	sprintf( s, "%s [%s]", BOARDTITLE, PATCHLEVEL );
	XSetStandardProperties( XtDisplay(bw), XtWindow(bw),
			s, BOARDICON, NULL, NULL, 0, NULL );

}



static void Redisplay() {
	GbRedisplayBoard (goban);
}

XtActionsRec actions[] = {
	{ "inputStone", (XtActionProc)InputStone },
	{ "removeStone", (XtActionProc)RemoveStone },
	{ "addStone", (XtActionProc)AlternateStone },
};

main( argc, argv )
	int argc;
	char **argv;
{
	extern void exit ();
	extern char *optarg;
	extern int optind;
	int c;
	int xtargc = 0;
	Arg args[8];
	int j;
	extern int getopt();

	get_cmd();
	if( cmd[0] == '\0' ) strcpy( cmdline, CMD );
	else strcpy( cmdline, (char *)cmd );

	initboard( boardsize );
	move = stepmove = (-1);
	currentmove = (-1);
	statusflag = FALSE;

	toplevel = XtAppInitialize( &app_context, "XIgc", NULL, 0, &argc, argv,
			NULL, NULL, 0);

	/* any more command-line args? */
	while( (c=getopt( argc, argv, "?c:ds" )) != (-1) ) {
	    switch( c ) {
		case 'd':	/* debug mode */
		    dbg = TRUE;
		    break;
		case 's':	/* stippled board */
		    stippleflag = TRUE;
		    break;
		case 'c':	/* command line for comm program */
		    strcpy( cmdline, optarg );
		    cmdflag = TRUE;
		    break;
		case '?':
		default:
		    fprintf( stderr, "%s: Release %s\n", argv[0], PATCHLEVEL );
	    	    fprintf( stderr, USAGE, argv[0] );
		    exit( (-1) );
		    break;
	    }
	}

	if( optind != argc ) {
	    fprintf( stderr, "%s: Release %s\n", argv[0], PATCHLEVEL );
	    fprintf( stderr, USAGE, argv[0] );
	    exit( (-1) );
	}

	bw = XtCreatePopupShell( "board", topLevelShellWidgetClass, toplevel,
			NULL, 0);
	form = XtCreateManagedWidget( "form", formWidgetClass, toplevel, NULL,
			0);
	j = 0;
	XtSetArg(args[j], XtNlabel, "Game:               " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	gamew = XtCreateManagedWidget( "gamew", labelWidgetClass, form,
					    args, j );

	j = 0;
	XtSetArg(args[j], XtNlabel, "Handicap:           " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	hcapw = XtCreateManagedWidget( "hcapw", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "White:              " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	whitew = XtCreateManagedWidget( "whitew", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Black:              " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	blackw = XtCreateManagedWidget( "blackw", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Captured:           " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	captw = XtCreateManagedWidget( "captw", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Captured:           " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	captb = XtCreateManagedWidget( "captb", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Time:               " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	timew = XtCreateManagedWidget( "timew", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Time:               " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	timeb = XtCreateManagedWidget( "timeb", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg(args[j], XtNlabel, "Last:                                     " ); ++j;
	XtSetArg(args[j], XtNjustify, XtJustifyLeft ); ++j;
	lastw = XtCreateManagedWidget( "lastw", labelWidgetClass, form,
					    args, j );
	j = 0;
	XtSetArg( args[j], XtNgameSize, 19 ); ++j;
	XtSetArg( args[j], XtNcursor, GbCBlackStone); ++j;
	goban = XtCreateManagedWidget( "goban", gobanWidgetClass, bw, args,
			j);

	refresh = XtCreateManagedWidget( "refresh", commandWidgetClass, form,
			NULL, 0);
	cursorcolor = XtCreateManagedWidget( "cursorcolor", commandWidgetClass,
			form, NULL, 0);
	clearb = XtCreateManagedWidget( "clearb", commandWidgetClass, form,
			NULL, 0);
	stepf = XtCreateManagedWidget( "stepf", commandWidgetClass, form, NULL,
			0);
	stepb = XtCreateManagedWidget( "stepb", commandWidgetClass, form, NULL,
			0);
	refreshstep = XtCreateManagedWidget( "refreshstep", commandWidgetClass,
			form, NULL, 0);

	localrefresh = XtCreateManagedWidget( "localrefresh",
			commandWidgetClass, form, NULL, 0);
	size = XtCreateManagedWidget( "size", commandWidgetClass, form, NULL,	
			0);
	savegame = XtCreateManagedWidget( "savegame", commandWidgetClass,
			form, NULL, 0);
	savecurrent = XtCreateManagedWidget( "savecurrent", commandWidgetClass,
			form, NULL, 0);
	coordinates = XtCreateManagedWidget( "coordinates", commandWidgetClass,
			form, NULL, 0);
	quit = XtCreateManagedWidget( "quit", commandWidgetClass, form, NULL,
			0);

	XtAppAddActions (app_context, actions, XtNumber(actions));

	XtAddCallback (refresh, XtNcallback, (XtCallbackProc)RefreshHost,
			NULL);
	XtAddCallback (cursorcolor, XtNcallback, (XtCallbackProc)CursorColor,
			NULL); 
	XtAddCallback (clearb, XtNcallback, (XtCallbackProc)ClearBoard, NULL);
	XtAddCallback (stepf, XtNcallback, (XtCallbackProc)StepForward, NULL);
	XtAddCallback (stepb, XtNcallback, (XtCallbackProc)StepBack, NULL);
	XtAddCallback (refreshstep, XtNcallback, (XtCallbackProc)RefreshStep,
			NULL);
	XtAddCallback (localrefresh, XtNcallback, (XtCallbackProc)LocalRefresh,
			NULL);
	XtAddCallback (size, XtNcallback, (XtCallbackProc)SetSize, NULL);
	XtAddCallback (savegame, XtNcallback, (XtCallbackProc)SaveGame,
			(XtPointer)REALMOVE );
	XtAddCallback (savecurrent, XtNcallback, (XtCallbackProc)SaveGame,
			(XtPointer)STEPMOVE );
	XtAddCallback (coordinates, XtNcallback, (XtCallbackProc)SetCoordinates,
			NULL);
	XtAddCallback (quit, XtNcallback, (XtCallbackProc)Quit, NULL);

	XtRealizeWidget (toplevel);

        XSetStandardProperties( XtDisplay(toplevel), XtWindow(toplevel),
		TITLE, ICONTITLE, NULL, argv, argc, NULL );

	SetupBoard();

	/* grab keystrokes when mouse is in board or menu windows */
#ifndef NOKEYGRAB
	XtGrabKey( bw, AnyKey, AnyModifier, FALSE, 
		GrabModeAsync, GrabModeAsync );
	XtAddEventHandler( bw, KeyPressMask | KeymapStateMask, FALSE, 
		(XtEventHandler)keyevent, NULL );

	XtGrabKey(toplevel, AnyKey, AnyModifier, FALSE, 
		GrabModeAsync, GrabModeAsync);
	XtAddEventHandler(toplevel, KeyPressMask | KeymapStateMask, FALSE, 
		(XtEventHandler)keyevent, NULL);
#endif /* NOKEYGRAB */

	setup_filter( &exec_stdin, &exec_stdout, &exec_stderr );
	input0id = XtAppAddInput( app_context, fileno(stdin),
		(XtPointer)(XtInputReadMask), read_kbd,
		(caddr_t)fileno(stdin) );
	input1id = XtAppAddInput( app_context, fileno(exec_stdout),
		(XtPointer)(XtInputReadMask), read_filter,
		(caddr_t)fileno(exec_stdout) );
	input2id = XtAppAddInput( app_context, fileno(exec_stderr),
		(XtPointer)(XtInputReadMask), read_filter,
		(caddr_t)fileno(exec_stderr) );

	XtAppAddTimeOut( XtWidgetToApplicationContext(toplevel), 1000, Ticker,
			 XtWidgetToApplicationContext(toplevel) );
	XtAppMainLoop (app_context);
}


/* this one reads input from the comm channel, prints it, and also
 * calls process_input for parsing
 */
void read_filter( client_data, source, id )
	int client_data;
	int *source;
	char *id;
{
	char str[LINESIZE+1], *s;
	int ret, i, code;

	if( dbg ) fprintf( stderr,
		"********* in read_filter() fd=%d **********\n", client_data );
	ret = read( client_data, str, LINESIZE );
	if( ret <= 0 ) {
	    XtRemoveInput( input1id );
	    XtRemoveInput( input2id );
	    fprintf( stderr, "Closing pipes to comm process\n" );
	    return;
	}
	else str[ret] = '\0';

	/* just check once more to be sure we have only 7-bit chars */
	for( i=0; i<ret; ++i ) str[i] &= 0x7f;

	process_input( str );

	if( dbg ) fprintf( stderr,
		"######### leave read_filter() [%d chars] #########\n", ret );
}

/* this one just reads lines from the kbd and passes them to comm stdin */
void read_kbd( client_data, source, id )
	int client_data;
	int *source;
	char *id;
{
	char str[LINESIZE+1];
	int ret;

	if( dbg ) fprintf( stderr,
		"********* in read_kbd() fd=%d **********\n", client_data );
	ret = read( client_data, str, LINESIZE );
	if( ret <= 0 ) {
	    fprintf( stderr, "\nKBD: no input!  (ignored)\n" );
	    return;
	}
	else str[ret] = '\0';

	/*XXX got to do something about the CTRL-P to make it work right
	 * when cursor is in xterm window
	 */

	if( process_kbd( str, exec_stdin ) != 0 ) {
	    fputs( str, exec_stdin );
	    fflush( exec_stdin );
	}

	if( dbg ) fprintf( stderr,
		"######### leave read_kbd() [%d chars] #########\n", ret );
}

setMark( i, j, t )
	int i, j;
	unsigned char t;
{
	GbSetMark( goban, (Position)i, (Position)j, t, 0 );
}

drawStone( i, h, t, flag )
	int i, h;
	int t;	/* 0=remove, 1=black, 2=white */
	unsigned char flag;
{
	if( dbg ) fprintf( stderr, "Drawing stone at %d,%d  (%d)\n", i, h, t );
	GbSetPoint( goban, i, h, t, flag );

}

update_status( g, black, white, bcapt, wcapt, btime, wtime, bbyo, wbyo )
	int g;
	char *white, *black;
	int wcapt, bcapt, wtime, btime;
	int bbyo, wbyo;
{
	Arg args[8];
	int j;
	char str[80];

	update_gameno( g );

	if( g < 0 ) sprintf( str, "Black:" );
	else sprintf( str, "Black: %s", black );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( blackw, args, j );

	if( g < 0 ) sprintf( str, "White:" );
	else sprintf( str, "White: %s", white );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( whitew, args, j );

	if( g < 0 ) sprintf( str, "Captured:" );
	else sprintf( str, "Captured: %d", wcapt );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( captw, args, j );

	if( g < 0 ) sprintf( str, "Captured:" );
	else sprintf( str, "Captured: %d", bcapt );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( captb, args, j );

	fix_wtime( wtime, wbyo );
	fix_btime( btime, bbyo );
}

update_move( last )
	char *last;
{
	int i, j;
	char str[80];
	Arg args[8];

	if( last == NULL ) sprintf( str, "Last:" );
	else {
	    sprintf( str, "Last: %s", last );
	    for( i=0; str[i] != '\0' && str[i] != '\r' && str[i] != '\n'; ++i );
	    str[i] = '\0';
	}

	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( lastw, args, j );
}

update_handicap( hcap )
	int hcap;
{
	Arg args[8];
	int j;
	char str[80];

	if( hcap < 0 ) sprintf( str, "Handicap:" );
	else sprintf( str, "Handicap: %d", hcap );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( hcapw, args, j );
}

update_gameno( g )
	int g;
{
	Arg args[8];
	int j;
	char str[80];

	if( g < 0 ) sprintf( str, "Game:" );
	else sprintf( str, "Game: %d", g );
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( gamew, args, j );
}

/* get the server config file, with command line to execute, if any
 * return (-1) if no
 *	1) a file $HOME/.xigcrc
 *	2) in this file:
 *		COMMAND   cmd line to execute
 *		QUITCOMMAND cmd to quit from "cmd"
 *		SAVEFORMAT  SGF or TEXT format for "Save game" menu item
 */
static int get_cmd() {
	char *ret;
	FILE *fp;
	char str[80];
	int cnt = 0;
	extern char *getenv();
	int len;

	cmd[0] = '\0';
	quitcmd[0] = '\0';

	ret = getenv( "HOME" );
	if( ret == NULL ) return( cnt );

	sprintf( str, "%s/.xigcrc", ret );
	if( dbg ) fprintf( stderr, "config file: >>%s<<\n", str );
	fp = fopen( str, "r" );
	if( fp  == NULL ) {
	    if( dbg ) fprintf( stderr, "can't open config file >>%s<<\n", str );
	    return( cnt );
	}
	
	while( fgets( str, 80, fp ) != NULL ) {
	    len = strlen( str );
	    if( len < 4 || str[0] == '#' ) continue;
	    str[len-1] = '\0';
	    if( dbg ) fprintf( stderr, ">>%s<<\n", str );
	    if( strncmp( str, "COMMAND", 7 ) == 0 ) {
		if( cmd[0] == '\0' ) {
		    strcpy( (char *)cmd, &str[8] );
		    if( dbg ) fprintf( stderr, "get_cmd: cmd >>%s<<\n" , cmd );
		    ++cnt;
		}
	    }
	    if( strncmp( str, "QUITCOMMAND", 11 ) == 0 ) {
		if( quitcmd[0] == '\0' ) {
		    strcpy( (char *)quitcmd, &str[12] );
		    if( dbg ) fprintf( stderr, "get_cmd: quitcmd >>%s<<\n",
					quitcmd );
		    ++cnt;
	        }
	    }
	    if( strncmp( str, "SAVEFORMAT", 10 ) == 0 ) {
		if( saveformat == (-1) ) {
		    if( strncmp( &str[11], "TEXT", 4 ) == 0 ||
		        strncmp( &str[11], "text", 4 ) == 0 ) saveformat = TEXT;
		    else if( strncmp( &str[11], "SGF", 3 ) == 0 ||
		        strncmp( &str[11], "sgf", 3 ) == 0 ) saveformat = SGF;
		    ++cnt;
		}
	    }
	}

	fclose( fp );
	return( cnt );
}

fix_wtime( wtime, wbyo )
	int wtime;
	int wbyo;
{
	Arg args[8];
	int j;
	char str[80];

	if( wbyo > 0 ) {
	    sprintf( str, "Byo Yomi: %d:%02.2d  %d",
		wtime/60, wtime%60, wbyo );
	}
	else {
	    sprintf( str, "Time: %d:%02.2d", wtime/60, wtime%60 );
	}
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( timew, args, j );
}

fix_btime( btime, bbyo )
	int btime, bbyo;
{
	Arg args[8];
	int j;
	char str[80];

	if( bbyo > 0 ) {
	    sprintf( str, "Byo Yomi: %d:%02.2d  %d",
		btime/60, btime%60, bbyo );
	}
	else {
	    sprintf( str, "Time: %d:%02.2d", btime/60, btime%60 );
	}
	j = 0;
	XtSetArg(args[j], XtNlabel, str ); ++j;
	XtSetValues( timeb, args, j );
}
SHAR_EOF
fi
if test -f 'xigc.man'
then
	echo shar: "will not over-write existing file 'xigc.man'"
else
cat << \SHAR_EOF > 'xigc.man'
.TH xigc 1 "1/93"
.SH NAME
xigc \- X Window System Interface for the Internet Go Server
.br
igscomm \- Simple Communications Interface for the Internet Go Server
.SH SYNOPSIS
.in +.5i
.ti -.5i
.B
xigc [-TypicalXArgs] [-c "command line for communications"] [-s] [-d]
.P
.ti -.5i
.br
.B
igscomm [-d] [-e] [-h host-address] [-p port-address]
.P
.in -.5i
.SH DESCRIPTION
.B "xigc"
provides an X Window System interface to the Internet
Go Server (IGS).  It works with
.B "cu"
and
.B "rlogin"
for indirect access through intermediate machines, as well as
.B "telnet"
or other socket-based communications programs for direct Internet
access to IGS.
.B "igscomm,"
a primitive version of
.B "telnet,"
is also included.  Because of bugs associated with telnet use,
.B "xigc"
users are STRONGLY urged to use
.B "igscomm"
as their communications program if possible.  Use of
.B "telnet"
is NOT recommended.
.sp
.B "xigc"
provides a go board window, a menu window, and a communications
stream between the user and the IGS.  The communications window is just the
.B "xterm"
window when the application was executed.  All manual IGS commands
continue to work as usual, except that when the user is playing or observing
a game, moves are displayed on the go board in its own window.  When playing
a game, the user can click on a point on the board to send a move at that
point to the IGS.
.SH INSTALLATION
After unpacking the source distribution, use
.B "xmkmf"
followed by
.B "make depend"
to generate a Makefile for your environment.  
If you do not have
.B "xmkmf"
or
.B "imake,"
you may be able to adapt the file
.B "Makefile.hand,"
and use it as a Makefile for your system.
Then type
.B "make"
and then
.B "make install"
to install
.B "xigc"
and
.B "igscomm"
in your standard locations.
.sp
Make sure the file
.B "XIgc.ad"
is placed in your standard place for X11
application defaults (and named
.B "XIgc),"
or added to your
.B ".Xdefaults."
You can also do
.ti 10
.B
xrdb -merge XIgc.ad
.br
.P
after you start X but before running
.B "xigc."
You must do one of these things or
.B "xigc"
will not run!
.B "make install"
should install this file correctly.
.SH "XIGC COMMAND LINE"
Execute
.B "xigc"
from an
.B "xterm"
window.  This is required since the standard I/O
between the IGS and the user is handled through this window.  That is,
you cannot make
.B "xigc"
run from a menu item unless it is run through the
.B "-e"
option on an
.B "xterm"
window.
.sp
If you run
.B "xigc"
alone with no command-line arguments, it uses
.B "igscomm"
command for Internet communications, or you can use
.ti 10
.B
xigc -c "command line in quotes"
.br
.P
where the command line is another communications program you select.
For example:
.ti 10
.B
xigc -c "telnet 128.32.201.46 6969"
.P
.br
or
.ti 10
.B
xigc -c "cu uswat"
.P
.br
In addition to
.B "igscomm,"
the communications methods
.B "cu, rlogin"
and one version of
.B "telnet"
have been tested.  Most communications programs
should work, but your mileage may vary.  Note that
.B "telnet"
has some problems and should be avoided if possible.  Use
.B "igscomm"
if you can.  Even 1200 baud connections have acceptable performance!
.sp
You can change the default command by modifying a couple of #define lines
near the top of xigc.c, and/or by creating a personal command file (see below).
When you do this, you must also specify a character
sequence that is used to exit from the communications command.
.sp
You can also place many common X Window System parameters on the
.B "xigc"
command line.  If you do this, place all X arguments before any
.B "xigc"
arguments on the command line.  You will need to experiment to see
which X arguments work, and which items must be specified in the
application defaults.
.sp
Use the
.B "-s"
option to display the board with a light-gray stippled pattern instead
of a solid color.  This feature is most useful if you have a monochrome
display.  You can change the entry
.B "XIgc*goban*stipple"
in your application defaults file to be
.B "true"
to turn on stippling.  If you do this, the
.B "-s"
option will turn stippling off.
.sp
Other
.B "xigc"
command line options include
.B "-d"
(for debugging; not recommended).
.sp
There is another method of setting the communications command
name to execute.
You may place these commands in a file
.B "$HOME/.xigcrc."
For example:
.br
.ti 10
$ cat $HOME/.xigcrc
.br
.ti 10
COMMAND igscomm -h 128.32.201.46 -p 6969
.ti 10
.br
QUITCOMMAND .
.sp
Do not use any equal signs or quotes in your
.B .xigcrc
file.  The order of priority for these commands is
compiled-in defaults lowest, then
.B .xigcrc
file, and command-line option
highest.
.SH "SETUP"
After logging into the IGS for the first time with
.B "xigc,"
type
.ti 10
.B
toggle client on
.P
.br
to set up the IGS for communications with
.B "xigc."
If you go back to direct
.B "telnet"
connections to the IGS, you will need to
.ti 10
.B
toggle client off
.P
.br
and
.ti 10
.B
toggle verbose on
.P
.br
to restore your IGS environment to its original state.
.sp
When you are using
.B "igscomm"
or
.B "telnet"
through an intermediate system, such as with
.B "cu"
or
.B "rlogin,"
you may find that commands are echoed twice.  You can turn off
this extra echo by adding the
.B "-e"
command-line option for
.B "igscomm,"
or using the
.B "telnet"
command
.B "^E"
(CNTRL-E).  When you execute
.B "igscomm"
or
.B "telnet"
directly from
.B "xigc,"
you should not get the extra echo, and the
.B "^E"
or
.B "-e"
should not be needed.
.sp
Note that
.B "igscomm"
must run on the machine that is directly connected to the Internet,
or your gateway machine.
It does not support connection across multiple systems.
.sp
The application defaults set many of the options for how
.B "xigc"
will look and perform in your environment.  You can set the size,
color, labels, and other information in the
.B "XIgc"
file, or change the items in your
.B ".Xdefaults"
file.  Look at the X Window System documentation and the
.B "XIgc.ad"
file for more information about setting size, color, screen location,
and other display variables.
.SH "USE"
You can type commands into the
.B "xigc"
windows, or place a stone by clicking
the left mouse button at a location on the board, or remove a stone by
clicking the middle mouse button over a stone on the board.  The left
button sends a move to the IGS, but the middle button just removes a stone
from the board locally.  Use the menu to change the color of the placed
stone (and the cursor), refresh the board, save the game to a file,
exit, etc.
.sp
If the cursor is over the board or menu window (but not over the
command window), you can type CNTRL-P to disable character echo for
the rest of that input line.  This allows you to type in any passwords
or other information without displaying them to any observers.
Currently this feature does not work if the cursor is over the
.B "xterm"
or command window.
.sp
Mouse button 3 (right button) places a stone on the board locally,
but does not send the move to the host.  It also changes the color
of the stone for the next click, so that you can
play games or sequences locally by using button 3.
You can restore the game to its "real" state
with the "Refresh (Local)" menu item.  Stones placed with button 3
are not saved to a file with "Save Moves", but can be saved with
"Save to Current," which saves the current board position as a "game."
.sp
You can step back one move in the current game using the "Step Back" menu
item, and can step forward with "Step Forward."  If you add stones
to the board with button 3 from a stepped position (not the current
"real" board position), you may use "Refresh to Step" to restore the
board to the current step.  To step through a game from the beginning,
load the game with "observe n" or "Refresh (Host)", then "Clear" the
board, then "Step Forward" until you reach the last move played.
Note that when you have changed the board from the "real" game
position, either by stepping or by using button 2 or 3,  incoming moves
are not immediately displayed on the board.  Instead, incoming moves
cause the terminal to beep, and the "Refresh (Local)" menu item becomes
highlighted.  You must restore the game to its "real" state (usually
with "Refresh (Local)") before incoming moves are again displayed
as they arrive.
.sp
You can also look at a game you are not observing by using the IGS
command "status n," where n is the game number you wish to look at.
This causes the board to switch to the game you request.  This
display is not active, and you cannot step forward or back, or
add stones with the mouse buttons.  You must restore the observed
(or played) game with "Refresh (Local)" to reactivate normal
.B "xigc"
behavior.
.sp
By default, the "Save Moves" and "Save Current" menu items
will save the current game
in a human-readable text format.  However, you can specify that
games be saved in the machine-readable SGF format if you wish.
To use SGF format, include the line
.ti 10
.B
SAVEFORMAT sgf
.P
.br
in your
.B ".xigcrc"
file.  Use
.ti 10
.B
SAVEFORMAT text
.P
.br
for the default behavior.
.sp
The local command
.B "gameno"
takes a number that sets the current game within
.B "xigc."
For example, to look at a game when you have first started
.B "xigc,"
use the command
.B "gameno 2"
to set
.B "xigc"
for game 2, then click "Refresh (Host)" to
display the moves of that game.
When playing or observing, the game number
is tracked automatically.  That is, if you use the IGS commands
.B "observe, moves"
or
.B "match,"
you do not need to use
.B "gameno."
Another way to look at a game in progress without observing it is with the
.B "moves n"
command, where
.B "n"
is the number of the game you wish to look at.  When you use
.B "moves n,"
you can step through the game moves; you cannot use
.B "moves"
while you are observing or playing another game.
.sp
The local command
.B "observeoff"
will stop observing a game in progress, but is not needed
when the game ends or is adjourned.  You can only play or observe
one game; you cannot observe multiple games with
.B "xigc."
.sp
When a game you are playing is near the end, and players have
made the three required passes, IGS will prompt "Type done when
finished" to signal you are to remove dead stones.  To do this with
.B "xigc,"
just place the cursor over a stone you wish to remove, and click
the left mouse button.  The stones will be removed at IGS and locally
within
.B "xigc."
When you and your opponent have removed all the dead
stones, type "done" to have IGS to score the game and redraw the
final board position on the
.B "xigc"
board.  Note that he final "on-the-board" point count, including captures
and territory, will be shown in the "Captured" lines in the
.B "xigc"
menu.  This final count does not include any komi associated
with the game, and so is not the correct final score.
.sp
The "Quit" menu item will not work if you have used the
.B "-c"
command-line option, since
.B "xigc"
does not know how to exit cleanly from any random user-specified
communications command.  You must exit from each intermediate
system manually.
.SH "IGSCOMM"
.B "igscomm"
is a very simple replacement for
.B "telnet"
for communications to the IGS.  If possible, use
.B "igscomm"
instead of
.B "telnet"
as your communications program with
.B "xigc."
.B "igscomm"
can take the
.B "-h"
argument, followed by a host address, and the
.B "-p"
argument, followed by a port (socket) number at that host.  These
arguments are only needed if you are calling a machine other than
the default IGS.  You can also use the
.B "-e"
argument with
.B "igscomm"
if you are using it through an intermediate system (i.e., with the
.B "-c"
option of
.B "xigc.)"
The
.B "-e"
option turns off the extra echo otherwise seen with intermediate
systems.  For example:
.ti 10
.B
igscomm -e -h cnam.cnam.fr -p 6969
.P
.sp
Exit from
.B "igscomm"
by entering a single dot on a line.
.SH "CAVEATS"
This code may not work on X11R3 or older releases of X Window System,
or on some SVR3 systems on 386 machines.  It has been tested with
Sun (X11R4 and X11R5), 386/SVR4 (X11R5), DEC (UNIX and VMS), HP (and Apollo),
SGI, MIPS (X11R4), Convex, and IBM RS6000 (AIX 3.2) systems.
.sp
This is not a general purpose terminal emulator; it was designed to work
with the IGS.  Output lines from intermediate systems that begin with numbers
may be mangled by
.B "xigc."
.SH "ACKNOWLEDGEMENTS"
The go board was adapted from the "Goban Widget" by dumesnil@etca.fr.
Code for dead stone management was adapted from
adrian@u.washington.edu, and some pieces concerned with syntax of I/O
between the user and the IGS came from tcasey@leo.unm.edu.  Thanks
to several other users for contributing ideas and code fragments, especially
loganj@byu.edu.
.sp
The IGS is currently on the machine icsib18.icsi.berkeley.edu (128.32.201.46)
at port 6969.  Another server may be at cnam.cnam.fr (192.33.159.6).
.SH "AUTHOR"
S.Coffin	 scoffin@uswest.com
.SH "BUGS"
.nf
.so README
.fi
SHAR_EOF
fi
exit 0
#	End of shell archive
