[comp.windows.x] patch for contrib/paint

dheller@cory.Berkeley.EDU (Dan Heller) (06/01/88)

I have gone over the paint program distributed with the X11R2 code
enough to make it work as it was probably intended by the original
author (except that I added rubberbanding).  The changes included
here are intended to patch only -- no additional features are added
and serious attempts at buidling a draw program should not be based
on this model.  See the modified README after applying these patches.

--------------------------------------------------------------------
*** paint.orig/README	Thu Feb 25 23:01:33 1988
--- README	Tue May 31 15:29:00 1988
***************
*** 1,12 ****
  Read carefully; this is the only documentation there is!
  
  The paint program takes no paramaters.  It makes a connection to
! $DISPLAY, and opens a window near the upper-left corner of the screen.
  
  Paint is very modal.  There are keyboard commands to change the modes. 
  Type the commands at the window on the X11 display.  The current mode
! is displayed on stdout.  (I would like to display the current mode on
! the X11 window, but I couldn't get fonts to work.)
  
  Some of the keyboard commands take an integer argument.  To specify an
  argument, type a number (with an optional minus sign) before the key
--- 1,22 ----
+ This program has been updated by Dan Heller <island!argv@sun.com>
+ to make it work with X11R2 and in the manner probably desired by
+ the original author.  Reader's note: "paint" is a misnomer because
+ this package maintains a display list of objects.  Paint packages
+ are not object based, but pixel based.  This is really a simplified
+ draw package intended to show examples of how some of the graphics
+ rendering machanisms work.  What follows is the original README file
+ modified to reflect my changes.
+ 	--Dan Heller 5/31/88 <island!argv@sun.com>
+ --------
+ 
  Read carefully; this is the only documentation there is!
  
  The paint program takes no paramaters.  It makes a connection to
! $DISPLAY.
  
  Paint is very modal.  There are keyboard commands to change the modes. 
  Type the commands at the window on the X11 display.  The current mode
! is displayed on the top of the window.
  
  Some of the keyboard commands take an integer argument.  To specify an
  argument, type a number (with an optional minus sign) before the key
***************
*** 14,23 ****
  
  a	Draw an arc.  When the user drags through a rectangle with the
  mouse, an arc will be inscribed in that rectangle (from angle1 to angle2).
  
  A	Draw a filled arc.  Same as above, but arc will be filled.
  
! C	Clear the window.
  
  f	Change the alu function.  This takes an argument from 0 to 15.
  
--- 24,34 ----
  
  a	Draw an arc.  When the user drags through a rectangle with the
  mouse, an arc will be inscribed in that rectangle (from angle1 to angle2).
+ Default set to 360 degrees and 0 degrees (a complete ellipse).
  
  A	Draw a filled arc.  Same as above, but arc will be filled.
  
! C	Clear the window (also clears display list).
  
  f	Change the alu function.  This takes an argument from 0 to 15.
  
***************
*** 24,34 ****
  l	Draw lines.  When the user drags through the window, a line
  will be drawn from where he presses the button to where he releases it.
  
! p	Draw polygons.  Specify several points on the screen by
! clicking with the left button.  Specify the last point with the right
! button.  A polygon will be drawn connecting the points in order.  (This
! isn't a real polygon; it won't automatically connect the first and last
! points for you.  This is just a test for XLines().)
  
  P	Draw filled polygons.  Same as above, but the polygon will be
  filled.  (The first and last points are connected by the server.)
--- 35,41 ----
  l	Draw lines.  When the user drags through the window, a line
  will be drawn from where he presses the button to where he releases it.
  
! p	Draw open polygon (freehand draw).  Release button to complete polygon.
  
  P	Draw filled polygons.  Same as above, but the polygon will be
  filled.  (The first and last points are connected by the server.)
***************
*** 41,52 ****
  t	Change the thickness (a.k.a. "line width").  The line width is
  set to the argument.
  
! ,	Set the value of angle1 to the argument.  The units are
! degrees.  (This was supposed to be a '<', but because I have to work to
! detect shifted characters, ',' was easier.)
  
! .	Set the value of angle2 to the argument.  (As above, this was
! supposed to be a '>'.)
  
! Paint will also refresh itself on expose windows.  The code to do this
! correctly with clipping rectangles is currently commented out.
--- 48,61 ----
  t	Change the thickness (a.k.a. "line width").  The line width is
  set to the argument.
  
! < or ,	Set the value of angle1 to the argument.  The units are in degrees.
  
! > or .	Set the value of angle2 to the argument.  The units are in degrees.
  
! q	quit program.
! 
! Paint will also refresh itself on expose windows.  This action redraws each
! object in the display list -- so it is very slow (esp on a sun).
! 
!     The Polygon routines leave screen dust (stray pixels) because of Xor-ing.
! This is due to the method used to "rubberband" freehand curves.
*** paint.orig/main.c	Thu Feb 25 23:01:20 1988
--- main.c	Tue May 31 16:32:26 1988
***************
*** 36,42 ****
  
  Display *dpy;
  
! int shiftbit = FALSE;
  
  HandleKey(event)
    XEvent *event;
--- 36,42 ----
  
  Display *dpy;
  
! int save_func, save_width;
  
  HandleKey(event)
    XEvent *event;
***************
*** 47,60 ****
      static int arg = 0;
      static int argval = 1;
      static int sgn = 0;
!     code = event->xkey.keycode;
!     if (code == 174) {
! 	shiftbit = TRUE;
  	return;
!     }
!     c = GetCharFromCode(code);
!     if (c >= 'a' && c <= 'z' && shiftbit)
! 	c += 'A' - 'a';
      switch (c) {
        case 'C':
  	XClearWindow(dpy, window);
--- 47,60 ----
      static int arg = 0;
      static int argval = 1;
      static int sgn = 0;
!     KeySym k;
!     char b[2];
! 
!     (void) XLookupString(event, b, 2, &k, NULL);
!     c = b[0];
!     if (IsModifierKey(k))
  	return;
! 
      switch (c) {
        case 'C':
  	XClearWindow(dpy, window);
***************
*** 75,85 ****
  	break;
        case 'p':
  	stat.mode = polygon;
- 	npoints = 0;
  	break;
        case 'P':
  	stat.mode = filledpolygon;
- 	npoints = 0;
  	break;
        case 'a':
  	stat.mode = arc;
--- 75,83 ----
***************
*** 88,102 ****
  	stat.mode = filledarc;
  	break;
        case 'f':
! 	stat.func = arg;
! 	if (arg != argval)
  	    stat.func = GXinvert;
- 	gcvalues.function = stat.func;
- 	XChangeGC(dpy, gc, GCFunction, &gcvalues);
  	break;
        case ',':
  	stat.angle1 = arg * 64;
  	break;
        case '.':
  	stat.angle2 = arg * 64;
  	break;
--- 86,99 ----
  	stat.mode = filledarc;
  	break;
        case 'f':
! 	if ((stat.func = arg) < GXclear || arg > GXset)
  	    stat.func = GXinvert;
  	break;
+       case '<':
        case ',':
  	stat.angle1 = arg * 64;
  	break;
+       case '>':
        case '.':
  	stat.angle2 = arg * 64;
  	break;
***************
*** 120,129 ****
  	return;
        case 't':
  	stat.thickness = argval;
- 	gcvalues.line_width = stat.thickness;
- 	XChangeGC(dpy, gc, GCLineWidth, &gcvalues);
  	break;
        default:
  	printf("Unknown code %d (%c)\n", event->xkey.keycode, c);
  	return;
      }
--- 117,127 ----
  	return;
        case 't':
  	stat.thickness = argval;
  	break;
+       case 'q':
+ 	exit(0);
        default:
+ 	XBell(dpy, 50);
  	printf("Unknown code %d (%c)\n", event->xkey.keycode, c);
  	return;
      }
***************
*** 133,175 ****
      sgn = 1;
  }
  
- HandleKeyUp(event)
-   XEvent *event;
- {
-     if (event->xkey.keycode == 174)
- 	shiftbit = FALSE;
- }
- 
  DisplayMode()
  {
!     char str[500];
!     sprintf(str,
! 	    "Mode %s; Thickness %d; Function %s; angle1 %.2f; angle2 %.2f",
! 	    StringForMode(stat.mode), stat.thickness, StringForFunction(stat.func),
! 	    stat.angle1 / 64.0, stat.angle2/64.0);
!     XDrawImageString(dpy, window, gc, 0, 0, str, strlen(str));
!     printf("%s\n", str);
  }
  
- HandleButtonDown(event)
-   XEvent *event;
- {
-     switch (stat.mode) {
-       case line:
-       case rect:
-       case filledrect:
-       case arc:
-       case filledarc:
- 	curx = event->xbutton.x;
- 	cury = event->xbutton.y;
- 	break;
-     }
- }
- 
  ImagePtr NewImage()
  {
      ImagePtr image;
!     image = (ImagePtr) malloc(sizeof(ImageRec));
      image->stat = stat;
      image->npoints = 0;
      image->points = (XPoint *) malloc(1);
--- 131,154 ----
      sgn = 1;
  }
  
  DisplayMode()
  {
!     char str[500], *p;
!     sprintf(str, "Mode %s, Thickness %d, Function %s",
! 	StringForMode(stat.mode), stat.thickness, StringForFunction(stat.func));
!     if (stat.mode == arc || stat.mode == filledarc) {
! 	p = str + strlen(str);
! 	sprintf(p, ", angle1 %g, angle2 %g",
! 	    stat.angle1 / 64.0, stat.angle2 / 64.0);
!     } else
! 	strcat(str, "                          "); /* to erase angles string */
!     XDrawImageString(dpy, window, gc, 5, 10, str, strlen(str));
  }
  
  ImagePtr NewImage()
  {
      ImagePtr image;
!     image = (ImagePtr) calloc((unsigned)1, sizeof(ImageRec));
      image->stat = stat;
      image->npoints = 0;
      image->points = (XPoint *) malloc(1);
***************
*** 180,209 ****
    ImagePtr image;
    int x, y;
  {
!     npoints = image->npoints++;
      image->points = (XPoint *)
  	realloc(image->points, sizeof(XPoint) * image->npoints);
!     image->points[npoints].x = x;
!     image->points[npoints].y = y;
!     image->next = NULL;
!     image->drawn = FALSE;
  }
  
! DrawImage(image)
    ImagePtr image;
  {
      XGCValues gcvalues;
      int x1, x2, y1, y2, x, y, width, height;
      gcvalues.function = image->stat.func;
      gcvalues.line_width = image->stat.thickness;
      XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
!     if (!image->drawn) {
  	if (lastimage)
  	    lastimage->next = image;
  	else
  	    firstimage = image;
  	lastimage = image;
- 	image->drawn = TRUE;
      }
      if (image->npoints == 2) {
  	x1 = image->points[0].x;
--- 159,186 ----
    ImagePtr image;
    int x, y;
  {
!     image->npoints++;
      image->points = (XPoint *)
  	realloc(image->points, sizeof(XPoint) * image->npoints);
!     image->points[image->npoints - 1].x = x;
!     image->points[image->npoints - 1].y = y;
  }
  
! DrawImage(image, append)
    ImagePtr image;
  {
      XGCValues gcvalues;
      int x1, x2, y1, y2, x, y, width, height;
+ 
      gcvalues.function = image->stat.func;
      gcvalues.line_width = image->stat.thickness;
      XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
!     if (append) {
  	if (lastimage)
  	    lastimage->next = image;
  	else
  	    firstimage = image;
  	lastimage = image;
      }
      if (image->npoints == 2) {
  	x1 = image->points[0].x;
***************
*** 244,253 ****
      }
  }
  
! 
! HandleButtonUp(event)
    XEvent *event;
  {
      int newx, newy;
      newx = event->xbutton.x;
      newy = event->xbutton.y;
--- 221,243 ----
      }
  }
  
! HandleButtonDown(event)
    XEvent *event;
  {
+     XGCValues gcvalues;
+ 
+     curx = event->xbutton.x;
+     cury = event->xbutton.y;
+     save_func = stat.func;
+     save_width = stat.thickness;
+     gcvalues.function = stat.func = GXxor;
+     gcvalues.line_width = stat.thickness = 1;
+     XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
+ }
+ 
+ ButtonMove(event)
+ XEvent *event;
+ {
      int newx, newy;
      newx = event->xbutton.x;
      newy = event->xbutton.y;
***************
*** 257,280 ****
        case filledrect:
        case arc:
        case filledarc:
! 	image = NewImage();
! 	StuffPoint(image, curx, cury);
! 	StuffPoint(image, newx, newy);
! 	DrawImage(image);
  	break;
        case polygon:
        case filledpolygon:
! 	if (image == NULL || image->stat.mode != stat.mode)
  	    image = NewImage();
  	StuffPoint(image, newx, newy);
! 	if (event->xbutton.button == Button3) {
! 	    DrawImage(image);
  	}
      }
      curx = newx;
      cury = newy;
-     printf("*");
-     fflush(stdout);
  }
  
  XRectangle rects[500];
--- 247,321 ----
        case filledrect:
        case arc:
        case filledarc:
! 	if (!image) {
! 	    image = NewImage();
! 	    StuffPoint(image, curx, cury);
! 	    StuffPoint(image, newx, newy);
! 	} else {
! 	    DrawImage(image, FALSE); /* erase old image */
! 	    image->points[1].x = newx;
! 	    image->points[1].y = newy;
! 	}
! 	DrawImage(image, FALSE);
  	break;
        case polygon:
        case filledpolygon:
! 	if (image == NULL) {
  	    image = NewImage();
+ 	    StuffPoint(image, curx, cury);
+ 	}
  	StuffPoint(image, newx, newy);
! 	/* build line piece by piece, don't rerender the whole polyline */
! 	XDrawLine(dpy, window, gc, curx, cury, newx, newy);
! 	curx = newx;
! 	cury = newy;
!     }
! }
! 
! HandleButtonUp(event)
! XEvent *event;
! {
!     int newx, newy;
!     newx = event->xbutton.x;
!     newy = event->xbutton.y;
!     if (image) {
! 	if (stat.mode == filledpolygon)
! 	    image->stat.mode = polygon;
! 	DrawImage(image, FALSE);
! 	if (stat.mode == filledpolygon)
! 	    image->stat.mode = filledpolygon;
! 	image->stat.func = save_func;
! 	image->stat.thickness = save_width;
!     }
!     /* change from xor/single linewidth mode to real render mode */
!     stat.func = save_func;
!     stat.thickness = save_width;
!     if (!image) /* a single click without movement won't create an object */
! 	return;
!     switch (stat.mode) {
!       case line:
!       case rect:
!       case filledrect:
!       case arc:
!       case filledarc:
! 	if (image->npoints > 1) {
! 	    image->points[1].x = newx;
! 	    image->points[1].y = newy;
! 	    break;
  	}
+       case polygon:
+       case filledpolygon:
+ 	StuffPoint(image, newx, newy);
+ 	/*
+ 	puts("polygon points:");
+ 	for (newx = 0; newx < image->npoints; newx++)
+ 	    printf("%d, %d\n", image->points[newx].x, image->points[newx].y);
+ 	*/
      }
+     DrawImage(image, TRUE);
+     image = NULL; /* reinitialize */
      curx = newx;
      cury = newy;
  }
  
  XRectangle rects[500];
***************
*** 295,301 ****
  	XSetClipRectangles(dpy, gc, 0, 0, rects, numrects, Unsorted);
  	numrects = 0;
  	for (image = firstimage; image; image = image->next)
! 	    DrawImage(image);
  	rects[0].x = 0;
  	rects[0].y = 0;
  	rects[0].width = 9999;
--- 336,342 ----
  	XSetClipRectangles(dpy, gc, 0, 0, rects, numrects, Unsorted);
  	numrects = 0;
  	for (image = firstimage; image; image = image->next)
! 	    DrawImage(image, FALSE);
  	rects[0].x = 0;
  	rects[0].y = 0;
  	rects[0].width = 9999;
***************
*** 311,327 ****
      Visual visual;
      XSetWindowAttributes attributes;
      XGCValues gcvalues;
!     if ((dpy = XOpenDisplay("")) == NULL)
  	Punt("Couldn't open display!");
-     InitUtil();
      windowwidth = 400;
      windowheight = 400;
      stat.thickness = 1;
!     stat.func = GXinvert;
      stat.angle1 = 0;
      stat.angle2 = 360 * 64;
!     foreground = WhitePixel(dpy, DefaultScreen(dpy));
!     background = BlackPixel(dpy, DefaultScreen(dpy));
      font = XLoadFont(dpy, "fixed");
      visual.visualid = CopyFromParent;
      attributes.background_pixel = background;
--- 352,367 ----
      Visual visual;
      XSetWindowAttributes attributes;
      XGCValues gcvalues;
!     if ((dpy = XOpenDisplay(NULL)) == NULL)
  	Punt("Couldn't open display!");
      windowwidth = 400;
      windowheight = 400;
      stat.thickness = 1;
!     save_func = stat.func = GXinvert;
      stat.angle1 = 0;
      stat.angle2 = 360 * 64;
!     background = WhitePixel(dpy, DefaultScreen(dpy));
!     foreground = BlackPixel(dpy, DefaultScreen(dpy));
      font = XLoadFont(dpy, "fixed");
      visual.visualid = CopyFromParent;
      attributes.background_pixel = background;
***************
*** 328,340 ****
      attributes.border_pixel = foreground;
      attributes.backing_store = Always;
      window = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
! 		    20, 20, windowwidth, windowheight, 1,
! 		    DefaultDepth(dpy, DefaultScreen(dpy)), CopyFromParent, &visual,
! 		    CWBackPixel | CWBorderPixel /*| CWBackingStore */,
! 		    &attributes);
      XChangeProperty(dpy, window, XA_WM_NAME, XA_STRING, 8, 
  		    PropModeReplace, "Paint", 5);
!     MyXSelectInput(dpy, window, KeyPressMask | KeyReleaseMask | ButtonPressMask
  		   | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
      XMapWindow(dpy, window);
      gcvalues.foreground = foreground;
--- 368,379 ----
      attributes.border_pixel = foreground;
      attributes.backing_store = Always;
      window = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
! 		20, 20, windowwidth, windowheight, 1,
! 		DefaultDepth(dpy, DefaultScreen(dpy)), CopyFromParent, &visual,
! 		CWBackPixel | CWBorderPixel /*| CWBackingStore */, &attributes);
      XChangeProperty(dpy, window, XA_WM_NAME, XA_STRING, 8, 
  		    PropModeReplace, "Paint", 5);
!     MyXSelectInput(dpy, window, KeyPressMask | ButtonPressMask
  		   | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
      XMapWindow(dpy, window);
      gcvalues.foreground = foreground;
***************
*** 348,363 ****
  		   &gcvalues);
      stat.mode = line;
      image = firstimage = lastimage = NULL;
!     DisplayMode();
!     while (1) {
  	XNextEvent(dpy, &event);
  	switch(event.type) {
  	  case KeyPress:
  	    HandleKey(&event);
  	    break;
- 	  case KeyRelease:
- 	    HandleKeyUp(&event);
- 	    break;
  	  case ButtonPress:
  	    HandleButtonDown(&event);
  	    break;
--- 387,398 ----
  		   &gcvalues);
      stat.mode = line;
      image = firstimage = lastimage = NULL;
!     for (;;) {
  	XNextEvent(dpy, &event);
  	switch(event.type) {
  	  case KeyPress:
  	    HandleKey(&event);
  	    break;
  	  case ButtonPress:
  	    HandleButtonDown(&event);
  	    break;
***************
*** 365,373 ****
--- 400,410 ----
  	    HandleButtonUp(&event);
  	    break;
  	  case MotionNotify:
+ 	    ButtonMove(&event);
  	    break;
  	  case Expose:
  	    RepaintDisplay(&event);
+ 	    DisplayMode();
  	    break;
  	}
      }	    
*** paint.orig/paint.h	Thu Feb 25 23:01:20 1988
--- paint.h	Fri May 27 15:55:41 1988
***************
*** 5,10 ****
--- 5,12 ----
  #include <stdio.h>
  #include "X11/Xlib.h"
  #include "X11/Xatom.h"
+ #include "X11/Xutil.h"
+ #include "X11/keysym.h"
  
  /***********************************************************
  Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
***************
*** 33,39 ****
  #define max(x, y) ((x) > (y) ? (x) : (y))
  #define abs(x) ((x) < 0 ? (-(x)) : (x))
  
! typedef enum {line, rect, filledrect, arc, filledarc, polygon, filledpolygon} ModeType;
  
  typedef struct {
      ModeType mode;
--- 35,49 ----
  #define max(x, y) ((x) > (y) ? (x) : (y))
  #define abs(x) ((x) < 0 ? (-(x)) : (x))
  
! typedef enum {
!     line,
!     rect,
!     filledrect,
!     arc,
!     filledarc,
!     polygon,
!     filledpolygon
! } ModeType;
  
  typedef struct {
      ModeType mode;
***************
*** 47,53 ****
      int npoints;
      XPoint *points;
      struct _ImageRec *next;
-     int drawn;
  } ImageRec, *ImagePtr;
  
  #ifndef TRUE
--- 57,62 ----
***************
*** 68,76 ****
  ext Window window;
  ext int windowheight, windowwidth;
  ext long foreground, background;
- 
- ext XPoint points[1000];
- ext int npoints;
  
  extern GC XCreateGC();
  extern XFontStruct *XFont();
--- 77,82 ----
*** paint.orig/util.c	Thu Feb 25 23:01:21 1988
--- util.c	Fri May 27 15:53:07 1988
***************
*** 48,92 ****
  }
  
  
- InitUtil()
- {
-     int i;
-     for (i=0 ; i<256 ; i++) ChrToCode[i] = 0;
-     ChrToCode['a'] = 194;    ChrToCode['b'] = 217;    ChrToCode['c'] = 206;
-     ChrToCode['d'] = 205;    ChrToCode['e'] = 204;    ChrToCode['f'] = 210;
-     ChrToCode['g'] = 216;    ChrToCode['h'] = 221;    ChrToCode['i'] = 230;
-     ChrToCode['j'] = 226;    ChrToCode['k'] = 231;    ChrToCode['l'] = 236;
-     ChrToCode['m'] = 227;    ChrToCode['n'] = 222;    ChrToCode['o'] = 235;
-     ChrToCode['p'] = 240;    ChrToCode['q'] = 193;    ChrToCode['r'] = 209;
-     ChrToCode['s'] = 199;    ChrToCode['t'] = 215;    ChrToCode['u'] = 225;
-     ChrToCode['v'] = 211;    ChrToCode['w'] = 198;    ChrToCode['x'] = 200;
-     ChrToCode['y'] = 220;    ChrToCode['z'] = 195;    ChrToCode['0'] = 239;
-     ChrToCode['1'] = 192;    ChrToCode['2'] = 197;    ChrToCode['3'] = 203;
-     ChrToCode['4'] = 208;    ChrToCode['5'] = 214;    ChrToCode['6'] = 219;
-     ChrToCode['7'] = 224;    ChrToCode['8'] = 229;    ChrToCode['9'] = 234;
-     ChrToCode['`'] = 191;    ChrToCode['~'] = 191;    ChrToCode['!'] = 192;
-     ChrToCode['#'] = 203;    ChrToCode['$'] = 208;
-     ChrToCode['%'] = 214;    ChrToCode['&'] = 224;
-     ChrToCode['*'] = 229;    ChrToCode['('] = 234;    ChrToCode[')'] = 239;
-     ChrToCode['-'] = 249;    ChrToCode['='] = 245;
-     ChrToCode['+'] = 245;    ChrToCode['['] = 250;    ChrToCode['{'] = 250;
-     ChrToCode[']'] = 246;    ChrToCode['}'] = 246;    ChrToCode[';'] = 242;
-     ChrToCode[':'] = 242;    ChrToCode['\''] = 251;   ChrToCode['"'] = 251;
-     ChrToCode['\\'] = 247;   ChrToCode['|'] = 247;    ChrToCode[','] = 232;
-     ChrToCode['.'] = 237;    ChrToCode['/'] = 243;    ChrToCode['?'] = 243;
-     ChrToCode['<'] = 201;    ChrToCode['>'] = 201;    ChrToCode['\t'] = 190;
-     ChrToCode[' '] = 212;
-     for (i=0 ; i<256 ; i++) CodeToChr[ChrToCode[i]] = i;
- }
- 
- 
- GetCharFromCode(n)
-   int n;
- {
-     return CodeToChr[n];
- }
- 
- 
  char *StringForMode(mode)
    ModeType mode;
  {
--- 48,53 ----

Dan Heller	<island!argv@sun.com>