From: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Subject: XControl program and terminal emulator 3/4
Reply-To: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Organization: University of Waterloo
Date: Sun, 24 Jan 1993 03:49:42 GMT


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Gordon R. Strachan <gordon@maxwell> on Sat Jan 23 22:18:43 1993
#
# This archive contains:
#	GenTerm/Parse.c		GenTerm/Pty.c		
#	GenTerm/Pty.man		GenTerm/TAGS		
#	GenTerm/ctest.c		GenTerm/hpterm.par	
#	GenTerm/test.c		xcontrol/ParseString.c	
#	xcontrol/TAGS		xcontrol/XControl.ad	
#
# Error checking via wc(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

echo x - GenTerm/Parse.c
cat >GenTerm/Parse.c <<'@EOF'
/* Parse.c : This file contains the terminal emulator parser */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include "GenTermEmP.h"
#include "Parser.h"

static char *GtEIntToStringConvert();
struct InputArgument *GtEPushArgs();
void GtEPopArgs();

static int GtENewLine();
static int GtEDownLine();
static int GtEUpLine();
static int GtECarriageReturn();
static int GtENextTab();
static int GtEMoveLeft();
static int GtEMoveRight();
static int GtESoundBell();
static int GtEMoveCursor();
static int GtEGetBottomText();
static int GtEGetPosition();
static int GtESetFont();
static int GtEIgnore();
static int GtESetField();
static int GtEClearLine();
static int GtEClearDisplay();
static int GtEMath();
static int GtELoadAttribute();
static int GtEClearMemory();
static int GtEInsertLines();
static int GtEDeleteLines();
static int GtESetTop();
static int GtEDeleteCharacters();
static int GtEGetTop();
static int GtEGetScreenSize();
static int GtESetInsertMode();
static int GtESetTab();
static int GtEUnSetTab();
static int GtESetParseTable();
static int GtESetKeyTable();
static int GtESetResource();
static int GtEGetResource();
static int GtEEmit();
static int GtEGetLine();
static int GtEPreviousTab();
static int GtESetScrollRegion();
static int GtEIf();
static int GtEReject();
static int GtEGetTopOfScrollRegion();
static int GtEQuit();
static int GtEGetFont();
static int GtESetInverseVideo();
static int GtESetUnderLineMode();
static int GtESetHalfBrightMode();
static int GtESetBlinkMode();
static int GtEProgramKey();
static int GtESetPen();
static int GtEGetPen();
static int GtEDefinePen();
static int GtEExecuteFunctionKey();
static int GtEEscapeCallback();
static int GtELoadMapTable();
static int GtEProgramMapTable();
static int GtEStore();
static int GtEFetch();
static int GtEOutputString();
static int GtEGetArg();
static int GtEGetLastButtonEvent();
static int GtEToAscii();
static int GtEConvertPosition();
static int GtECheckModifiers();
static int GtEGetStringLength();
static int GtEGetSubString();
static int GtEIntToString();
static int GtESetFlow();

static int GtEMatchInt();
static int GtEMatchDigits();
static int GtEMatchSelect();
static int GtEMatchString();
static int GtEMatchFloat();
static int GtEMatchUpto();

static int ArgToInt();
static char *ArgToString();
static float ArgToFloat();

struct FuncDefs Translators[]=
{{"DownLine",GtEDownLine},
  {"NewLine",GtENewLine},
  {"CarriageReturn",GtECarriageReturn},
  {"NextTab",GtENextTab},
  {"MoveLeft",GtEMoveLeft},
  {"MoveRight",GtEMoveRight},
  {"MoveCursor",GtEMoveCursor},
  {"GetBottomText",GtEGetBottomText},
  {"GetPosition",GtEGetPosition},
  {"SetFont",GtESetFont},
  {"Ignore",GtEIgnore},
  {"SoundBell",GtESoundBell},
  {"UpLine",GtEUpLine},
  {"SetField",GtESetField},
  {"ClearLine",GtEClearLine},
  {"ClearDisplay",GtEClearDisplay},
  {"Math",GtEMath},
  {"LoadAttribute",GtELoadAttribute},
  {"ClearMemory",GtEClearMemory},
  {"InsertLines",GtEInsertLines},
  {"DeleteLines",GtEDeleteLines},
  {"SetTop",GtESetTop},
  {"DeleteCharacters",GtEDeleteCharacters},
  {"GetTop",GtEGetTop},
  {"GetScreenSize",GtEGetScreenSize},
  {"SetInsertMode",GtESetInsertMode},
  {"SetTab",GtESetTab},
  {"UnSetTab",GtEUnSetTab},
  {"SetParseTable",GtESetParseTable},
  {"SetKeyTable",GtESetKeyTable},
  {"SetResource",GtESetResource},
  {"Emit",GtEEmit},
  {"GetLine",GtEGetLine},
  {"PreviousTab",GtEPreviousTab},
  {"SetScrollRegion",GtESetScrollRegion},
  {"If",GtEIf},
  {"Reject",GtEReject},
  {"GetTopOfScrollRegion",GtEGetTopOfScrollRegion},
  {"Quit",GtEQuit},
  {"GetFont",GtEGetFont},
  {"SetInverseVideo",GtESetInverseVideo},
  {"SetUnderLineMode",GtESetUnderLineMode},
  {"SetHalfBrightMode",GtESetHalfBrightMode},
  {"SetBlinkMode",GtESetBlinkMode},
  {"ProgramKey",GtEProgramKey},
  {"SetPen",GtESetPen},
  {"GetPen",GtEGetPen},
  {"DefinePen",GtEDefinePen},
  {"ExecuteFunctionKey",GtEExecuteFunctionKey},
  {"EscapeCallback",GtEEscapeCallback},
  {"LoadMapTable",GtELoadMapTable},
  {"ProgramMapTable",GtEProgramMapTable},
  {"Store",GtEStore},
  {"Fetch",GtEFetch},
  {"OutputString",GtEOutputString},
  {"GetResource",GtEGetResource},
  {"GetArg",GtEGetArg},
  {"GetLastButtonEvent",GtEGetLastButtonEvent},
  {"ToAscii",GtEToAscii},
  {"ConvertPosition",GtEConvertPosition},
  {"CheckModifiers",GtECheckModifiers},
  {"GetStringLength",GtEGetStringLength},
  {"GetSubString",GtEGetSubString},
  {"IntToString",GtEIntToString},
  {"SetFlow",GtESetFlow},
  {NULL,NULL}
};

struct FuncDefs Specials[]=
{{"Int",GtEMatchInt},
  {"Select",GtEMatchSelect},
  {"String",GtEMatchString},
  {"Float",GtEMatchFloat},
  {"Digits",GtEMatchDigits},
  {"Upto",GtEMatchUpto},
  {NULL,NULL}
};

/* GtEParse:  This function is the main entry point to the GenTermEm Widget. */
/*  It takes as input a string that is to be displayed.  It passes the */
/*  string through the current parse table.  If it matches an entry in the */
/*  table then the translators defined for that sequence are executed.  If */
/*  no match is found then the string is simply displayed. */

GtEParse(w,string,len)

GenTermEmWidget w;
char *string;
int len;

{
 int i,j,k;
 char Storage[1024];
 int StorePoint = 0;
 struct ParseItem *temp;
 struct Translator *StartTrans,*trans;
 int Matched;
 int Result;
 int num;
 int ReturnVal;

 for(i = 0; i < len; i++)
  {
   temp  = w->genTermEm.CurrentPoint;
   Matched = 0;
   while(temp != NULL)   /* first search for the character in parse table */
    {
     if(temp->c == string[i])    /* found and entry in our parse table */
      {
       w->genTermEm.InputStack[w->genTermEm.TopStack++] = string[i];
       w->genTermEm.CurrentPoint = temp = temp->child;
       Matched = 1;
       break;
      }
     else
      temp = temp->next;
    }

/* if we didn't find a match, check if there is a special translator to call */

   if((Matched == 0) && (w->genTermEm.CurrentPoint->special != NULL))
    {
     Result = (w->genTermEm.CurrentPoint->special->func)(w,string,len,i,&num,
                                                        w->genTermEm.CurrentPoint->special->arglist,
                                                        w->genTermEm.CurrentPoint->special->position);

/* special parsers return a 0 for a bad match 1 for a complete match and 2 */
/* for an incomplete match */
     if(Result == 1)
      {
       w->genTermEm.CurrentPoint = w->genTermEm.CurrentPoint->child;
/* store matched characters in case we reject them later */
       for(j = 0; j < num; j++)
        w->genTermEm.InputStack[w->genTermEm.TopStack++] = string[i+j];
       if(num >= 0)
	i += num - 1;
       else
	i += num;
       Matched = 1;
      }
     else if (Result == 2)
      {
       for(j = 0; j < num; j++)
        w->genTermEm.InputStack[w->genTermEm.TopStack++] = string[i+j];
       i += num;
       Matched = 1;
      }
     else    /* was a batch match, reject it */
      {
       Matched = 0;
      }
    }

/* okay, by now we have either matched the character or not.  If it is match */
/* execute any translator bound to if any */

   if(Matched)
    {
     if(w->genTermEm.CurrentPoint->translators != NULL)
      {
       if(StorePoint != 0)
        {
         GtOutput(w,Storage,StorePoint); /* emit all stored chars before */
         StorePoint = 0;                 /* calling the translators */
        }
/* before we call the translators we reset the parser just incase one of the */
/* translators will cause the parser to re-entered */
       StartTrans = trans = w->genTermEm.CurrentPoint->translators;
       w->genTermEm.TopStack = 0;
       w->genTermEm.CurrentPoint = w->genTermEm.ParseTable;
       while(trans != NULL)
        {
         ReturnVal = (trans->func)(w,trans->arglist);
	 if(ReturnVal == TRANSERROR)
	  break;
	 else if(ReturnVal == TRANSOKAY)
	  trans = trans->next;
	 else if(ReturnVal == TRANSREJECT)
	  {     
	   w->genTermEm.CurrentPoint = w->genTermEm.ParseTable;
	   for(j = 0; j < w->genTermEm.TopStack; j++)
	    Storage[StorePoint++] = w->genTermEm.InputStack[j];
	   w->genTermEm.TopStack = 0;
	   Storage[StorePoint++] = string[i];
	   break;
	  }
	 else
	  {
	   trans = StartTrans;
	   while((trans != NULL) &&(trans->label != ReturnVal))
	    trans = trans->next;
	  }
	}
/* okay, here walk input argument list and free what ever needed */
/* hmm... bug alert, InputArgs is not re-entrant if a translator causes the */
/* input parser routine to be recalled it will over write the argumentlist */
/* I don't know how to fix this right now, perhaps the proper thing to do is */
/* to not allow translators to call the parse function (usually through a */
/* kbdCallBack and instead queue up output to emit later... */
       for(k = 0; k < NUMARGS; k++)
        if(w->genTermEm.InputArgs[k].valid & AMALLOCED)
         {
          XtFree(w->genTermEm.InputArgs[k].string);
          w->genTermEm.InputArgs[k].valid = 0;
         }
      }
    }
   else   /* wasn't matched, reject the characters already on the stack */
    {
     w->genTermEm.CurrentPoint = w->genTermEm.ParseTable;
     for(j = 0; j < w->genTermEm.TopStack; j++)
      Storage[StorePoint++] = w->genTermEm.InputStack[j];
     w->genTermEm.TopStack = 0;
     Storage[StorePoint++] = string[i];
    }

/* The previous operation might have caused the screen to be scrolled.  In */
/* this case we must hold off further processing because we don't know if */
/* the X server was able to fufill the XCopyArea request.  Therefore, we */
/* must store the characters which are waiting to be processed and break out */
/* of this loop so we can return and process any graphics expose events */
/* which might be waiting for us.  We must also stop listening to our input */
/* descriptor because we can't service any more requests until all the */
/* graphics exposures are processed */
   if(w->genTerm.ExposureCount > 0)
    break;
  }
 if(StorePoint != 0)
  GtOutput(w,Storage,StorePoint);
 if(w->genTerm.ExposureCount > 0)
  GtESetWaitForGraphicsExpose(w,string,i+1,len);
}

/* GtEPushArgs:  This function cause a new input argument list to be created */
/*  and the old one is returned to the calling function for storage.  It is */
/*  used to make the GtEParse function re-entrant. */

struct InputArgument *GtEPushArgs(w)

GenTermEmWidget w;

{
 int i;
 char *store;
 struct InputArgument *temp = w->genTermEm.InputArgs;

 w->genTermEm.InputArgs = (struct InputArgument *)
  XtMalloc(sizeof(struct InputArgument) * NUMARGS);
 for(i = 0; i < NUMARGS; i++)
  {
   w->genTermEm.InputArgs[i].valid = 0;
   if((temp[i].valid & ADEFINED) && ((temp[i].valid & AMALLOCED) == 0))
    {
     store = XtMalloc(temp[i].length + 1);
     memcpy(store,temp[i].string,temp[i].length);
     temp[i].string = store;
     temp[i].valid |= AMALLOCED;
    }
  }
 return(temp);
}

/* GtEPopArgs: This function causes the input argument list to be reset to */
/*   its previously stored value.  The current input list is freed. */

void GtEPopArgs(w,New)

GenTermEmWidget w;
struct InpuArgument *New;

{
 int i;
 
 for(i = 0; i < NUMARGS; i++)
  if(w->genTermEm.InputArgs[i].valid & AMALLOCED)
   XtFree(w->genTermEm.InputArgs[i].string);
 XtFree(w->genTermEm.InputArgs);

 w->genTermEm.InputArgs = New;
}

/* Start of special matching functions for the parser */

/* GtEMatchInt:  This function attemprs to match a string of digits from the */
/*  input stream and collect them into an integer. It takes as an arguement */
/*  the number of digits to match.  If no argument is given then it matches */
/*  upto the next non-digit character. */

static int GtEMatchInt(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;

 if(w->genTermEm.SpecialVars.Started == 0)   /* first time called? */
  {
   w->genTermEm.SpecialVars.Started = 1;
   w->genTermEm.InputArgs[position].valid = 0;
   w->genTermEm.InputArgs[position].length = 0;
   w->genTermEm.SpecialVars.store.NumToGo = ArgToInt(w,args,1,-1);
  }

 *num = 0;
 for(i = start; i < len; i++)
  {
   if(isdigit(string[i]) || ((w->genTermEm.SpecialVars.Started == 1) && 
			     (string[i] == '-')))
    {
     w->genTermEm.SpecialVars.Started = 2;
     if(w->genTermEm.InputArgs[position].valid == 0)
      {
/* this is a bit of a kludge.  We need to remember the characters matched */
/* so we can get them later.  We make the string point to the top of the */
/* input stack because we know GtEParse will store the characters there */
       w->genTermEm.InputArgs[position].string = 
	&(w->genTermEm.InputStack[w->genTermEm.TopStack]);
       w->genTermEm.InputArgs[position].valid = ADEFINED;
      }
     *num += 1;
     w->genTermEm.InputArgs[position].length++;
     w->genTermEm.SpecialVars.store.NumToGo--;
     if(w->genTermEm.SpecialVars.store.NumToGo == 0)
      {
       w->genTermEm.SpecialVars.Started = 0;
       return(1);
      }
    }
   else
    {
     w->genTermEm.SpecialVars.Started = 0;

/* found a non integer character, if we were to match a unknown number of */
/* characters and have matched some then return success, otherwise flag an */
/* error */

     if((w->genTermEm.SpecialVars.store.NumToGo < 0) && 
	(w->genTermEm.InputArgs[position].length > 0))
      {
       if(i == start)  /* if we failed on first character force a reparse */
	*num -= 1;
       return(1);
      }
     else
      {
       w->genTermEm.InputArgs[position].valid = 0;
       return(0);
      }
    }
  }
 return(2);
}

/* GtEMatchDigits:  This translator attempts to match a list of zero or more */
/*  digits from the input stream and collect them into a list of integers. */
/*  It takes as its arguments, the default value to return is no arguments */
/*  are given and the character which is used to seperate the list. An */
/*  optional third argument exists to specify the number of digits in each */
/*  number otherwise an arbirtrary number is matched. */

static int GtEMatchDigits(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;
 char buffer[1024];
 int place;

 if(w->genTermEm.SpecialVars.Started == 0)   /* first time called? */
  {
   w->genTermEm.SpecialVars.Started = 1;
   w->genTermEm.InputArgs[position].valid = 0;
   w->genTermEm.InputArgs[position].length = 0;
   ArgToString(w,args,2," ",w->genTermEm.SpecialVars.store.DigitsVars.Sep,1);
   w->genTermEm.SpecialVars.store.DigitsVars.NumToGo = ArgToInt(w,args,3,-1);
   w->genTermEm.SpecialVars.store.DigitsVars.Store = position;
  }

 *num = 0;
 place = w->genTermEm.SpecialVars.store.DigitsVars.Store;
 for(i = start; i < len; i++)
  {
   if(isdigit(string[i]))
    {
     if(w->genTermEm.InputArgs[place].valid == 0)
      {
/* this is a bit of a kludge.  We need to remember the characters matched */
/* so we can get them later.  We make the string point to the top of the */
/* input stack because we know GtEParse will store the characters there */
       w->genTermEm.InputArgs[place].string = 
	&(w->genTermEm.InputStack[w->genTermEm.TopStack + *num]);
       w->genTermEm.InputArgs[place].valid = ADEFINED;
      }
     *num += 1;
     w->genTermEm.InputArgs[place].length++;
     w->genTermEm.SpecialVars.store.DigitsVars.NumToGo--;
     if(w->genTermEm.SpecialVars.store.DigitsVars.NumToGo == 0)
      {
       w->genTermEm.SpecialVars.Started = 0;
       return(1);
      }
    }
   else if(string[i] == w->genTermEm.SpecialVars.store.DigitsVars.Sep[0])
    {    /* found end of one integer start next one in list */
     if(w->genTermEm.InputArgs[place].length == 0)
      {
       ArgToString(w,args,1,"",buffer,1023);
       StringToInputArg(w,place,buffer,strlen(buffer));
      }
     w->genTermEm.SpecialVars.store.DigitsVars.Store += 1;
     place++;

     w->genTermEm.InputArgs[place].valid = 0;
     w->genTermEm.InputArgs[place].length = 0;
     w->genTermEm.SpecialVars.store.DigitsVars.NumToGo = ArgToInt(w,args,3,-1);
     *num += 1;
    }
   else
    {
     w->genTermEm.SpecialVars.Started = 0;

/* found a non integer character, if we haven't matched any characters then */
/* return the default.  If we found some, but not the right number then */
/* return an error.  If we were to match a unknown number of characters and */
/*  have matched some then return success */

     if(w->genTermEm.InputArgs[place].length == 0)
      {
       ArgToString(w,args,1,"",buffer,1023);
       StringToInputArg(w,place,buffer,strlen(buffer));
       StringToInputArg(w,place+1,buffer,strlen(buffer));
       return(1);
      }
     else if((w->genTermEm.SpecialVars.store.DigitsVars.NumToGo < 0) && 
	(w->genTermEm.InputArgs[place].length > 0))
      {
/* set the next token to the default to signal end of the list */
       ArgToString(w,args,1,"",buffer,1023);
       StringToInputArg(w,place+1,buffer,strlen(buffer));
       if(i == start) 
	*num -= 1;
       return(1);
      }
     else
      {
       w->genTermEm.InputArgs[place].valid = 0;
       return(0);
      }
    }
  }
 return(2);
}
/* GtEMatchSelect:  This function attempts to match a character against */
/*  any of the characters given as arguements. */

static int GtEMatchSelect(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;
 char match[2];

 for(i = 1; i <= args->NumArgs; i++)
  {
   ArgToString(w,args,i," ",match,1);
   if(match[0] == string[start])    /* do we have a match? */
    {
     *num = 1;
     w->genTermEm.InputArgs[position].string = 
      &(w->genTermEm.InputStack[w->genTermEm.TopStack]);
     w->genTermEm.InputArgs[position].valid = ADEFINED;
     w->genTermEm.InputArgs[position].length = 1;
     return(1);
    }
  }
 return(0);
}

/* GtEMatchFloat: This function attempts to match a floating point number */
/*  It does not consider exponentional notation */

static int GtEMatchFloat(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;
 int good;

 if(w->genTermEm.SpecialVars.Started == 0)
  {
   w->genTermEm.SpecialVars.Started = 1;
   w->genTermEm.InputArgs[position].valid = 0;
   w->genTermEm.InputArgs[position].length = 0;
   w->genTermEm.SpecialVars.store.FloatVars.IntNumToGo = ArgToInt(w,args,1,-1);
   w->genTermEm.SpecialVars.store.FloatVars.FracNumToGo = ArgToInt(w,args,2,-1);
   w->genTermEm.SpecialVars.store.FloatVars.SeenDot = 0;
  }

 *num = 0;
 for(i = start; i < len; i++)
  {
   good = False;
   if(string[i] == '.')
    {
     if(w->genTermEm.SpecialVars.store.FloatVars.SeenDot == 0)
      {
       good = True;
       w->genTermEm.SpecialVars.store.FloatVars.SeenDot = 1;
      }
    }
   else if(isdigit(string[i]))
    {
     if(w->genTermEm.SpecialVars.store.FloatVars.SeenDot == 0)
      {
       if(w->genTermEm.SpecialVars.store.FloatVars.IntNumToGo == 0)
	{   /* bad number of digits in the integer part! */
	 w->genTermEm.InputArgs[position].valid = 0;
	 return(0);
	}
       w->genTermEm.SpecialVars.store.FloatVars.IntNumToGo--;
       good = True;
      }
     else
      {
       good = True;
       w->genTermEm.SpecialVars.store.FloatVars.FracNumToGo--;
      }
    }
   else
    {
     w->genTermEm.SpecialVars.Started = 0;
/* found a non valid character, if we were to match an unknown number of */
/* digits in the decimal part then return success. */
     
     if((w->genTermEm.SpecialVars.store.FloatVars.FracNumToGo < 0) &&
	(w->genTermEm.InputArgs[position].length > 0))
      {
       if(i == start)
	*num -= 1;
       return(1);
      }
     else
      {
       w->genTermEm.InputArgs[position].valid = 0;
       return(0);
      }
    }
   if(good)
    {
     if(w->genTermEm.InputArgs[position].valid == 0)
      w->genTermEm.InputArgs[position].string =
       &(w->genTermEm.InputStack[w->genTermEm.TopStack]);
     w->genTermEm.InputArgs[position].valid = ADEFINED;
    }
   *num += 1;
   w->genTermEm.InputArgs[position].length++;
   if(w->genTermEm.SpecialVars.store.FloatVars.FracNumToGo == 0)
    return(1);
  }
 return(2);
}

/* GtEMatchString:  This function attempts to match an arbitrary string of */
/*  characters of a given length.  Right now it will keep waiting for a */
/*  match even if the character never shows up.  Perhaps it should time out */
/*  after a while but then, what would the appropriate thing be to do? */

static int GtEMatchString(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;

 if(w->genTermEm.SpecialVars.Started == 0)   /* first time called? */
  {
   *num = 0;
   w->genTermEm.SpecialVars.Started = 1;
   w->genTermEm.InputArgs[position].valid = 0;
   w->genTermEm.InputArgs[position].length = 0;
   w->genTermEm.SpecialVars.store.NumToGo = ArgToInt(w,args,1,-1);

   if((w->genTermEm.SpecialVars.store.NumToGo == -1) || 
      (w->genTermEm.SpecialVars.store.NumToGo == 0))
    /*XtAppError(XtWidgetToApplicationContext(w),
      "Error in GenTermEm widget, String matching function needs a non-zero argument!");*/
    return(1);
   
   w->genTermEm.InputArgs[position].string = 
    &(w->genTermEm.InputStack[w->genTermEm.TopStack]);
   w->genTermEm.InputArgs[position].valid = ADEFINED;
  }

 *num = 0;
 for(i = start; i <len; i++)
  {
   *num += 1;
   w->genTermEm.InputArgs[position].length += 1;
   w->genTermEm.SpecialVars.store.NumToGo -= 1;

   if(w->genTermEm.SpecialVars.store.NumToGo == 0)
    {
     w->genTermEm.SpecialVars.Started = 0;
     return(1);
    }
  }
 return(2);
}

/* GtEMatchUpto:  This function attempts to match an arbitrary input stream */
/*  upto the specified character.  That specified character is not returned */
/*  on the input stack. */

static int GtEMatchUpto(w,string,len,start,num,args,position)

GenTermEmWidget w;
char *string;
int len;
int start;
int *num;
struct ArgumentList *args;
int position;

{
 int i;
 char input[2];

 if(w->genTermEm.SpecialVars.Started == 0)   /* first time called? */
  {
   w->genTermEm.SpecialVars.Started = 1;
   w->genTermEm.InputArgs[position].valid = 0;
   w->genTermEm.InputArgs[position].length = 0;
   ArgToString(w,args,1,"",input,1);
   w->genTermEm.SpecialVars.store.NumToGo = (int) input[0];

   if(w->genTermEm.SpecialVars.store.NumToGo == 0-1)
    XtAppError(XtWidgetToApplicationContext(w),
	       "Error in GenTermEm widget, Upto matching function needs a non-zero argument!");
   
   w->genTermEm.InputArgs[position].string = 
    &(w->genTermEm.InputStack[w->genTermEm.TopStack]);
   w->genTermEm.InputArgs[position].valid = ADEFINED;
  }

 *num = 0;
 for(i = start; i <len; i++)
  {
   *num += 1;
   w->genTermEm.InputArgs[position].length += 1;
   if(string[i] == (char)w->genTermEm.SpecialVars.store.NumToGo)
    {
     w->genTermEm.SpecialVars.Started = 0;
     return(1);
    }
  }
 return(2);
}

/* ArgToInt:  This function converts parser argument list element into an */
/*  integer value.  If the requested argument is not is not in the list then */
/*  the default value is returned. */

static int ArgToInt(w,args,position,def)

GenTermEmWidget w;
struct ArgumentList *args;
int position;
int def;

{
 int n;
 char string [1024];

 if(args->NumArgs < position)
  return(def);
 else
  {
   switch(args->args[position-1].type)
    {
   case AINT:
     return(args->args[position-1].n);
   case APOSITION:
     n = args->args[position-1].n;
     if(w->genTermEm.InputArgs[n].valid)
      {
       memcpy(string,w->genTermEm.InputArgs[n].string,
	       w->genTermEm.InputArgs[n].length);
       string[w->genTermEm.InputArgs[n].length] = NULL;
       return(atoi(string));
      }
     else
      return(def);
   case ASTRING:
     return(atoi(args->args[position-1].string));
    }
  }
}

/* ArgToFloat: This function converts an input parser argument into a */
/* float. */

static float ArgToFloat(w,args,position,def)

GenTermEmWidget w;
struct ArgumentList *args;
int position;
float def;

{
 int n;
 char string[1024];
 
 if(args->NumArgs < position)
  return(def);
 else
  {
   switch(args->args[position-1].type)
    {
   case AINT:
     return((float)args->args[position-1].n);
   case APOSITION:
     n = args->args[position-1].n;
     if(w->genTermEm.InputArgs[n].valid)
      {
       memcpy(string,w->genTermEm.InputArgs[n].string,
	       w->genTermEm.InputArgs[n].length);
       string[w->genTermEm.InputArgs[n].length] = NULL;
       return((float)atof(string));
      }
     else
      return(def);
   case ASTRING:
     return((float)atof(args->args[position-1].string));
    }
  }
}

/* ArgToString:  This function converts an input parser argument into a  */
/*  string.  The output is stored in the given string which must be big */
/*  enough to store everything.  */

static char *ArgToString(w,args,position,def,string,len)

GenTermEmWidget w;
struct ArgumentList *args;
int position;
char *def;
char *string;
int len;

{
 int n;
 char store[1024];

  if(args->NumArgs < position)
  {
   memcpy(string,def,len);
   string[len] = NULL;
   return(string);
  }
 else
  {
   position--;
   switch(args->args[position].type)
    {
   case AINT:
     GtEIntToStringConvert(args->args[position].n,store);
     memcpy(string,store,len);
     string[len] = NULL;
     return(string);
   case APOSITION:
     n = args->args[position].n;
     if(w->genTermEm.InputArgs[n].valid)
      {
       if(w->genTermEm.InputArgs[n].length < len)
	len = w->genTermEm.InputArgs[n].length;
       memcpy(string,w->genTermEm.InputArgs[n].string,len);
       string[len] = NULL;
      }
     else
      {
       memcpy(string,def,len);
       string[len] = NULL;
      }
     return(string);
   case ASTRING:
     if(args->args[position].n < len)
      len= args->args[position].n;
     memcpy(string,args->args[position].string,len);
     string[len] = NULL;
     return(string);
    }
  }
}

/* GtEIntToStringConvert:  This function takes an integer and converts it */
/*   into a string*/

static char *GtEIntToStringConvert(num,string)

int num;
char *string;

{
 int len,j,digit;
 int flag = 0;
 char store[200];

 if(num == 0)
  strcpy(string,"0");
 else
  {
   j = 0;
   if(num < 0)
    {
     flag = 1;
     num = num * -1;
    }
   while(num > 0)
    {
     digit = num / 10;
     store[j++] = '0' + num - digit * 10;
     num = digit;
    }
   string[j+flag] = NULL;
   if(flag == 1)
    string[0] = '-';
   for(num = 0; num < j; num++)
    string[num+flag] = store[j-1-num];
  }
 return(string);
}

/* IntToInputArg:  This function takes an integer and stores it as an input */
/*  argument in the given argument position */

static int IntToInputArg(w,position,num)

GenTermEmWidget w;
int position;
int num;

{
 char string[1024];
 int len;
 int j;
 int digit;

 if((position < 0) || (position >= NUMARGS))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
	       "GenTermEm Widget: Invalid position number in IntToInputArg");
   return(-1);
  }

 GtEIntToStringConvert(num,string);
 j = strlen(string);

 if((w->genTermEm.InputArgs[position].valid & ADEFINED) &&
    (w->genTermEm.InputArgs[position].valid & AMALLOCED))
  XtFree(w->genTermEm.InputArgs[position].string);

 w->genTermEm.InputArgs[position].valid = ADEFINED | AMALLOCED;
 w->genTermEm.InputArgs[position].length = j;
 w->genTermEm.InputArgs[position].string = 
  (char *) XtMalloc(sizeof(char)*j+1);
 w->genTermEm.InputArgs[position].string[j] = NULL;
 strcpy(w->genTermEm.InputArgs[position].string,string);
}

/* StringToInputArg:  This function takes a string and stores it as an input */
/*  argumet in the given argument position */

static int StringToInputArg(w,position,string,len)

GenTermEmWidget w;
int position;
char *string;
int len;

{

 if((position < 0) || (position >= NUMARGS))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Invalid argument number in StringToInputArg");
   return(-1);
  }

 if((w->genTermEm.InputArgs[position].valid & ADEFINED) &&
    (w->genTermEm.InputArgs[position].valid & AMALLOCED))
  XtFree(w->genTermEm.InputArgs[position].string);

 w->genTermEm.InputArgs[position].valid = ADEFINED | AMALLOCED;
 w->genTermEm.InputArgs[position].length = len;
 w->genTermEm.InputArgs[position].string =
  (char *) XtMalloc(sizeof(char)*(len + 1));
 memcpy(w->genTermEm.InputArgs[position].string,string,len);
 w->genTermEm.InputArgs[position].string[len] = NULL;
}

/*  We now begin the second of the parser which implement the individual */
/*  translators. */

/* GtENewLine:  This translator implements the newline function.  It moves */
/*  the current position down one line and will force a scroll at the bottom */
/*  of a scroll region. */

static int GtENewLine(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 GtNewLine(w,1);
 return(TRANSOKAY);
}

/* GtEDownLine:  This translator moves the cursor down n lines.  If wrap=0 */
/*  the screen will be scrolled up at the bottom of the screen.  If wrap=1 */
/*  the cursor will wrap around to the top. If wrap=2, then the cursor */
/*  sticks at the bottom. */

static int GtEDownLine(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n = 0;
 int wrap;

 n = ArgToInt(w,args,1,1);
 wrap = ArgToInt(w,args,2,0);
 GtCursorDown(w,n,wrap);
 return(TRANSOKAY);
}

/* GtEUpLine: This translator moves the cursor up n lines.  If wrap=0, the */
/*  screen is scrolled down when the cursor moves passed the top.  If wrap=1,*/
/*  the cursor will wrap around to the bottom. If wrap=2, the cursor will */
/*  stick at the top of the screen. */

static int GtEUpLine(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n,wrap;

 n = ArgToInt(w,args,1,1);
 wrap = ArgToInt(w,args,2,0);
 GtCursorUp(w,n,wrap);
 return(TRANSOKAY);
}

/* GtEMoveLeft:  This translator moves the cursor left n lines.  If wrap = 0 */
/*  the cursor will remain at the column 0 when it hits it.  If wrap = 1 the */
/*  cursor will wrap around to the rightmost column. */

static int GtEMoveLeft(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n = 0;
 int wrap;
 int roll;

 n = ArgToInt(w,args,1,1);
 wrap = ArgToInt(w,args,2,0);
 roll = ArgToInt(w,args,3,0); 
 GtCursorLeft(w,n,wrap,roll);
 return(TRANSOKAY);
}

/* GtEMoveRight:  This translator ove the cursor right n lines.  If wrap = 0 */
/*  the cursor remains at the rightmost column.  Otherwise, it wraps around */
/*  to the leftmost one. If roll=0 the cursor will wrap from the bottom right*/
/*  of the screen to the top left, otherwise it the screen is rolled up */

static int GtEMoveRight(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n;
 int wrap;
 int roll;

 n = ArgToInt(w,args,1,1);
 wrap = ArgToInt(w,args,2,0);
 roll = ArgToInt(w,args,3,0);
 GtCursorRight(w,n,wrap,roll);
 return(TRANSOKAY);
}

/* GtEMoveCursor:  Move the cursor to the position given by the row and */
/*  column argument.  If this position is invalid, GtSetCursorPosition will */
/*  move to the closest valid position. */

static int GtEMoveCursor(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int row,column;

 row = ArgToInt(w,args,1,0);
 column = ArgToInt(w,args,2,0);

 GtSetCursorPosition(w,row,column);
 return(TRANSOKAY);
}

/* GtECarriageReturn:  This translator moves the current position to column 0*/

static int GtECarriageReturn(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 GtCursorReturn(w);
 return(TRANSOKAY);
}

/* GtENextTab:  This translator moves the cursor to the next tab stop.  If */
/*  destructive tabs are set, the movement is performed by outputing spaces */
/*  otherwise a simple cursor move is performed. */

static int GtENextTab(w,args)

GenTermEmWidget w;
struct ArgumntList *args;

{
 int crow,ccolumn;
 int i;
 int fcolumn;
 int dist;
 char buffer[80];

 GtGetCursorPosition(w,&crow,&ccolumn);
 for(i = 0; i < NTABS; i++)
  if(w->genTermEm.TabStops[i] > ccolumn)
   break;
 if(i == NTABS)
  fcolumn = w->genTermEm.TabStops[NTABS - 1];
 else
  fcolumn = w->genTermEm.TabStops[i];

 dist = fcolumn - ccolumn;
 if(w->genTermEm.DestructiveTab == TRUE)
  {
   for(i = 0; i < dist; i++)
    buffer[i] = ' ';
   GtOutput(w,buffer,dist);
  }
 else
  GtCursorRight(w,dist,1,1);
 return(TRANSOKAY);
}

/* PreviousTab:  This translator moves the cursor to the previous tab stop */
/*  If there are no tab stops to the left then the cursor is moved to column */
/*  zero. */

static int GtEPreviousTab(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int crow,ccolumn;
 int i;
 int fcolumn = 0;
 int dist;

 GtGetCursorPosition(w,&crow,&ccolumn);
 for(i = NTABS - 1; i >= 0; i--)
  if(w->genTermEm.TabStops[i] <= ccolumn)
   {
    fcolumn = w->genTermEm.TabStops[i];
    break;
   }

 dist = ccolumn - fcolumn;
 GtCursorLeft(w,dist,0,1);
 return(TRANSOKAY);
}

/* GtESetTab:  This function sets a new tab stop at the passed column */
/*   position. */

static int GtESetTab(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int newtab;
 int i,j;

 newtab = ArgToInt(w,args,1,-1);

 if(newtab == -1)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid number of arguments for SetTab translator");
   return(TRANSERROR);
  }
 else
  {
   for(i = 0; i < NTABS; i++)
    {
     if(w->genTermEm.TabStops[i] > newtab)
      break;
    }
   if(i == NTABS)
    i = NTABS - 1;
   for(j = NTABS - 2; j >= i; j--)
    {
     w->genTermEm.TabStops[j+1] = w->genTermEm.TabStops[j];
    }
   w->genTermEm.TabStops[i] = newtab;
  }
 return(TRANSOKAY);
}

/* GtEUnSetTab:  This translator clears a tab stop at the passed column. */
/*  If the position is -1, all tab stops are cleared. */

static int GtEUnSetTab(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int tab;
 int i;

 tab = ArgToInt(w,args,1,-1);

 if(tab == -1)
  {
   for(i = 0; i < NTABS; i++)
    w->genTermEm.TabStops[i] = 0;
  }
 else
  {
   for(i = 0; i < NTABS; i++)
    if(w->genTermEm.TabStops[i] == tab)
     {
      if(i == 0)
       w->genTermEm.TabStops[i] = 0;
      else
       w->genTermEm.TabStops[i] = w->genTermEm.TabStops[i-1];
     }
  }
 return(TRANSOKAY);
}

/* GtESoundBell:  This translator causes the terminal to beep. */

static int GtESoundBell(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 XBell(XtDisplay(w),50);
 return(TRANSOKAY);
}

/* GtEGetBottomText:  This translator determines the last row on the screen */
/*  which has any text on it.  The row number is returned in the passed */
/*  argument number.  */

static int GtEGetBottomText(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int position;
 char string[1024];
 int len;
 int i;
 int rows,cols;

 position = ArgToInt(w,args,1,1);
 GtGetScreenSize(w,&rows,&cols);

 for(i = rows - 1; i >= 0; i--)
  {
   GtGetLine(w,i,string,&len);
   if(len != 0)
    break;
  }

 IntToInputArg(w,position,i);
 return(TRANSOKAY);
}

/* GtEGetPosition: This translator returns the current row and column  */
/*  position in the passed argument numbers. */

static int GtEGetPosition(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int rpos,cpos;
 int row,col;

 rpos = ArgToInt(w,args,1,1);
 cpos = ArgToInt(w,args,2,2);

 GtGetCursorPosition(w,&row,&col);
 IntToInputArg(w,rpos,row);
 IntToInputArg(w,cpos,col);
 return(TRANSOKAY);
}

/* GtESetFont:  This translators set the font to the base font if the */
/*  argument is 0 and to the alternate font if the argument is 1 */

static int GtESetFont(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag;

 flag = ArgToInt(w,args,1,0);

 if((flag == 0) || (flag == 1))
  {
   GtSetAttribute(w,GTFONT,flag);
   return(TRANSOKAY);
  }
 else
  return(TRANSERROR); 
}

/* GtESetPen: This translator sets the pen number to the given argument. */

static int GtESetPen(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num = ArgToInt(w,args,1,0);

 GtSetAttribute(w,GTPEN,num);
 return(TRANSOKAY);
}

/* GtEGetFont:  This translator returns 0 if the current font is the base */
/*  font or 1 if it isthe alternate font. */

static int GtEGetFont(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int value;
 int pos = ArgToInt(w,args,1,1);

 GtGetAttribute(w,GTFONT,&value);
 
 IntToInputArg(w,pos,value);
 return(TRANSOKAY);
}

/* GtEGetPen:  This translator returns the number of the pen which is */
/*  currently in use. */

static int GtEGetPen(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int value;
 int pos = ArgToInt(w,args,1,1);

 GtGetAttribute(w,GTPEN,&value);

 IntToInputArg(w,pos,value);
 return(TRANSOKAY);
}

/* GtESetInverseVideo:  This translator puts the widget int inverse video */
/*  mode if the argument is 1 and sets it to normal if the argument is 0 */

static int GtESetInverseVideo(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag = ArgToInt(w,args,1,0);

 if((flag == 0) || (flag == 1))
  {
   GtSetAttribute(w,GTINVERSEVIDEO,flag);
   return(TRANSOKAY);
  }
 else
  return(TRANSERROR);
}

/* GtESetUnderLineMode:  This translator puts the widget into underline mode */
/*  if the argument is 1 and sets it to normal if the argument is 0 */

static int GtESetUnderLineMode(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag = ArgToInt(w,args,1,0);

 if((flag == 0) || (flag == 1))
  {
   GtSetAttribute(w,GTUNDERLINE,flag);
   return(TRANSOKAY);
  }
 else
  return(TRANSERROR);
}

/* GtESetHalfBrightMote:  This translator turns the half bright mode on or */
/*  off. */

static int GtESetHalfBrightMode(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag = ArgToInt(w,args,1,0);

 if((flag == 0) || (flag == 1))
  {
   GtSetAttribute(w,GTHALFBRIGHT,flag);
   return(TRANSOKAY);
  }
 else
  return(TRANSERROR);
}

/* GtESetBlinkMode: This translator turns the blink mode on or off */

static int GtESetBlinkMode(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag = ArgToInt(w,args,1,0);

 if((flag == 0) || (flag == 1))
  {
   GtSetAttribute(w,GTBLINKMODE,flag);
   return(TRANSOKAY);
  }
 else
  return(TRANSERROR);
}

/* GtESetField:  This translator causes the GenTerm widget to extend the */
/*  current attribute through out the rest of the field.  A field ends at */
/*  the next non-blank character or the end of the line. */

static int GtESetField(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int type = ArgToInt(w,args,1,0);

 GtSetFieldAttribute(w,type);
 return(TRANSOKAY);
}

/* GtEClearLine:  This translator clears the current line.  If the argument */
/*   is 0 the entire line is cleared, if line = 1 then the line is cleared */
/*   from the  cursor to the end of the line. If line = 2 then the line is */
/*   cleared from the beginning of the line upto the cursor */

static int GtEClearLine(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag;
 int crow,ccolumn;
 int rows,columns;

 flag = ArgToInt(w,args,1,1);
 GtGetCursorPosition(w,&crow,&ccolumn);
 GtGetScreenSize(w,&rows,&columns);

 if(flag == 0)
  GtClearRegion(w,crow,0,crow,columns);
 else if(flag == 1)
  GtClearRegion(w,crow,ccolumn,crow,columns);
 else if(flag == 2)
  GtClearRegion(w,crow,0,crow,ccolumn-1);
 else
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Bad line mode in ClearLine translator");
   return(TRANSERROR);
  }
 return(TRANSOKAY);
}

/* GtEClearDisplay:  This translator clears the display starting given line */
/*  and going down to the given bottom lines or the bottom of the screen if */
/*  none given. */

static int GtEClearDisplay(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int line;
 int bottom; 
 int rows,columns;

 GtGetScreenSize(w,&rows,&columns);
 line = ArgToInt(w,args,1,0);
 bottom = ArgToInt(w,args,2,rows);
 if(line < rows)
  GtClearRegion(w,line,0,bottom,columns);
 return(TRANSOKAY);
}

/* GtEMath:  This translator performs a math operation on its arguments and */
/*  returns the result in another argument.  The first and third arguments */
/*  are the two operands.  The second argument is a string which is used to */
/*  define the operation to be carried out.  The fourth argument is the */
/*  number of the argument in which the result is to be returned. */

static int GtEMath(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int op1,op2;
 int result;
 int pos;
 int type = 1;
 char operation[2];
 char string1[100];
 char string2[100];
 char string3[100];

 op1 = ArgToInt(w,args,1,0);
 op2 = ArgToInt(w,args,3,0);
 pos = ArgToInt(w,args,4,1);
 ArgToString(w,args,2," ",operation,1);

 switch(operation[0])
  {
 case '+':
   result = op1 + op2;
   break;
 case '-':
   result = op1 - op2;
   break;
 case '*':
   result = op1 * op2;
   break;
 case '/':
   if(op2 == 0)
    result = 0;
   else
    result = op1 / op2;
   break;
 case '%':
   result = op1 % op2;
   break;
 case '>':
   result = op1 >> op2;
   break;
 case '<' :
  result = op1 << op2;
   break;
 case '&':
   ArgToString(w,args,1," ",string1,99);
   ArgToString(w,args,3," ",string2,99);
   strcpy(string3,string1);
   strcat(string3,string2);
   type = 2;
   break;
 default:
   result = 0;
  }
 if(type == 1)
  IntToInputArg(w,pos,result);
 else
  StringToInputArg(w,pos,string3,strlen(string3));
 return(TRANSOKAY);
}

/* GtEIf:  This translators implements an if function.  The first and third */
/*  are the conditionals to be evaluated.  The second argument is the boolean*/
/*  expression to be evaluated.  The fourth argument is the function label */
/*  which will be branched to if the expression evaluates to true. */

static int GtEIf(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int op1,op2;
 char operation[10];
 int result;
 int label;

 op1 = ArgToInt(w,args,1,0);
 op2 = ArgToInt(w,args,3,0);
 label = ArgToInt(w,args,4,1);
 ArgToString(w,args,2," ",operation,9);

 if(strcmp(operation,"=") == 0)
  result = (op1 == op2);
 else if(strcmp(operation,">") == 0)
  result = (op1 > op2);
 else if(strcmp(operation,">=") == 0)
  result = (op1 >= op2);
 else if(strcmp(operation,"<") == 0)
  result = (op1 < op2);
 else if(strcmp(operation,"<=") == 0)
  result = (op1 <= op2);
 else if(strcmp(operation,"!=") == 0)
  result = (op1 != op2);
 else
  result = 0;
 
 if(result)
  return(label);
 else
  return(TRANSOKAY);
}

/* GtELoadAttribute:  This translator caused the GenTerm widget to load its */
/*  current attribute with the attribute settings of the character at */
/*  the position given by the first (row) and second (column arguments */

static int GtELoadAttribute(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int row,col;

 row = ArgToInt(w,args,1,0);
 col = ArgToInt(w,args,2,0);

 GtLoadAttribute(w,row,col);
 return(TRANSOKAY);
}

/* GtEClearMemory:  This translator causes the GenTerm widget to clear its */
/*  virtual screen.  If the argument=0 then the entire virtual screen is */
/*  cleared.  If it is equal to 1 then the portion of the virtual screen */
/*  currently below the real screen is cleared.  If it is equal to 2 then */
/*  portion of the virtual screen above the real screen is cleared. */

static int GtEClearMemory(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int which;
 
 which = ArgToInt(w,args,1,0);

 if((which >= 0) && (which <= 3))
  {
   GtClearMemory(w,which);
   return(TRANSOKAY);
  }
 else
  return(TRANSOKAY);
}

/* GtEInsertLines:  This translator inserts a number of lines into the */
/*  virtual screen.  The first argument is the number of lines to insert. */
/*  The second is the offset from the current position where the insertion */
/* is to take place. */

static int GtEInsertLines(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n,where;
 int row,column;

 n = ArgToInt(w,args,1,1);
 where = ArgToInt(w,args,2,1);

 GtGetCursorPosition(w,&row,&column);
 row += where;
 GtInsertLines(w,row,n);
 return(TRANSOKAY);
}

/* GtEDeleteLines:  This translator deletes a number of lines in the virtual */
/*  screen.  The argument is the number of lines to delete. */

static int GtEDeleteLines(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num;

 num = ArgToInt(w,args,1,1);

 GtDeleteLines(w,num);
 return(TRANSOKAY);
}

/* GtESetTop:  This translator sets the line number of the top of the screen */
/*  to correspond to the argument */
static int GtESetTop(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int position = ArgToInt(w,args,1,0);

 GtSetTopOfScreen(w,position);
 return(TRANSOKAY);
}

/* GtEDeleteCharacters:  This translator deletes n characters starting at the*/
/*  current position.  The argument is the number of characters to delete. */

static int GtEDeleteCharacters(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num = ArgToInt(w,args,1,1);

 GtDeleteCharacters(w,num);
 return(TRANSOKAY);
}

/* GtEGetTop:  This translator determine the line number of the top of the */
/*  screen and returns it in the passed argument number. */

static int GtEGetTop(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int pos = ArgToInt(w,args,1,1);
 int top;

 top = GtGetTopOfScreen(w);

 IntToInputArg(w,pos,top);
 return(TRANSOKAY);
}

/* GtEGetScreenSize: This translator returns the size of the screen in the */
/*  passed arguments. */

static int GtEGetScreenSize(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int rows,columns;
 int rpos = ArgToInt(w,args,1,1);
 int cpos = ArgToInt(w,args,2,2);

 GtGetScreenSize(w,&rows,&columns);
 IntToInputArg(w,rpos,rows);
 IntToInputArg(w,cpos,columns);
 return(TRANSOKAY);
}

/* GtESetInsertMode:  This translator sets the terminal widget's insert mode */
/*  If the passed argument is a one then insert mode is turned on.  If it is */
/*  a zero, it is turned off. */

static int GtESetInsertMode(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int flag;
 Arg Xargs[10];
 int n = 0;

 flag = ArgToInt(w,args,1,0);

 if(flag == 0)
  {
   XtSetArg(Xargs[n],XtNinsertMode,False);
   n++;
  }
 else if(flag == 1)
  {
   XtSetArg(Xargs[n],XtNinsertMode,True);
   n++;
  }
 else
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid argument for SetInsertMode translator");
   return(TRANSERROR);
  }

 XtSetValues(w,Xargs,n);
 return(TRANSOKAY);
}

/* GtESetParseTable: This translator changes the current parse table to */
/*  the one specified by the given name.  If no parse table exists under */
/*  that name, a warning is issued and the request is ignored. */

static int GtESetParseTable(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 char name[80];
 struct GtEList *temp;

 ArgToString(w,args,1,"Default",name,79);
 temp = w->genTermEm.ParseList;
 while(temp != NULL)
  {
   if(strcmp(name,temp->Name) == 0)
    break;
   temp = temp->Next;
  }
 if(temp == NULL)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Bad parse table name given to SetParseTable translator");
   return(TRANSERROR);
  }
 else
  {
   w->genTermEm.ParseTable = temp->Point.ParseTable;
   return(TRANSOKAY);
  }
}

/* GtESetKeyTable:  This translator changes the current key translation */
/*  table to the one specified by the given name.  If no key table exists */
/*  under that name, a warning is issued and the request is ignored. */

static int GtESetKeyTable(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 char name[80];
 struct GtEList *temp;

 ArgToString(w,args,1,"Default",name,79);
 temp = w->genTermEm.KeyList;
 while(temp != NULL)
  {
   if(strcmp(name,temp->Name) == 0)
    break;
   temp = temp->Next;
  }
 if(temp == NULL)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Bad parse table name given to SetKeyTable translator");
   return(TRANSERROR);
  }
 else
  {
   w->genTermEm.Keys = temp->Point.KeyTable;
   w->genTermEm.NumKeys = temp->Num;
   return(TRANSOKAY);
  }
}

/* GtESetResource:  This translator sets the specified resource to the given*/
/*  value.  Note currently is can only set integer values. */

static int GtESetResource(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 char resource[80];
 int value;
 Arg Xargs[10];
 int n = 0;

 ArgToString(w,args,1," ",resource,79);
 value = ArgToInt(w,args,2,0);

 XtSetArg(Xargs[n],resource,value);
 n++;
 XtSetValues(w,Xargs,n);
 return(TRANSOKAY);
}

/* GtEGetResource:  This translator gets the specified resource and returns */
/*  it in the passed variable. */

static int GtEGetResource(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 char resource[80];
 int value;
 Arg Xargs[10];
 int n = 0;
 int position = ArgToInt(w,args,2,1);

 ArgToString(w,args,1," ",resource,79);

 XtSetArg(Xargs[n],resource,&value); n++;
 XtGetValues(w,Xargs,n);
 IntToInputArg(w,position,value);
 return(TRANSOKAY);
}

/* GtEEmit:  This function emits the passed character strings.  The data is */
/*  is passed to the parent functions via the keyboard callback. */

static int GtEEmit(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 GenTermEmCallback reason;
 char string[1024];
 int i;

 reason.reason = GTE_INPUT;
 reason.event = NULL;
 reason.string = string;

 for(i = 1; i <= args->NumArgs; i++)
  {
   ArgToString(w,args,i,"",string,1023);
   reason.len = strlen(string);

   XtCallCallbacks(w,XtNkbdCallback,(caddr_t) &reason);
  }
 return(TRANSOKAY);
}

/* GtEOutputString: This function outputs the passed character strings on */
/*   the terminal widget.  WARNING!!! This function causes the GtEParse */
/*   function to be called recursively which can cause the input stack to be */
/*   over written. Call this translator with care */

static int GtEOutputString(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 char string[1024];
 int i;
 struct InputArgument *Store;

 for(i = 1; i <= args->NumArgs; i++)
  {
   ArgToString(w,args,i,"",string,1023);
   Store = GtEPushArgs(w);
   GtEOutput(w,string,strlen(string));
   GtEPopArgs(w,Store);
  }
 return(TRANSOKAY);
}

/* GtEGetLine:  This translator returns the characters on the screen  */
/*  starting at the given position and continueing to the end of the line */

static int GtEGetLine(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int row;
 int col;
 int pos;
 int len;
 char string[1024];

 row = ArgToInt(w,args,1,0);
 col = ArgToInt(w,args,2,0);
 pos = ArgToInt(w,args,3,1);

 GtGetLine(w,row,string,&len);
 len -= col;
 if(len < 0)
  len = 0;
 StringToInputArg(w,pos,&(string[col]),len);
 return(TRANSOKAY);
}

/* GtESetScrollRegion:  This translator sets the scroll region for the given */
/*  range and scroll region number. */

static int GtESetScrollRegion(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int rows,columns;
 int start = ArgToInt(w,args,1,0);
 int end = ArgToInt(w,args,2,-1);
 int num = ArgToInt(w,args,3,0);

 GtGetScreenSize(w,&rows,&columns);
 if(end == -1)
  end = rows - 1;
 GtSetScrollRegion(w,start,end,num);
 return(TRANSOKAY);
}

/* GtEReject:  This translator causes the parser to reject the currently */
/*  matched and to reset the parser. */

static int GtEReject(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 return(TRANSREJECT);
}

/* GtEGetTopOfScrollRegion: This translator returns the row number */
/*  corresponding to the top of the given scroll region.  If the scroll */
/*  region doesn't exist then a zero is returned. */

static int GtEGetTopOfScrollRegion(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num;
 int pos;
 int top,bottom;

 num = ArgToInt(w,args,1,0);
 pos = ArgToInt(w,args,2,1);

 GtGetScrollRegion(w,num,&top,&bottom);
 if(top == -1)
  top = 0;
 IntToInputArg(w,pos,top);

 return(TRANSOKAY);
}

/* GtEQuit:  This translator causes the parser to quite executing translators*/
/*  and to parse the next character. */

static int GtEQuit(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 return(TRANSERROR);
}

/* GtEProgramKey:  This translator sets the information for a specific */
/*  function key.  The first agrument is the type of function to assign to */
/*  the key.  The second aregument is the key number.  The third argument */
/*  is the key label and the final argument is the string to be bound to the */
/*  key. */

static int GtEProgramKey(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int type = ArgToInt(w,args,1,0);
 int number = ArgToInt(w,args,2,1);
 char label[20];
 char string[1000];
 char buffer[100];
 Arg xargs[20];
 int n = 0;
 
 ArgToString(w,args,3," ",label,19);
 ArgToString(w,args,4,"",string,999);

 number--;
 if((number >= 0) && (number < NKEYS))
  {
   if(strlen(label) > 0)
    {
     XtFree(w->genTermEm.FKeys[number].Label);
     w->genTermEm.FKeys[number].Label = 
      XtMalloc(sizeof(char)*(strlen(label)+1));
    strcpy(w->genTermEm.FKeys[number].Label,label); 
    }
   if(strlen(string) > 0)
    {
     XtFree(w->genTermEm.FKeys[number].String);
     w->genTermEm.FKeys[number].String = XtMalloc(sizeof(char) *
						 (strlen(string) + 1));
     strcpy(w->genTermEm.FKeys[number].String,string);
    }
   
   w->genTermEm.FKeys[number].Type = type;

   if(strlen(label) > w->genTermEm.FuncLabelWidth)
    {
     memcpy(buffer,label,w->genTermEm.FuncLabelWidth);
     buffer[w->genTermEm.FuncLabelWidth] = '\n';
     strcpy(&(buffer[w->genTermEm.FuncLabelWidth + 1]),
	    &(label[w->genTermEm.FuncLabelWidth]));
    }
   else
    strcpy(buffer,label);

   if(w->genTermEm.FunctionRealized == True)
    {
     XtSetArg(xargs[n],XmNlabelString,
	      XmStringCreateLtoR(buffer,XmSTRING_DEFAULT_CHARSET)); n++;
     
     XtSetValues(w->genTermEm.FKeys[number].FuncKey,xargs,n);
    }
  }

}

/* GtEIgnore:  This translator is do nothing function.  It is effectively a */
/*  no-op */

static int GtEIgnore(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 return(TRANSOKAY);
}

/* GtEDefinePen:  This translator defines the foreground and background */
/*  colour of a pen.  The first arguement is the pen number to be defined. */
/*  The next three arguments specify the colours of the foreground.  These */
/*  values run from 0 to 1 and are either rgb or hsl values depending on */
/*  DefineColor resource. The final three arguements is the colour */
/*  specification of the background. */

static int GtEDefinePen(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int npen = ArgToInt(w,args,1,0);
 float fr = ArgToFloat(w,args,2,0);
 float fg = ArgToFloat(w,args,3,0);
 float fb = ArgToFloat(w,args,4,0);
 float br = ArgToFloat(w,args,5,0);
 float bg = ArgToFloat(w,args,6,0);
 float bb = ArgToFloat(w,args,7,0);

 GtDefinePenColour(w,npen,fr,fg,fb,br,bg,bb);
 return(TRANSOKAY);
}

/* GtEExecuteFunctionKey:  This translator executes a specific function key */
/*  just as if the user had pressed it. */

static int GtEExecuteFunctionKey(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int key = ArgToInt(w,args,1,1);
 GenTermEmCallback ReasonSent;
 char buffer[1024];

 if((key > 0) && (key < w->genTermEm.NumberFunctionKeys))
  {
   ReasonSent.reason = GTE_INPUT;
   ReasonSent.event = NULL;
   ReasonSent.string = buffer;
   ReasonSent.len = 0;

   if((w->genTermEm.FKeys[key].Type == 0) || (w->genTermEm.FKeys[key].Type == 2))
    {
     strcpy(buffer,w->genTermEm.FKeys[key].String);
     ReasonSent.len = strlen(buffer);
    }
   if((w->genTermEm.FKeys[key].Type == 0) || (w->genTermEm.FKeys[key].Type == 1))
    {
     GtEOutput(w,w->genTermEm.FKeys[key].String,
	       strlen(w->genTermEm.FKeys[key].String));
    }
   if(ReasonSent.len > 0)
    XtCallCallbacks(w,XtNkbdCallback,(caddr_t) &ReasonSent);

   return(TRANSOKAY);
  }
 else
  return(TRANSERROR);
}

/* GtEEscapeCallback:  This translator causes any escape callbacks that are */
/*  bound to the widget to be executed.  */

static int GtEEscapeCallback(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 GenTermEmCallback callback;
 int i;
 int nargs = args->NumArgs;
 char buffer[1024];

 callback.reason = GTE_ESCAPE;
 callback.event = NULL;
 callback.escapes = (char **) XtMalloc(sizeof(char *) * (nargs + 1));

 for(i = 1; i <= nargs; i++)
  {
   ArgToString(w,args,i,"",buffer,1023);
   callback.escapes[i-1] = (char *) XtMalloc(sizeof(char) * strlen(buffer)+1);
   strcpy(callback.escapes[i-1],buffer);
  }
 callback.escapes[nargs] = NULL;
 
 XtCallCallbacks(w,XtNescCallback,(caddr_t)&callback);

 for(i = 0; i <nargs; i++)
  XtFree(callback.escapes[i]);
 XtFree(callback.escapes);
 return(TRANSOKAY);
}

/* GtELoadMapTable:  This translator loads the specified output mapping */
/*  table. */

static int GtELoadMapTable(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num = ArgToInt(w,args,1,0);

 if((num < 0) || (num >= w->genTermEm.NumMapTables))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid table number in LoadMapTable translator");
   return(TRANSERROR);
  }
 GtSetMapTable(w,w->genTermEm.MapTables[num]);
 return(TRANSOKAY);
}

/* GtEProgramMapTable: This translator sets the values in the specied */
/*  mapping table.  The values are specified by the starting and ending */
/*  positions in the table and the value to set the starting position to and */
/*  the value to set the ending value to.  All intermediate values are set to*/
/*  the linear points inbetween. */

static int GtEProgramMapTable(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num = ArgToInt(w,args,1,0);
 int StartPoint = ArgToInt(w,args,2,0);
 int EndPoint = ArgToInt(w,args,3,NMAP-1);
 int StartValue = ArgToInt(w,args,4,0);
 int EndValue = ArgToInt(w,args,5,NMAP-1);
 int i;
 int val,step;

 if((num < 0) || (num >= w->genTermEm.NumMapTables))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid table number in ProgramMapTable translator");
   return(TRANSERROR);
  }

 if((StartPoint < 0) || (StartPoint >= NMAP) || (EndPoint < 0) ||
    (EndPoint >= NMAP))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid range in PorgramMapTable translator");
   return(TRANSERROR);
  }

 val = StartValue;
 step = (EndValue - StartValue)/(EndPoint - StartPoint - 1);

 for(i = StartPoint; i <= EndPoint; i++, val += step)
  w->genTermEm.MapTables[num][i] = val;

 return(TRANSOKAY);
}

/* GtEStore: This translator takes an input argument and copies it to the */
/*  the global input stack so that it can be recalled at a later date */

static int GtEStore(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int position = ArgToInt(w,args,2,1);
 char string[1024];

 ArgToString(w,args,1," ",string,1023);

 if((position < 0 ) || (position >= w->genTermEm.NumStoreArgs))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid storage position in Store translator");
   return(TRANSERROR);
  }

 if(w->genTermEm.StoreArgs[position].valid & AMALLOCED)
  XtFree(w->genTermEm.StoreArgs[position].string);

 w->genTermEm.StoreArgs[position].valid = ADEFINED | AMALLOCED;
 w->genTermEm.StoreArgs[position].length = strlen(string);
 w->genTermEm.StoreArgs[position].string = 
  (char *) XtMalloc(sizeof(char) *
		    (w->genTermEm.StoreArgs[position].length + 1));
 strcpy(w->genTermEm.StoreArgs[position].string,string);
 
 return(TRANSOKAY);
}

/* GtEFetch:  This translator takes the global argument at the given position*/
/*  position and returns it in the position specified from the second */
/*  argument. */

static int GtEFetch(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int from = ArgToInt(w,args,1,1);
 int to = ArgToInt(w,args,2,1);

 if((from < 0) || (from >= w->genTermEm.NumStoreArgs))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"Invalid storage position in Fetch translator");
   return(TRANSERROR);
  }
 
 if((w->genTermEm.StoreArgs[from].valid & ADEFINED) == 0)
  StringToInputArg(w,to," ",1);
 else
  StringToInputArg(w,to,w->genTermEm.StoreArgs[from].string,
		   w->genTermEm.StoreArgs[from].length);

 return(TRANSOKAY);
}

/* GtEGetArg:  This translator implements an indirect reference to an input */
/*  argument.  Its first argument is the number of the input argument to get */
/*  The second argument is the store the referenced value in. */

static int GtEGetArg(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int from = ArgToInt(w,args,1,1);
 int to = ArgToInt(w,args,2,2);

 if(w->genTermEm.InputArgs[to].valid & AMALLOCED)
  XtFree(w->genTermEm.InputArgs[to].string);

 w->genTermEm.InputArgs[to].valid = w->genTermEm.InputArgs[from].valid;
 w->genTermEm.InputArgs[to].length = w->genTermEm.InputArgs[from].length;

 if(w->genTermEm.InputArgs[to].valid & AMALLOCED)
  {
   w->genTermEm.InputArgs[to].string = 
    XtMalloc(sizeof(char) * (w->genTermEm.InputArgs[to].length + 1));
   memcpy(w->genTermEm.InputArgs[to].string,w->genTermEm.InputArgs[from].string,
	  w->genTermEm.InputArgs[from].length);
  }
 else
  w->genTermEm.InputArgs[to].string = w->genTermEm.InputArgs[from].string;

 return(TRANSOKAY);
}

/* GtEGetLastButtonEvent:  This translator returns the information in the */
/*  stored last button event.  It returns the button that was pressed, the */
/*  x and y positions and the modifiers that were active. */

static int GtEGetLastButtonEvent(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int ButtonPos = ArgToInt(w,args,1,1);
 int XPos = ArgToInt(w,args,2,2);
 int YPos = ArgToInt(w,args,3,3);
 int ModPos = ArgToInt(w,args,4,4);

 if((w->genTermEm.LastEvent.type != ButtonPress) && 
    (w->genTermEm.LastEvent.type != ButtonRelease))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Last event is not a button event");
   return(TRANSERROR);
  }
 
 IntToInputArg(w,ButtonPos,w->genTermEm.LastEvent.xbutton.button);
 IntToInputArg(w,XPos,w->genTermEm.LastEvent.xbutton.x);
 IntToInputArg(w,YPos,w->genTermEm.LastEvent.xbutton.y);
 IntToInputArg(w,ModPos,w->genTermEm.LastEvent.xbutton.state);

 return(TRANSOKAY);
}

/* GtEToAscii:  This translator takes an integer and converts it to its */
/*  ascii equivalent. */

static int GtEToAscii(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int num = ArgToInt(w,args,1,0);
 int Pos = ArgToInt(w,args,2,1);
 char buff[2];

 if((num < 0) || (num >= 256))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Value can not be converted to ascii");
   return(TRANSERROR);
  }
 
 buff[0] = (char) num;
 buff[1] = NULL;
 
 StringToInputArg(w,Pos,buff,1);
 
 return(TRANSOKAY);
}

/* GtEConvertPosition:  This translator takes a pixel position (x,y) and */
/*  converts it to the corresponding row and column number. */

static int GtEConvertPosition(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int X = ArgToInt(w,args,1,0);
 int Y = ArgToInt(w,args,2,0);
 int RowPos = ArgToInt(w,args,3,1);
 int ColPos = ArgToInt(w,args,4,2);
 int Row,Col;

 
 GtPositionToRowColumn(w,(Dimension)X,(Dimension)Y,&Row,&Col);
 IntToInputArg(w,RowPos,Row);
 IntToInputArg(w,ColPos,Col);

 return(TRANSOKAY);
}

/* GtECheckModifiers:  This translator takes an event modifier and */
/*  if a specified modifier was present during the event.  The first */
/*  parameter is the value of the modifier (set GtEGetLastButtonEvent).  The */
/*  second parameter is the modifier to check for, either Shift Control or */
/*  Meta.  The final parameter is the position to return the answer in */

static int GtECheckModifiers(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int mods = ArgToInt(w,args,1,0);
 int pos = ArgToInt(w,args,3,1);
 char string[100];
 int i = 0;
 int val = 0;

 ArgToString(w,args,2," ",string,99);

 while((w->genTermEm.Mods[i].Name != NULL) && 
       (strcmp(w->genTermEm.Mods[i].Name,string) != 0))
  i++;
 if(w->genTermEm.Mods[i].Name == NULL)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Invalid modifier name");
   return(TRANSERROR);
  }
 
 if(mods & w->genTermEm.Mods[i].Mask)
  val = 1;

 IntToInputArg(w,pos,val);

 return(TRANSOKAY);
}

/* GtEGetStringLength:  This translator determines the length of the string */
/* given as the first parameter and returns it in the parameter given by */
/* the second argument */

static int GtEGetStringLength(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int pos = ArgToInt(w,args,2,1);
 int n;
 char string[100];

 ArgToString(w,args,1," ",string,99);
 n = strlen(string);
 IntToInputArg(w,pos,n);

 return(TRANSOKAY);
}

/* GtEGetSubString:  This translator gets the contents of the substring of */
/*  the string in the first parameter with in the bounds of the substring */
/*  given by the second and third argument.  The result is returned in the */
/*  parameter specified by the fourth argument. */

static int GtEGetSubString(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int start = ArgToInt(w,args,2,0);
 int end = ArgToInt(w,args,3,1);
 int pos = ArgToInt(w,args,4,1);
 char string[100];
 int n;
 int len;

 ArgToString(w,args,1," ",string,99);
 n = strlen(string);

 if((n < start) || (start < 0) || (end < 0))
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Invalid substring specified in GetSubString");
   return(TRANSERROR);
  }
 if(end > n)
  end = n;
 
 len = (end - start);
 StringToInputArg(w,pos,&(string[start]),len);
 return(TRANSOKAY);
}

/* GtEIntToString:  This translator performs an explicit integer to string */
/* conversion.  The first argument is the number of convert.  The second */
/* argument is the number of characters in the final string and the final */
/* argument is where to store the result */

static int GtEIntToString(w,args)

GenTermEmWidget w;
struct ArgumentList *args;

{
 int n = ArgToInt(w,args,1,0);
 int len = ArgToInt(w,args,2,1);
 int pos = ArgToInt(w,args,3,1);
 char buffer[20];
 char string[20]; 
 int i,size,diff;

 if(len <= 0)
  {
   XtAppWarning(XtWidgetToApplicationContext(w),
		"GenTermEm Widget: Invalid string length in IntToString");
   return(TRANSERROR);
  }

 GtEIntToStringConvert(n,buffer);
 size = strlen(buffer);
 
 if(size < len)
  {
   diff = len - size;
   for(i = 0; i < diff; i++)
    string[i] = '0';
   memcpy(&(string[diff]),buffer,size);
  }
 else if(size > len)
  {
   memcpy(string,&(buffer[size-len]),len);
  }
 else
  memcpy(string,buffer,len);

 StringToInputArg(w,pos,string,len);
 return(TRANSOKAY);
}

/* GtESetFlow:  This translators envokes the flow callback so that the */
/*  parent widget knows that the underlying application has asserted flow */
/*  control.  It asserts an XOFF passed argument is a 0 and sends an */
/*  XON otherwise */

static int GtESetFlow(w,args)

GenTermEmWidget w;
struct ArgumentList args;

{
 int flow = ArgToInt(w,args,1,1);
 GenTermEmCallback reason;

 if(flow == 0)
  {
   reason.reason = GTE_XOFF;
  }
 else
  {
   reason.reason = GTE_XON;
  }
  XtCallCallbacks(w,XtNflowCallback,(caddr_t) &reason);
 return(TRANSOKAY);
}
@EOF
set `wc -lwc <GenTerm/Parse.c`
if test $1$2$3 != 2734773667395
then
	echo ERROR: wc results of GenTerm/Parse.c are $* should be 2734 7736 67395
fi

chmod 644 GenTerm/Parse.c

echo x - GenTerm/Pty.c
cat >GenTerm/Pty.c <<'@EOF'
/* Pty.c -- A Pty managment widget */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <bsdtty.h>
#include <sys/pty.h>
#include <sys/errno.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <X11/Xatom.h>
#include "PtyP.h"
#include "Pty.h"

#define True 1
#define False 0
char *GetNextWord();

extern GenTermEmClassRec genTermEmClassRec;

static struct TtyMode TtyModes[] = 
{
 {"parenb",True,TTYCMODE,TTYLATER,PARENB},
 {"parodd",True,TTYCMODE,TTYLATER,PARODD},
 {"cs5",False,TTYCMODE,TTYLATER,CS5},
 {"cs6",False,TTYCMODE,TTYLATER,CS6},
 {"cs7",False,TTYCMODE,TTYLATER,CS7},
 {"cs8",False,TTYCMODE,TTYLATER,CS8},
 {"0",False,TTYSPEED,TTYNOW,B0},
 {"50",False,TTYSPEED,TTYNOW,B50},
 {"75",False,TTYSPEED,TTYNOW,B75},
 {"110",False,TTYSPEED,TTYNOW,B110},
 {"134.5",False,TTYSPEED,TTYNOW,B134},
 {"150",False,TTYSPEED,TTYNOW,B150},
 {"200",False,TTYSPEED,TTYNOW,B200},
 {"300",False,TTYSPEED,TTYNOW,B300},
 {"600",False,TTYSPEED,TTYNOW,B600},
 {"900",False,TTYSPEED,TTYNOW,B900},
 {"1200",False,TTYSPEED,TTYNOW,B1200},
 {"1800",False,TTYSPEED,TTYNOW,B1800},
 {"2400",False,TTYSPEED,TTYNOW,B2400},
 {"3600",False,TTYSPEED,TTYNOW,B3600},
 {"4800",False,TTYSPEED,TTYNOW,B4800},
 {"7200",False,TTYSPEED,TTYNOW,B7200},
 {"9600",False,TTYSPEED,TTYNOW,B9600},
 {"19200",False,TTYSPEED,TTYNOW,B19200},
 {"38400",False,TTYSPEED,TTYNOW,B38400},
 {"exta",False,TTYCMODE,TTYNOW,EXTA},
 {"extb",False,TTYCMODE,TTYNOW,EXTB},
 {"hupcl",True,TTYCMODE,TTYLATER,HUPCL},
 {"hup",True,TTYCMODE,TTYLATER,HUPCL},
 {"cstopb",True,TTYCMODE,TTYLATER,CSTOPB},
 {"cread",True,TTYCMODE,TTYLATER,CREAD},
 {"clocal",True,TTYCMODE,TTYLATER,CLOCAL},
 {"loblk",True,TTYCMODE,TTYLATER,LOBLK},
 {"ignbrk",True,TTYIMODE,TTYLATER,IGNBRK},
 {"ienqak",True,TTYIMODE,TTYLATER,IENQAK},
 {"brkint",True,TTYIMODE,TTYLATER,BRKINT},
 {"ignpar",True,TTYIMODE,TTYLATER,IGNPAR},
 {"parmrk",True,TTYIMODE,TTYLATER,PARMRK},
 {"inpck",True,TTYIMODE,TTYLATER,INPCK},
 {"istrip",True,TTYIMODE,TTYLATER,ISTRIP},
 {"inlcr",True,TTYIMODE,TTYLATER,INLCR},
 {"igncr",True,TTYIMODE,TTYLATER,IGNCR},
 {"icrnl",True,TTYIMODE,TTYLATER,ICRNL},
 {"iuclc",True,TTYIMODE,TTYLATER,IUCLC},
 {"ixon",True,TTYIMODE,TTYLATER,IXON},
 {"ixany",True,TTYIMODE,TTYLATER,IXANY},
 {"ixoff",True,TTYIMODE,TTYLATER,IXOFF},
 {"opost",True,TTYOMODE,TTYLATER,OPOST},
 {"olcuc",True,TTYOMODE,TTYLATER,OLCUC},
 {"onlcr",True,TTYOMODE,TTYLATER,ONLCR},
 {"ocrnl",True,TTYOMODE,TTYLATER,OCRNL},
 {"onocr",True,TTYOMODE,TTYLATER,ONOCR},
 {"onlret",True,TTYOMODE,TTYLATER,ONLRET},
 {"ofill",True,TTYOMODE,TTYLATER,OFILL},
 {"ofdel",True,TTYOMODE,TTYLATER,OFDEL},
 {"cr0",False,TTYOMODE,TTYLATER,CR0},
 {"cr1",False,TTYOMODE,TTYLATER,CR1},
 {"cr2",False,TTYOMODE,TTYLATER,CR2},
 {"cr3",False,TTYOMODE,TTYLATER,CR3},
 {"nl0",False,TTYOMODE,TTYLATER,NL0},
 {"nl1",False,TTYOMODE,TTYLATER,NL1},
 {"tab0",False,TTYOMODE,TTYLATER,TAB0},
 {"tab1",False,TTYOMODE,TTYLATER,TAB1},
 {"tab2",False,TTYOMODE,TTYLATER,TAB2},
 {"tab3",False,TTYOMODE,TTYLATER,TAB3},
 {"bs0",False,TTYOMODE,TTYLATER,BS0},
 {"bs1",False,TTYOMODE,TTYLATER,BS1},
 {"ff0",False,TTYOMODE,TTYLATER,FF0},
 {"ff1",False,TTYOMODE,TTYLATER,FF1},
 {"vt0",False,TTYOMODE,TTYLATER,VT0},
 {"vt1",False,TTYOMODE,TTYLATER,VT1},
 {"isig",True,TTYLMODE,TTYLATER,ISIG},
 {"icanon",True,TTYLMODE,TTYLATER,ICANON},
 {"iexten",True,TTYLMODE,TTYLATER,IEXTEN},
 {"xcase",True,TTYLMODE,TTYLATER,XCASE},
 {"echo",True,TTYLMODE,TTYLATER,ECHO},
 {"echoe",True,TTYLMODE,TTYLATER,ECHOE},
 {"echok",True,TTYLMODE,TTYLATER,ECHOK},
 {"lfkc",True,TTYLMODE,TTYLATER,ECHOK},
 {"echonl",True,TTYLMODE,TTYLATER,ECHONL},
 {"noflsh",True,TTYLMODE,TTYLATER,NOFLSH},
 {"tostop",True,TTYLMODE,TTYLATER,TOSTOP},
 {"erase",False,TTYCCHAR,TTYLATER,VERASE},
 {"kill",False,TTYCCHAR,TTYLATER,VKILL},
 {"intr",False,TTYCCHAR,TTYLATER,VINTR},
 {"quit",False,TTYCCHAR,TTYLATER,VQUIT},
 {"eof",False,TTYCCHAR,TTYLATER,VEOF},
 {"eol",False,TTYCCHAR,TTYLATER,VEOL},
 {"min",False,TTYCCHAR,TTYLATER,VMIN},
 {"time",False,TTYCCHAR,TTYLATER,VTIME},
 {"susp",False,TTYCCHAR,TTYLATER,VSUSP},
 {"dsusp",False,TTYCCHAR,TTYLATER,VSUSP},
 {"swtch",False,TTYCCHAR,TTYLATER,VSWTCH},
 {"stop",False,TTYCCHAR,TTYLATER,VSTOP},
 {"start",False,TTYCCHAR,TTYLATER,VSTART},
 {"rows",False,TTYSIZE,TTYNOW,TTYROW},
 {"columns",False,TTYSIZE,TTYNOW,TTYCOLUMN},
 {NULL,NULL,NULL,NULL,NULL}
};

static char *BaseMaster = "/dev/pty";
static char *BaseSlave = "/dev/tty";
static char *Offset = "pqr";
static char *Index =  "0123456789abcdef";

static void PtyInitialize();
static void PtyRealize();
static void PtyResize();
static Boolean PtySetValues();
static void PtyDestroy();
static void PtyExceptionCB();
static void PtyDoPtyCallbacks();
static void PtyWriteCB();
static void PtyWriteAction();
static void PtySetModeAction();

static XtResource resources[] = {
 {XtNmasterPtyName,XtCMasterPtyName,XtRString,sizeof(char *),
   XtOffset(PtyWidget,pty.MasterPtyName),XtRString,""},
 {XtNslavePtyName,XtCSlavePtyName,XtRString,sizeof(char *),
   XtOffset(PtyWidget,pty.SlavePtyName),XtRString,""},
 {XtNmasterPtyDescriptor,XtCMasterPtyDescriptor,XtRInt,sizeof(int),
   XtOffset(PtyWidget,pty.MasterDescriptor),XtRImmediate,(caddr_t)-1},
 {XtNslavePtyDescriptor,XtCSlavePtyDescriptor,XtRInt,sizeof(int),
   XtOffset(PtyWidget,pty.SlaveDescriptor),XtRImmediate,(caddr_t)-1},
 {XtNmasterPtyOpenMode,XtCMasterPtyOpenMode,XtRInt,sizeof(int),
   XtOffset(PtyWidget,pty.MasterPtyOpenModes),XtRImmediate,
   (caddr_t)(O_RDWR | O_NDELAY)},
 {XtNslavePtyOpenMode,XtCSlavePtyOpenMode,XtRInt,sizeof(int),
   XtOffset(PtyWidget,pty.SlavePtyOpenModes),XtRImmediate,(caddr_t)O_RDWR},
 {XtNttyMode,XtCTtyMode,XtRString,sizeof(char *),
   XtOffset(PtyWidget,pty.TtyModes),XtRString,"-icanon min 1"},
 {XtNptyCallback,XtCPtyCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(PtyWidget,pty.PtyCallbacks),XtRCallback,NULL},
};

static XtActionsRec actions[] =
{
 {"ptywrite",PtyWriteAction},
 {"ptysetmode",PtySetModeAction},
};

PtyClassRec ptyClassRec =
{
 
 {  /* core fields */
    /* superclass               */      (WidgetClass) &genTermEmClassRec,
    /* class_name               */      "Pty",
    /* widget_size              */      sizeof(PtyRec),
    /* class_initialize         */      NULL,
    /* class_part_initialize    */      NULL,
    /* class_inited             */      FALSE,
    /* initialize               */      PtyInitialize,
    /* initialize_hook          */      NULL,
    /* realize                  */      PtyRealize,
    /* actions                  */      actions,
    /* num_actions              */      XtNumber(actions),
    /* resources                */      resources,
    /* num_resources            */      XtNumber(resources),
    /* xrm_class                */      NULLQUARK,
    /* compress_motion          */      TRUE,
    /* compress_exposure        */      FALSE,
    /* compress_enterleave      */      TRUE,
    /* visible_interest         */      FALSE,
    /* destroy                  */      PtyDestroy,
    /* resize                   */      PtyResize,
    /* expose                   */      XtInheritExpose,
    /* set_values               */      PtySetValues,
    /* set_values_hook          */      NULL,
    /* set_values_almost        */      XtInheritSetValuesAlmost,
    /* get_values_hook          */      NULL,
    /* accept_focus             */      XtInheritAcceptFocus,
    /* version                  */      XtVersion,
    /* callback_private         */      NULL,
    /* tm_table                 */      XtInheritTranslations,
    /* query_geometry           */      XtInheritQueryGeometry,
    /* display_accelerator      */      XtInheritDisplayAccelerator,
    /* extension                */      NULL
  },
     { /* composite_class fields */
    /* geometry_manager   */   XtInheritGeometryManager,
    /* change_managed     */   XtInheritChangeManaged,
    /* insert_child       */   XtInheritInsertChild,
    /* delete_child       */   XtInheritDeleteChild,
    /* extension          */   NULL
  },
     { NULL},
     { NULL},
 
};

WidgetClass ptyWidgetClass = (WidgetClass) &ptyClassRec;

/* PtyInitialize:  This is the initialization method for the widget.  Right */
/*  now it is a no-op.  All the real work is done in the realize method. */

static void PtyInitialize(request,new)

PtyWidget request,new;

{
 new->pty.StartChar = 021;   /* control Q */
 new->pty.StartAny = False;
 new->pty.FlowEnabled = True;
 new->pty.WriteEnabled = False;
 new->pty.NumStore = 0;
 new->pty.StoreSize = 20;
 new->pty.Storage = (char *) XtMalloc(sizeof(char) * new->pty.StoreSize);
};

/* PtyRealize:  This is the realize method for the widget.  It opens the Pty */
/*  makes sure it has the correct modes and sets up all the handling routines*/

static void PtyRealize(w,valueMask,attributes)

PtyWidget w;
XtValueMask *valueMask;
XSetWindowAttributes *attributes;

{
 Arg args[20];
 int n = 0;
 WidgetClass superclass;
 char *Names[2];

 superclass = (WidgetClass)genTermEmWidgetClass;
 (*superclass->core_class.realize)(w,valueMask,attributes);

 OpenPty(&(w->pty.MasterDescriptor),&(w->pty.SlaveDescriptor),
	 w->pty.MasterPtyOpenModes,w->pty.SlavePtyOpenModes,Names);

 if((w->pty.MasterDescriptor == -1) || (w->pty.SlaveDescriptor == -1))
  {
   XtAppError(XtWidgetToApplicationContext(w),
	      "Pty Widget can not open an pty!");
  }
 
 w->pty.MasterPtyName = Names[0];
 w->pty.SlavePtyName = Names[1];

 SetPtyMode(w->pty.MasterDescriptor,w->pty.TtyModes);

 XtSetArg(args[n],XtNoutputFile,w->pty.MasterDescriptor); n++;
 XtSetValues(w,args,n);

 w->pty.ExceptId = XtAppAddInput(XtWidgetToApplicationContext(w),
				 w->pty.MasterDescriptor,XtInputExceptMask,
				 PtyExceptionCB,(XtPointer)w);
 n = 1;
 ioctl(w->pty.MasterDescriptor,TIOCMONITOR,&n);
 ioctl(w->pty.MasterDescriptor,TIOCTRAP,&n);

 PtyDoPtyCallbacks(w,PTY_OPEN,NULL);
}

/* PtyResize:  This is the resize method for the widget.  It first calls the */
/*  superclass's resize method and then does the ioctl on the pty to inform */
/*  the underlying application that the window size changed. */

static void PtyResize(w)

PtyWidget w;

{
 Arg args[10];
 int n = 0;
 int row,col;
 char mode[80];
 WidgetClass superclass = (WidgetClass)genTermEmWidgetClass;

 (*superclass->core_class.resize)(w);
 
 XtSetArg(args[n],XtNrows,&row); n++;
 XtSetArg(args[n],XtNcolumns,&col); n++;
 XtGetValues(w,args,n);

 sprintf(mode,"rows %d columns %d",row,col);
 SetPtyMode(w->pty.MasterDescriptor,mode);
}

/* PtySetValues:  This is the set values method for the widget.  Most values */
/*  for this widget can not be set after initialization.  This function will */
/*  detect this, correct the value and return an error. */

static Boolean PtySetValues(current,request,new)

PtyWidget current,request,new;
{
 int Error = False;

 if((current->pty.TtyModes != new->pty.TtyModes) &&
    (strcmp(current->pty.TtyModes,new->pty.TtyModes) != 0) &&
    (XtIsRealized(new)))
  {
   SetPtyMode(new->pty.MasterDescriptor,new->pty.TtyModes);
  }
 if((current->pty.MasterPtyOpenModes != new->pty.MasterPtyOpenModes) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.MasterPtyOpenModes = current->pty.MasterPtyOpenModes;
  }
 if((current->pty.SlavePtyOpenModes != new->pty.SlavePtyOpenModes) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.SlavePtyOpenModes = current->pty.SlavePtyOpenModes;
  }
 if((current->pty.MasterPtyName != new->pty.MasterPtyName) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.MasterPtyName = current->pty.MasterPtyName;
  }
 if((current->pty.SlavePtyName != new->pty.SlavePtyName) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.SlavePtyName = current->pty.SlavePtyName;
  }
 if((current->pty.MasterDescriptor != new->pty.MasterDescriptor) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.MasterDescriptor = current->pty.MasterDescriptor;
  }
 if((current->pty.SlaveDescriptor != new->pty.SlaveDescriptor) &&
    (XtIsRealized(new)))
  {
   Error = True;
   new->pty.SlaveDescriptor = current->pty.SlaveDescriptor;
  }

 if(Error)
  XtAppWarning(XtWidgetToApplicationContext(new),
	       "Attempt to set a read only resource in Pty widget");
 return(False);
}

/* PtyDestroy:  This is the pty destroy method for the widget.  It frees up */
/*  all allocated memory and removes any input handlers. */

static void PtyDestroy(w)

PtyWidget w;

{
 XtRemoveInput(w->pty.ExceptId);
 if(w->pty.WriteEnabled)
  XtRemoveInput(w->pty.OutputId);
 close(w->pty.MasterDescriptor);
 close(w->pty.SlaveDescriptor);
 XtFree(w->pty.MasterPtyName);
 XtFree(w->pty.SlavePtyName);
 XtFree(w->pty.Storage);
}

/* PtyExceptionCB:  This is the input exception handler for the widget.  It */
/*  is used to monitor the changes to the pty the underlying processes is */
/*  requesting.  This is done so we can handle flow control properly and to */
/*  determine if there even is a process attatched to us. */

static void PtyExceptionCB(client,source,id)

XtPointer client;
int *source;
XtInputId *id;

{
 PtyWidget w = (PtyWidget) client;
 struct request_info request;
 char c;
 int size;
 union buffer
  {
   struct termios termios;
   struct ltchars ltchars;
#ifdef TIOCGWINSZ
   struct winsize winsize;
#endif
   long value;
  } argument;

/* first we complete the Pty Monitor handshake */

 if(ioctl(w->pty.MasterDescriptor,TIOCREQCHECK,&request) != EINVAL)
  {
   switch(request.request)
    {
   case TIOCOPEN:
     PtyDoPtyCallbacks(w,PTY_SLAVEOPEN,NULL);
     break;
   case TIOCCLOSE:
     PtyDoPtyCallbacks(w,PTY_SLAVECLOSE,NULL);
     break;
   default:
     break;
    }
   if(request.argget != 0)
    ioctl(w->pty.MasterDescriptor,request.argget,&argument);
   if(request.argset != 0)
    ioctl(w->pty.MasterDescriptor,request.argset,&argument);
   request.return_value = 0;
   ioctl(w->pty.MasterDescriptor,TIOCREQSET,&request);

/* we have now completed the handshake so let's look at what changed */
   
   tcgetattr(w->pty.MasterDescriptor,&argument);

   w->pty.StartChar = argument.termios.c_cc[VSTART];
   
   if((argument.termios.c_iflag & IXANY) &&
      (argument.termios.c_lflag & IEXTEN))
    w->pty.StartAny = True;
   else
    w->pty.StartAny = False;
   if(argument.termios.c_iflag & IXOFF)
    w->pty.FlowEnabled = True;
   else
    w->pty.FlowEnabled = False;

/* finally tell application program about changes */
  
   PtyDoPtyCallbacks(w,PTY_IOCTL,&(argument.termios));
  }
}

/* PtyDoPtyCallbacks:  This function envokes the PtyCallback.  It allocates */
/*  the callback structures and executes the callback. */

static void PtyDoPtyCallbacks(w,why,term)

PtyWidget w;
int why;
struct termios *term;

{
 PtyCallback reason;

 reason.reason = why;
 reason.MasterPtyDescriptor = w->pty.MasterDescriptor;
 reason.SlavePtyDescriptor = w->pty.SlaveDescriptor;
 reason.Termios = term;
 XtCallCallbacks(w,XtNptyCallback,(caddr_t)&reason);
}

/* PtyWrite:  This is the input routine to the widget.  It allows the calling*/
/*  application to write data to the pty with out fear of blocking.  It */
/*  handles all necessary flow control. */

PtyWrite(w,string,len)

PtyWidget w;
char *string;
int len;

{
 int i;

 if(len + w->pty.NumStore >= w->pty.StoreSize)
  {
   w->pty.StoreSize = (len + w->pty.NumStore) * 2;
   w->pty.Storage = (char *) XtRealloc(w->pty.Storage,
				       sizeof(char)*w->pty.StoreSize);
  }

 memcpy(&(w->pty.Storage[w->pty.NumStore]),string,len);
 w->pty.NumStore += len;

 if(w->pty.FlowEnabled)
  {
   if(w->pty.StartAny)
    tcflow(w->pty.MasterDescriptor,TCOON);
   else
    for(i = 0; i < len; i++)
     if(string[i] == w->pty.StartChar)
      tcflow(w->pty.MasterDescriptor,TCOON);
  }

 if(w->pty.WriteEnabled == False)
  {
   w->pty.OutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
				  w->pty.MasterDescriptor,XtInputWriteMask,
				  PtyWriteCB,(XtPointer)w);
   w->pty.WriteEnabled = True;
  }
}

/* PtyWriteCB:  This is the write event handler.  It is called when ever the */
/*  the pty is ready to write more data and there is data to be sent to it. */

static void PtyWriteCB(client,source,id)

XtPointer client;
int *source;
XtInputId *id;

{
 PtyWidget w = (PtyWidget)client;
 int n;
 int start = 0;

 while((w->pty.NumStore > 0) && ((n = write(w->pty.MasterDescriptor,
					    &(w->pty.Storage[start]),
					    w->pty.NumStore)) > 0))
  {
   w->pty.NumStore -= n;
   start += n;
  }
 
 if(w->pty.NumStore != 0)
  {
   for(n = 0; n < w->pty.NumStore; n++)
    w->pty.Storage[n] = w->pty.Storage[start + n];
  }
 else
  {
   XtRemoveInput(w->pty.OutputId);
   w->pty.WriteEnabled = False;
  }
}

/* PtyWriteAction:  This is the write action handler for the widget.  It */
/*  simply sends all the strings to the pty. */

static void PtyWriteAction(w,event,strings,num)

PtyWidget w;
XEvent *event;
char *strings[];
Cardinal *num;

{
 int i;
 
 for(i = 0; i < *num; i++)
  PtyWrite(w,strings[i],strlen(strings[i]));
}

/* PtySetModeAction:  Thisis the set mode action handler for the widget.  It */
/*  sets the tty mode of the master pty to the values given in the first */
/*  string. */

static void PtySetModeAction(w,event,strings,num)

PtyWidget w;
XEvent *event;
char *strings[];
Cardinal *num;

{
 if(*num > 0)
  SetPtyMode(w->pty.MasterDescriptor,strings[0]);
}

/* PtySignal:  This function sends a signal to the process group associated */
/*  with the slave side of the Pty. */

void PtySignal(w,Sig)

PtyWidget w;
int Sig;

{
 ioctl(w->pty.MasterDescriptor,TIOCSIGSEND,Sig);
}

OpenPty(master,slave,master_mode,slave_mode,names)

int *master;
int *slave;
int master_mode;
int slave_mode;
char *names[2];

{
 char Filename[80];
 int i,j;
 int offsize,indexsize;
 int basesize;

 offsize = strlen(Offset);
 indexsize = strlen(Index);
 basesize = strlen(BaseMaster) - 1;
 strcpy(Filename,BaseMaster);
 Filename[basesize+3] = NULL;
 *master = *slave = -1;

 for(i = 0; i <= offsize; i++)
  for(j = 0; j <= indexsize;j++)
   {
    Filename[basesize+1] = Offset[i];
    Filename[basesize+2] = Index[j];
    if((*master = open(Filename,master_mode)) >= 0)
     {
      names[0] = XtMalloc(sizeof(char)*(strlen(Filename) + 1));
      strcpy(names[0],Filename);
      strcpy(Filename,BaseSlave);
      basesize = strlen(BaseSlave) - 1;
      Filename[basesize+1] = Offset[i];
      Filename[basesize+2] = Index[j];
      Filename[basesize+3] = NULL;
      if((*slave = open(Filename,slave_mode)) < 0)
       {
        fprintf(stderr,"Error can not open slave pty %s\n",Filename);
        close(*master);
        *master = *slave = -1;
	strcpy(Filename,BaseMaster);
       }
      else
       {
	names[1] = XtMalloc(sizeof(char)*(strlen(Filename) + 1));
	strcpy(names[1],Filename);
	return;
       }
     }
   }
}

SetPtyMode(fd,ModeList)

int fd;
char *ModeList;

{
 int i = 0;
 char name[1024];
 int which;
 char arg;
 struct termios buf;
#ifdef TIOCGWINSZ
 struct winsize size;
#endif
 int invert;

 if(tcgetattr(fd,&buf) != 0)
  {
   perror("SetPtyMode");
   return(-1);
  }
#ifdef TIOCGWINSZ
 if(ioctl(fd,TIOCGWINSZ,&size) != 0)
  {
   perror("SetPtyMode");
   return(-1);
  }
#endif

 while(*ModeList != NULL)
  {
   ModeList = GetNextWord(ModeList,name,&invert,True);
   i = 0;
   which = -1;
   
   while(TtyModes[i].Name != NULL)
    {
     if(strcmp(TtyModes[i].Name,name) == 0)
      {
       which = i;
       break;
      }
     i++;
    }
   if(which == -1)
    {
     fprintf(stderr,"Bad tty mode %s\n",name);
     return(-1);
    }
   if((invert == 1) && (TtyModes[i].Invertable == False))
    {
     fprintf(stderr,"%s can not be complimented\n",name);
     return(-1);
    }
   switch(TtyModes[which].Type)
    {
   case TTYIMODE:
     SetMode(&buf.c_iflag,TtyModes[which].Mask,invert);
     break;
   case TTYOMODE:
     SetMode(&buf.c_oflag,TtyModes[which].Mask,invert);
     break;
   case TTYCMODE:
     SetMode(&buf.c_cflag,TtyModes[which].Mask,invert);
     break;
   case TTYLMODE:
     SetMode(&buf.c_lflag,TtyModes[which].Mask,invert);
     break;
   case TTYSPEED:
     cfsetospeed(&buf,TtyModes[which].Mask);
     cfsetispeed(&buf,TtyModes[which].Mask);
     break;
   case TTYSIZE:
     ModeList = GetNextWord(ModeList,name,&invert,False);
#ifdef TIOCGWINSZ
     if(TtyModes[which].Mask == TTYROW)
      size.ws_row = atoi(name);
     else
      size.ws_col = atoi(name);
#endif
     break;
   case TTYCCHAR:
     ModeList = GetNextWord(ModeList,name,&invert,False);
     if((TtyModes[which].Mask == VMIN) || (TtyModes[which].Mask == VTIME))
      {
       buf.c_cc[TtyModes[which].Mask] = atoi(name);
      }
     else
      {
       if(name[0] = '^')
	{
	 if(strlen(name) != 2)
	  {
	   fprintf(stderr,"%s is an invalid keyword\n",name);
	   return(-1);
	  }
	 if(islower(name[1]))
	  buf.c_cc[TtyModes[which].Mask] = toupper(name[1]) & 077;
	 else
	  buf.c_cc[TtyModes[which].Mask] = name[1] & 077;
	}
       else
	{
	 if(strlen(name) != 1)
	  {
	   fprintf(stderr,"%s is an invalid keyword\n",name);
	   return(-1);
	  }
	 buf.c_cc[TtyModes[which].Mask] = name[0];
	}
      }
     break;
    }
   if(TtyModes[which].When == TTYNOW)
    {
     if(tcsetattr(fd,TCSANOW,&buf))
      {
       perror("SetPtyMode");
       return(-1);
      }
#ifdef TIOCSWINSZ
     if(ioctl(fd,TIOCSWINSZ,&size))
      {
       perror("SetPtyMode");
       return(-1);
      }
#endif
     if(tcgetattr(fd,&buf))
      {
       perror("SetPtyMode");
       return(-1);
      }
#ifdef TIOCGWINSZ
     if(ioctl(fd,TIOCGWINSZ,&size))
      {
       perror("SetPtyMode");
       return(-1);
      }
#endif
    }
  }
 if(tcsetattr(fd,TCSANOW,&buf))
  {
   perror("SetPtyMode");
   return(-1);
  }
#ifdef TIOCSWINSZ
 if(ioctl(fd,TIOCSWINSZ,&size))
  {
   perror("SetPtyMode");
   return(-1);
  }
#endif
 return(0);
}



SetMode(mode,mask,invert)

tcflag_t *mode;
tcflag_t mask;
int invert;

{
 if(invert)
  *mode &= ~mask;
 else
  *mode |= mask;
}

char *GetNextWord(List,name,invert,flag)

char *List;
char *name;
int *invert;
int flag;

{
 *invert = False;

 while((*List != NULL) && (*List == ' '))
  List++;

 if(flag)
  {
   if(*List == '-')
    {
     *invert = True;
     List++;
    }
  }
 while((*List != NULL) && (*List != ' '))
  *(name++) = *(List++);
 *name = NULL;
 return(List);
}
@EOF
set `wc -lwc <GenTerm/Pty.c`
if test $1$2$3 != 853192422746
then
	echo ERROR: wc results of GenTerm/Pty.c are $* should be 853 1924 22746
fi

chmod 644 GenTerm/Pty.c

echo x - GenTerm/Pty.man
sed 's/^@//' >GenTerm/Pty.man <<'@EOF'
@.\" Man page for the GenTermEm Widget -*-nroff-*-
@.\"
@.\"  Written by G. Strachan 1992
@.\"
@.de KS  \"      Keep start
@.br
@.in 0
@.di KP
@..
@.de KE  \"      Keep end
@.br
@.di
@.ne \\n(dnu
@.nr fI \\n(.u
@.nf
@.KP
@.if \\n(fI .fi
@.in
@..
@.TH Pty 3X
@.SH NAME
\fBPty \- The Pty widget class.\fP
@.sp 1
@.SH SYNOPSIS
\fB#include "/usr/local/include/Pty.h"\fP
@.SH DESCRIPTION
The \fBPty\fP widget is a pty management and terminal emulator widget.
In inherits all
capabilities and resource of the \fBGenTermEm\fP widget and adds
management capabilities specific to handling pty's  The widget will
allocate and initialize pty's for the application code.  In addition,
the widget will handle all pty flow control and blocking.  Finally,
the widget has been constructed in such a manner that it will not
deadlock if the application is reading and writing from the same pty.
After finding and allocating the pty, the widget will set its line
discipline properly and then control the master side of the pty.  Any
data written to the slave side of the pty will be displayed in the
terminal emulator widget's window.  Any data entered from the keyboard
into the widget will be written to the master side of the pty and can
be read from the slave side.  In addition, the widget performs some
monitoring of the pty and can inform the application of changes in
line discipline and when processes attach and detach themselves from
the slave pty.  Finally, on system which support \fISIGWINCH\fP, the
widget will automatically inform process attached to the slave pty
about changes in the widget's dimensions.
@.SH CLASSES
\fBPty\fP inherits behavior and resources from \fBGenTermEm\fP,
\fBGenTerm\fP, \fBCore\fP and \fBComposite\fP classes.
@.PP
The class pointer it \fBptyWidgetClass\fP
@.PP
The class name is \fBPty\fP
@.SH "NEW RESOURCES"
The following table lists the resources recognized by the \fBPty\fP
widget.  The programmer can also set the resource of the inherited
classes.  To set these resources in the resource database, remove the
\fBXtN\fP and \fBXtC\fp prefixes to the resource names.
@.sp 1
@.KS
@.sp 1
@.TS
center;
cB sss
lB lB lB lB
l l l l.
Pty Resource Set
Name	Class	Type	Default
_
XtNmasterPtyDescriptor	XtCMasterPtyDescriptor	Int	Dynamic
XtNmasterPtyName	XtCMasterPtyName	String	Dynamic
XtNmasterPtyOpenMode	XtCMasterPtyOpenMode	Int	O_RDWR | O_NDELAY
XtNptyCallback	XtCPtyCallback	Callback	NULL
XtNslavePtyDescriptor	XtCSlavePtyDescriptor	Int	Dynamic
XtNslavePtyName	XtCSlavePtyName	String	Dynamic
XtNslavePtyOpenMode	XtCSlavePtyOpenMode	Int	O_RDWR
XtNttyMode	XtCTtyMode	String	"-icanon min 1"
@.TE
@.KE
@.sp 1
@.IP \fBXtNmasterPtyDescriptor\fP
This read only resource will contain the file descriptor associated
with the master side of the pty after the widget has been realized and has
issued its first pty callback.
@.IP \fBXtNmasterPtyName\fP
This read only resource will contain the complete path name of the
master side if the pty after the widget has been realized and has
issued its first pty callback.
@.IP \fBXtNmasterPtyOpenMode\fP
This resource specifies the modes to use when opening the master side
of the pty.  See man (2) open for details on the values to specify.
This resource can not be changed after the widget has been realized.
@.IP \fBXtNptyCallback\fP
This resource specifies the list of callbacks to call when ever the widget
asserts a pty callback.  These callbacks are generated when ever the
widget first opens the pty or when ever an exception is pending on the
master side of the pty.  The callback will be passed the reason for
the callback.
@.IP \fBXtNslavePtyDescriptor\fP
This read only resource will contain the file descriptor associated
with the slave side of the pty after the widget has been realized and
has issued its first pty callback.
@.IP \fBXtNslavePtyName\fP
This read only resource will contain the complete path name of the
slave side of the pty after the widget has been realized and has
issued it first pty callback.
@.IP \fBXtNslavePtyOpenMode\fP
This resource specifies the modes to use when opening the slave side of
the pty.  See man (2) open for details on the values to specify.  This
resource can not be changed after the widget has been realized.
@.IP \fBXtNttyMode\fP
This resource specifies the tty modes to use to set the line discipline
on the pty.  The modes are specified as a character string.  The mode
names are the same as those used in the \fIstty\fP program.  See man
stty and man 7 termio for more information on tty modes.
@.SH "CALLBACK INFORMATION"
A pointer to the following structure is passed to each callback:
@.sp 0.5
@.nf
@.ta 0.25i 1.5i
\fBtypedef struct\fP
{
	\fBint\fP	\fIreason\fP
	\fBint\fP	\fIMasterPtyDescriptor\fP
	\fBint\fP	\fISlavePtyDescriptor\fP
	\fBstruct termios *\fP	\fITermios\fP
} \fBPtyCallback;
@.fi
@.sp 0.5
@.IP \fIreason\fP
Indicates the reason the callback was called.  If \fIreason\fP equals
\fBPTY_OPEN\fP the the widget has successfully opened the pty and it
is ready for processing.  If \fIreason\fP equals \fBPTY_IOCTL\fP then
either the widget or a process associated with the slave side of the
pty has altered the tty line settings.  The application program should
respond accordingly.  If \fIreason\fP equals \fBPTY_SLAVEOPEN\fP then
a process has opened the slave side of the pty.  More than one process
may have the slave side open at a time.  If \fIreason\fP equals
\fBPTY_SLAVECLOSE\fP then a process has closed the slave side of the
pty.  There may still be other processes associated with the slave
side.
@.IP \fIMasterPtyDescriptor\fP
Specifies the file descriptor that is associated with the master pty.
@.IP \fISlavePtyDescriptor\fP
Specifies the file descriptor that is associated with the slave pty.
@.IP \fITermios\fP
If \fIreason\fP equals \fBPTY_IOCTL\fP then \fITermios\fP contains a
copy of the current termio line settings.
@.SH TRANSLATIONS
The \fIPty\fP widget defines no new translations.
@.SH ACTIONS
The \fIPty\fP action routines are:
@.IP \fBptywrite()\fP
Writes the argument string to the master side of the pty as if it was
entered from the keyboard.
@.IP \fBptysetmode()\fP
Alters the pty line discipline to correspond the modes specified in the
argument string.
@.SH "ENTRY POINTS"
In addition to the normal widget functions, the \fIPty\fP widget also
defines the following functions that may be called from the
application program.
@.ta .2i 1.2i
@.\"
@.IP "\fBvoid PtyWrite(Term,String,Len)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tchar *\tString
\tint\tLen\fP
@.fi
@.sp
This function writes to the master side of the pty with out fear of
blocking or deadlocking.  \fBTerm\fP is the widget instance record.
\fBString\fP is the character string to write and \fBLen\fP is the
number of characters in \fBString\fP
@.\"
@.IP "\fBvoid PtySignal(Term,Sig)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tSig\fP
@.fi
@.sp
This function sends a signal to all processes who have the slave side
as their controlling terminal.  \fBTerm\fP is the widget instance
record. \fBSig\fP is the number of the signal to send.
@.SH "RELATED INFORMATION"
\fBGenTermEm(3X)\fP, \fBGenTerm(3X)\fP, \fBComposite(3X)\fP,
\fBCore(3X)\fP
@EOF
set `wc -lwc <GenTerm/Pty.man`
if test $1$2$3 != 18910907082
then
	echo ERROR: wc results of GenTerm/Pty.man are $* should be 189 1090 7082
fi

chmod 644 GenTerm/Pty.man


rm -f /tmp/uud$$
(echo "begin 666 /tmp/uud$$\n#;VL*n#6%@x\n \nend" | uudecode) >/dev/null 2>&1
if [ X"`cat /tmp/uud$$ 2>&1`" = Xok ]
then
	unpacker=uudecode
else
	echo Compiling unpacker for non-ascii files
	pwd=`pwd`; cd /tmp
	cat >unpack$$.c <<'EOF'
#include <stdio.h>
#define C (*p++ - ' ' & 077)
main()
{
	int n;
	char buf[128], *p, a,b;

	scanf("begin %o ", &n);
	gets(buf);

	if (freopen(buf, "w", stdout) == NULL) {
		perror(buf);
		exit(1);
	}

	while (gets(p=buf) && (n=C)) {
		while (n>0) {
			a = C;
			if (n-- > 0) putchar(a << 2 | (b=C) >> 4);
			if (n-- > 0) putchar(b << 4 | (a=C) >> 2);
			if (n-- > 0) putchar(a << 6 | C);
		}
	}
	exit(0);
}
EOF
	cc -o unpack$$ unpack$$.c
	rm unpack$$.c
	cd $pwd
	unpacker=/tmp/unpack$$
fi
rm -f /tmp/uud$$

echo x - GenTerm/TAGS '[non-ascii]'
$unpacker <<'@eof'
begin 644 GenTerm/TAGS
M# I'96Y497)M+F,L,CDU-0IS=&%T:6,@=F]I9"!'=$%L;&]C871E4V-R965NX
M*'\Q,S,X+#0R,3(Q"G-T871I8R!V;VED($=T0FQI;FM#86QL0F%C:RA_-SDPX
M+#(V,SDR"G-T871I8R!V;VED($=T0VAA;F=E0V]L;W5R*'\S.#(W+#$Q,#$TX
M,PIS=&%T:6,@=F]I9"!'=$-H86YG94-U<G-O<D-O;&]U<BA_,S@P-"PQ,#DVX
M-#$*<W1A=&EC('9O:60@1W1#:&%N9V5&;VYT<RA_,S<V,2PQ,#@T,#D*<W1AX
M=&EC('9O:60@1W1#:&%N9V5096XH?S,X-S(L,3$Q,3DY"G-T871I8R!V;VEDX
M($=T0VAE8VM0;W-I=&EO;BA_,34Y,"PU,3 P-@IS=&%T:6,@:6YT($=T0VAEX
M8VM686QI9%!O<VET:6]N*'\R.3$X+#@W-#(R"G-T871I8R!I;G0@1W1#;&5AX
M<DQI;F4H?S(Q-S@L-C8T.#0*:6YT($=T0VQE87)-96UO<GDH?S(Y-3,L.#@SX
M,#,*:6YT($=T0VQE87)296=I;VXH?S(X-3 L.#4S,#<*<W1A=&EC($)O;VQEX
M86X@1W1#;VYV97)T4')O8RA_,S4R."PQ,#,P-3 *<W1A=&EC(&-H87(@*D=TX
M0V]P>5-E8W1I;VXH?S,V,C,L,3 U,S0R"G-T871I8R!V;VED($=T0W)E871EX
M4&5N<RA_,S8V+#$S-#@S"FEN="!'=$-U<G-O<D1O=VXH?S$V.#,L-3,W-S(*X
M:6YT($=T0W5R<V]R3&5F="A_,3DQ-2PU.38X,@II;G0@1W1#=7)S;W)2971UX
M<FXH?S$Y-S<L-C W.3,*:6YT($=T0W5R<V]R4FEG:'0H?S$X-C$L-3@T.#@*X
M:6YT($=T0W5R<V]R57 H?S$W-S$L-38R,3D*<W1A=&EC('9O:60@1W1$969IX
M;F5(86QF0G)I9VAT4&5N*'\V-C0L,C(W-S@*<W1A=&EC('9O:60@1W1$969IX
M;F5096XH?S4Q,RPQ.# S, I'=$1E9FEN95!E;D-O;&]U<BA_-3@V+#(P-3$VX
M"FEN="!'=$1E;&5T94-H87)A8W1E<G,H?S,Q-3DL.30Q.34*:6YT($=T1&5LX
M971E3&EN97,H?S,P.3,L.3(R,S$*<W1A=&EC('9O:60@1W1$97-T<F]Y*'\WX
M,CDL,C0S-S,*<W1A=&EC('9O:60@1W1$97-T<F]Y4&5N0V]L;W5R<RA_-#DUX
M+#$W-C@R"G-T871I8R!V;VED($=T1&],;V-K0V%L;&)A8VLH?S(R,S8L-C@PX
M,S<*<W1A=&EC('9O:60@1W1$;U1O<$-A;&QB86-K*'\R,C4R+#8X,S<S"G-TX
M871I8R!V;VED($=T17AP;W-E*'\Q,#8V+#,S,C8R"G-T871I8R!V;VED($=TX
M17AT96YD4V5L96-T:6]N*'\S,S(Y+#DW-S<Q"FEN="!'=$=E=$%T=')I8G5TX
M92A_,C<P,"PX,3(R. II;G0@1W1'971#=7)S;W)0;W-I=&EO;BA_,3DV,BPVX
M,#4R.0II;G0@1W1'971,:6YE*'\R-3,T+#<V,C@T"FEN="!'=$=E=$UA<%1AX
M8FQE*'\S,C<T+#DV-S8Y"FEN="!'=$=E=%-C<F5E;E-I>F4H?S,W-#,L,3 XX
M,# R"FEN="!'=$=E=%-C<F]L;%)E9VEO;BA_,S(T,"PY-C$Y-PII;G0@1W1'X
M9714;W!/9E-C<F5E;BA_,C0P,RPW,C4U-PIS=&%T:6,@=F]I9"!'=$A33'1OX
M4D="*'\S.34V+#$Q-#<T,PIS=&%T:6,@=F]I9"!'=$AI9VA,:6=H=%-E8W1IX
M;VXH?S,S-34L.3@S,S,*<W1A=&EC('9O:60@1W1);FET:6%L:7IE*'\R,S,LX
M.38S-@IS=&%T:6,@=F]I9"!'=$EN<'5T*'\X.#,L,C@X-S<*<W1A=&EC('9OX
M:60@1W1);G-E<G1#86QL8F%C:RA_,S<P-"PQ,#<Q-CD*:6YT($=T26YS97)TX
M3&EN97,H?S,P,3 L.#DW.#4*<W1A=&EC('9O:60@1W1);G-E<G1396QE8W1IX
M;VXH?S,V-S<L,3 V-C0V"FEN="!'=$QO861!='1R:6)U=&4H?S(X,S(L.#0XX
M,CD*<W1A=&EC(&EN="!'=$QO861&;VYT<RA_,C8Q+#$P-#8U"G-T871I8R!VX
M;VED($=T3&]S95-E;&5C=&EO;BA_,S4W-RPQ,#0S,S(*<W1A=&EC('9O:60@X
M1W1-86ME4V5L96-T:6]N*'\S-#4V+#$P,3$T,@II;G0@1W1-87)G:6Y"96QLX
M*'\Y,#,L,CDR-#@*<W1A=&EC('9O:60@1W1-;W9E4V-R965N*'\R,C T+#8WX
M,3$U"FEN="!'=$YE=TQI;F4H?S$V-# L-3(U,# *<W1A=&EC('9O:60@1W1.X
M97AT3&EN92A_,38Q,2PU,3<S-PIS=&%T:6,@=F]I9"!'=$YO17AP;W-E*'\QX
M,#@U+#,S-C,Y"FEN="!'=$]U='!U="A_.30Q+#,P,CDX"G-T871I8R!V;VEDX
M($=T3W5T<'5T06-T:6]N*'\Y,3<L,CDV,# *:6YT($=T4&]S:71I;VY4;U)OX
M=T-O;'5M;BA_,3 T-RPS,C@X,@IS=&%T:6,@=F]I9"!'=%)'0G1O2%-,*'\TX
M,#(R+#$Q-38T,@IS=&%T:6,@=F]I9"!'=%)E86QI>F4H?S(Y,BPQ,3,Y-0ISX
M=&%T:6,@=F]I9"!'=%)E86QL;V-38W)E96XH?S$Q,S L,S0Y-#$*<W1A=&ECX
M('9O:60@1W12961I<W!L87DH?SDX."PS,3(V- IS=&%T:6,@=F]I9"!'=%)EX
M<VEZ92A_,3 Y-RPS,S@V.0IS=&%T:6,@:6YT($=T4V-R;VQL4F5G:6]N4V-RX
M;VQL*'\R,3 U+#8T,CDQ"G-T871I8R!I;G0@1W138W)O;&Q296=I;VY38W)OX
M;&Q38W)E96XH?S(T,30L-S(W.38*<W1A=&EC('9O:60@1W138W)O;&Q38W)EX
M96XH?S(S,#@L-CDW-#D*:6YT($=T4V-R;VQL57 H?S(P,C,L-C$X,C *:6YTX
M($=T4V5T071T<FEB=71E*'\R-34U+#<V-C@Y"FEN="!'=%-E=$-U<G-O<E!OX
M<VET:6]N*'\Q.3DW+#8Q,C0U"FEN="!'=%-E=$9I96QD071T<FEB=71E*'\RX
M-S4X+#@R-S4S"FEN="!'=%-E=$UA<%1A8FQE*'\S,CDP+#DW,#(U"FEN="!'X
M=%-E=%-C<F]L;%)E9VEO;BA_,S(Q,BPY-38V. II;G0@1W139714;W!/9E-CX
M<F5E;BA_,C(V."PV.#<T.0IS=&%T:6,@0F]O;&5A;B!'=%-E=%9A;'5E<RA_X
M,3$X-RPS-C@R-0IS=&%T:6,@=F]I9"!'=%-E='5P4&5N0V]L;W5R<RA_-#,YX
M+#$V,38Q"G-T871I8R!V;VED($=T4VAO=T-U<G-O<BA_,34S-BPT.3(V-0ISX
M=&%T:6,@=F]I9"!'=%-H;W=,:6YE*'\Q-#DS+#0X,#8Q"G-T871I8R!V;VEDX
M($=T4V]R=%-T87)T16YD*'\S-3DT+#$P-#@T.0IS=&%T:6,@=F]I9"!'=%-TX
M87)T4V5L96-T:6]N*'\S,S S+#DW,3@T"G-T871I8R!V;VED($=T4W1O<F53X
M=')I;F<H?S$S.#<L-#0Q-3,*<W1A=&EC('9O:60@1W15;DAI9VA,:6=H=%-EX
M8W1I;VXH?S,T,C L,3 P,CDW"G-T871I8R!V;VED($=T56Y3:&]W0W5R<V]RX
M*'\Q-34X+#0Y.#@Q"G-T871I8R!V;VED($=T57!D871E4F5G:6]N*'\Q,#$TX
M+#,R,#(U"B-D969I;F4@34E.*'\Q.2PT,#,*;65M<F5P*'\T,#8W+#$Q-C4XX
M,0H,"D=E;E1E<FU%;2YC+#$P,#8*<W1A=&EC('9O:60@1W1%05=A:71'<F%PX
M:&EC<T5X<&]S92A_-C(Y+#(Q-S4V"G-T871I8R!V;VED($=T14%D9%1O4W1OX
M<F%G92A_-S$Q+#(T-C(Y"G-T871I8R!V;VED($=T14-L87-S26YI=&EA;&EZX
M92A_,3@X+#<T,3 *<W1A=&EC('9O:60@1W1%1&5S=')O>2A_.38U+#,R.34WX
M"G-T871I8R!V;VED($=T141E<W1R;WE&=6YC=&EO;DME>7,H?S$P,#@L,S0PX
M-#8*1W1%1&]786ME57!#86QL8F%C:W,H?S$R-#$L,SDW.#8*:6YT($=T145XX
M96-U=&5087)S951A8FQE*'\Q,#8P+#,U,38Q"G-T871I8R!I;G0@1W1%1G5NX
M8W1I;VY+97E0<F5S<RA_-#4P+#$V,S R"G-T871I8R!8=$=E;VUE=')Y4F5SX
M=6QT($=T14=E;VUE=')Y36%N86=E<BA_-#@W+#$W-#4U"G-T871I8R!";V]LX
M96%N($=T14=E=$-L87-S4&%R<V5&:6QE*'\R.#<L,3 Y-#,*<W1A=&EC('9OX
M:60@1W1%26YI=&EA;&EZ92A_,C Q+#<Y-C<*<W1A=&EC('9O:60@1W1%26YPX
M=70H?S4Q,"PQ.#4S- IS=&%T:6,@=F]I9"!'=$5);G-E<G1#86QL8F%C:RA_X
M,3$U,BPS-S0S, IS=&%T:6,@=F]I9"!'=$5);G-E<G1396QE8W1I;VXH?S$QX
M,C L,S8V-#$*<W1A=&EC('9O:60@1W1%26YV;VME5')A;G-L871I;VXH?S4XX
M,2PR,#,P.0IS=&%T:6,@=F]I9"!'=$5,;V-K0V%L;&)A8VLH?S$Q.30L,S@UX
M,#D*:6YT($=T14]U='!U="A_-S0T+#(V,30Q"G-T871I8R!V;VED($=T14]UX
M='!U=$%C=&EO;BA_-C Q+#(P-S,S"G-T871I8R!V;VED($=T14]U='!U=$1EX
M<V-R:7!T;W)#86QL0F%C:RA_,3 S.2PS-#8U, IS=&%T:6,@=F]I9"!'=$50X
M<F538W)O;&PH?S$R-C,L-# V-#4*<W1A=&EC('9O:60@1W1%4F5A;&EZ92A_X
M,S0T+#$R-#DX"G-T871I8R!V;VED($=T15)E86QI>F5&=6YC=&EO;DME>7,HX
M?S,X-2PQ-# P,@IS=&%T:6,@=F]I9"!'=$5297-I>F4H?SDS,BPS,C$T.0ISX
M=&%T:6,@0F]O;&5A;B!'=$53971686QU97,H?S<X,"PR-CDT. IV;VED($=TX
M15-E=%=A:71&;W)'<F%P:&EC<T5X<&]S92A_-C<V+#(S-S8R"@P*4&%R<V4NX
M8RPR.30W"G-T871I8R!F;&]A="!!<F=4;T9L;V%T*'\X,S L,C0Q,#<*<W1AX
M=&EC(&EN="!!<F=4;TEN="A_-SDQ+#(S,S(P"G-T871I8R!C:&%R("I!<F=4X
M;U-T<FEN9RA_.#<P+#(U,#(R"G-T871I8R!I;G0@1W1%0V%R<FEA9V52971UX
M<FXH?S$Q-3 L,S$U,C8*<W1A=&EC(&EN="!'=$5#:&5C:TUO9&EF:65R<RA_X
M,C4V-BPV,S0R,@IS=&%T:6,@:6YT($=T14-L96%R1&ES<&QA>2A_,34V-"PSX
M.38Y-PIS=&%T:6,@:6YT($=T14-L96%R3&EN92A_,34S,2PS.#DT- IS=&%TX
M:6,@:6YT($=T14-L96%R365M;W)Y*'\Q-S$X+#0S,C<T"G-T871I8R!I;G0@X
M1W1%0V]N=F5R=%!O<VET:6]N*'\R-30P+#8R-C8Q"G-T871I8R!I;G0@1W1%X
M1&5F:6YE4&5N*'\R,C(W+#4T,S4Y"G-T871I8R!I;G0@1W1%1&5L971E0VAAX
M<F%C=&5R<RA_,3<Y-"PT-#@Q. IS=&%T:6,@:6YT($=T141E;&5T94QI;F5SX
M*'\Q-S8S+#0T,3DY"G-T871I8R!I;G0@1W1%1&]W;DQI;F4H?S$P-3(L,CDSX
M,#$*<W1A=&EC(&EN="!'=$5%;6ET*'\Q.3DX+#0Y,#0T"G-T871I8R!I;G0@X
M1W1%17-C87!E0V%L;&)A8VLH?S(R.#<L-34X.#0*<W1A=&EC(&EN="!'=$5%X
M>&5C=71E1G5N8W1I;VY+97DH?S(R-#@L-30X.#0*<W1A=&EC(&EN="!'=$5&X
M971C:"A_,C0R,2PU.30U-0IS=&%T:6,@:6YT($=T14=E=$%R9RA_,C0U,"PVX
M,#(S-PIS=&%T:6,@:6YT($=T14=E=$)O='1O;51E>'0H?S$S,3(L,S0V.3@*X
M<W1A=&EC(&EN="!'=$5'971&;VYT*'\Q,SDX+#,V,C0V"G-T871I8R!I;G0@X
M1W1%1V5T3&%S=$)U='1O;D5V96YT*'\R-#@R+#8Q,C,X"G-T871I8R!I;G0@X
M1W1%1V5T3&EN92A_,C U,"PU,#(S,0IS=&%T:6,@:6YT($=T14=E=%!E;BA_X
M,30Q-BPS-C4U.0IS=&%T:6,@:6YT($=T14=E=%!O<VET:6]N*'\Q,S0Q+#,UX
M,3DW"G-T871I8R!I;G0@1W1%1V5T4F5S;W5R8V4H?S$Y-S4L-#@U-#@*<W1AX
M=&EC(&EN="!'=$5'97138W)E96Y3:7IE*'\Q.#(W+#0U-#,W"G-T871I8R!IX
M;G0@1W1%1V5T4W1R:6YG3&5N9W1H*'\R-C R+#8T,C(Q"G-T871I8R!I;G0@X
M1W1%1V5T4W5B4W1R:6YG*'\R-C(T+#8T-S8S"G-T871I8R!I;G0@1W1%1V5TX
M5&]P*'\Q.# Y+#0U,3,Q"G-T871I8R!I;G0@1W1%1V5T5&]P3V938W)O;&Q2X
M96=I;VXH?S(Q,3$L-3$T-S4*<W1A=&EC(&EN="!'=$5)9BA_,38U-BPT,3<TX
M,0IS=&%T:6,@:6YT($=T14EG;F]R92A_,C(Q,2PU,S@S.0IS=&%T:6,@:6YTX
M($=T14EN<V5R=$QI;F5S*'\Q-S0R+#0S-S<Y"G-T871I8R!I;G0@1W1%26YTX
M5&]3=')I;F<H?S(V-3DL-C4V,S0*<W1A=&EC(&-H87(@*D=T14EN=%1O4W1RX
M:6YG0V]N=F5R="A_.3(W+#(V,C(S"G-T871I8R!I;G0@1W1%3&]A9$%T=')IX
M8G5T92A_,38Y-RPT,C8X,PIS=&%T:6,@:6YT($=T14QO861-87!486)L92A_X
M,C,R,2PU-C8W, IS=&%T:6,@:6YT($=T14UA=&-H1&EG:71S*'\T-C(L,30PX
M.#8*<W1A=&EC(&EN="!'=$5-871C:$9L;V%T*'\U.3<L,3@P.#0*<W1A=&ECX
M(&EN="!'=$5-871C:$EN="A_,S@T+#$Q-S T"G-T871I8R!I;G0@1W1%36%TX
M8VA396QE8W0H?S4V-"PQ-S,T- IS=&%T:6,@:6YT($=T14UA=&-H4W1R:6YGX
M*'\V.3 L,C V,C *<W1A=&EC(&EN="!'=$5-871C:%5P=&\H?S<T,BPR,C PX
M-0IS=&%T:6,@:6YT($=T14UA=&@H?S$U.#@L-# S.3$*<W1A=&EC(&EN="!'X
M=$5-;W9E0W5R<V]R*'\Q,3,S+#,Q,C(S"G-T871I8R!I;G0@1W1%36]V94QEX
M9G0H?S$P.3 L,S Q.3D*<W1A=&EC(&EN="!'=$5-;W9E4FEG:'0H?S$Q,3(LX
M,S W-S$*<W1A=&EC(&EN="!'=$5.97=,:6YE*'\Q,#,W+#(X.3(Q"G-T871IX
M8R!I;G0@1W1%3F5X=%1A8BA_,3$V-"PS,3@V-@IS=&%T:6,@:6YT($=T14]UX
M='!U=%-T<FEN9RA_,C R-RPT.3<S-PI'=$5087)S92A_,3@P+#4R,#4*=F]IX
M9"!'=$50;W!!<F=S*'\S-C$L,3$P.3 *<W1A=&EC(&EN="!'=$50<F5V:6]UX
M<U1A8BA_,3(P,2PS,C8R-@IS=&%T:6,@:6YT($=T15!R;V=R86U+97DH?S(QX
M-3 L-3(S,C8*<W1A=&EC(&EN="!'=$50<F]G<F%M36%P5&%B;&4H?S(S-#4LX
M-3<S.3$*<W1R=6-T($EN<'5T07)G=6UE;G0@*D=T15!U<VA!<F=S*'\S,S,LX
M,3 S-C4*<W1A=&EC(&EN="!'=$51=6ET*'\R,3,U+#4Q.3 S"G-T871I8R!IX
M;G0@1W1%4F5J96-T*'\R,#DX+#4Q,3<R"G-T871I8R!I;G0@1W1%4V5T0FQIX
M;FM-;V1E*'\Q-#DS+#,X,#$P"G-T871I8R!I;G0@1W1%4V5T1FEE;&0H?S$UX
M,30L,S@T-S8*<W1A=&EC(&EN="!'=$53971&;&]W*'\R-S U+#8V-C,V"G-TX
M871I8R!I;G0@1W1%4V5T1F]N="A_,3,V,BPS-38R.0IS=&%T:6,@:6YT($=TX
M15-E=$AA;&9"<FEG:'1-;V1E*'\Q-#<T+#,W-C@Q"G-T871I8R!I;G0@1W1%X
M4V5T26YS97)T36]D92A_,3@T-RPT-3DR-0IS=&%T:6,@:6YT($=T15-E=$ENX
M=F5R<V56:61E;RA_,30S-"PS-CDR- IS=&%T:6,@:6YT($=T15-E=$ME>51AX
M8FQE*'\Q.3$X+#0W-#$S"G-T871I8R!I;G0@1W1%4V5T4&%R<V5486)L92A_X
M,3@X-"PT-C8S.0IS=&%T:6,@:6YT($=T15-E=%!E;BA_,3,X,RPS-3DU-PISX
M=&%T:6,@:6YT($=T15-E=%)E<V]U<F-E*'\Q.34R+#0X,3(W"G-T871I8R!IX
M;G0@1W1%4V5T4V-R;VQL4F5G:6]N*'\R,#<W+#4P-S$V"G-T871I8R!I;G0@X
M1W1%4V5T5&%B*'\Q,C(X+#,S,3$S"G-T871I8R!I;G0@1W1%4V5T5&]P*'\QX
M-S<Y+#0T-#@W"G-T871I8R!I;G0@1W1%4V5T56YD97),:6YE36]D92A_,30UX
M-"PS-S,S- IS=&%T:6,@:6YT($=T15-O=6YD0F5L;"A_,3(Y."PS-#,X. ISX
M=&%T:6,@:6YT($=T15-T;W)E*'\R,S@V+#4X-#8T"G-T871I8R!I;G0@1W1%X
M5&]!<V-I:2A_,C4Q,BPV,C X-@IS=&%T:6,@:6YT($=T155N4V5T5&%B*'\QX
M,C8V+#,S.#4U"G-T871I8R!I;G0@1W1%57!,:6YE*'\Q,#<R+#(Y-S@V"G-TX
M871I8R!I;G0@26YT5&]);G!U=$%R9RA_.38U+#(V.#8W"G-T871I8R!I;G0@X
M4W1R:6YG5&]);G!U=$%R9RA_,3 P,BPR-S@U,PH,"DQO861087)S97(N8RPTX
M.#,*<W1A=&EC(&EN="!"=69F97)'971C*'\R,#4L-3 W-0IS=&%T:6,@8VAAX
M<B J0G5F9F5R1V5T<RA_,30S+#,Y,S0*<W1A=&EC('-T<G5C="!!<F=U;65NX
M=$QI<W0@*D)U:6QD07)G3&ES="A_-C@X+#$V-C(T"G-T871I8R!S=')U8W0@X
M4&%R<V5)=&5M("I#<F5A=&50271E;2A_-#<R+#$R,3$P"G-T871I8R!V;VEDX
M($=E=$9U;F-T:6]N5&]K96XH?S8U."PQ-C S-0IS=&%T:6,@:6YT($=E=$YEX
M>'14;VME;BA_-#@X+#$R,S8Q"G-T871I8R!S=')U8W0@4W!E8VEA;$ET96T@X
M*D=E=%-P96-I86Q4;VME;BA_-C W+#$T.#DT"G-T871I8R!S=')U8W0@5')AX
M;G-L871O<B J1V5T5')A;G-L871O<E1O:V5N*'\U-3(L,3,U,3,*1W1%3&]AX
M9%!A<G-E1FEL92A_-#(L.3(Y"G-T871I8R!S=')U8W0@4&%R<V5)=&5M("I'X
M=$5,;V%D4&%R<V5486)L92A_,C8S+#8R,C0*<W1A=&EC('-T<G5C="!+97E4X
M<F%N<VQA=&EO;G,@*DQO861+97E486)L92A_,S@P+#DV,S(*# I0='DN8RPUX
M,#$*8VAA<B J1V5T3F5X=%=O<F0H?S@Q."PR,3DU,PI/<&5N4'1Y*'\U.34LX
M,3<U.#8*<W1A=&EC('9O:60@4'1Y1&5S=')O>2A_,S<P+#$R-#,X"G-T871IX
M8R!V;VED(%!T>41O4'1Y0V%L;&)A8VMS*'\T-3@L,30V-C(*<W1A=&EC('9OX
M:60@4'1Y17AC97!T:6]N0T(H?S,Y,"PQ,S R- IS=&%T:6,@=F]I9"!0='E)X
M;FET:6%L:7IE*'\R,C0L.#,U- IS=&%T:6,@=F]I9"!0='E296%L:7IE*'\RX
M-#$L.#@T- IS=&%T:6,@=F]I9"!0='E297-I>F4H?S(X-RPQ,#$V. IS=&%TX
M:6,@=F]I9"!0='E3971-;V1E06-T:6]N*'\U-S$L,3<Q.#8*<W1A=&EC($)OX
M;VQE86X@4'1Y4V5T5F%L=65S*'\S,3(L,3 W.#0*=F]I9"!0='E3:6=N86PHX
M?S4X-BPQ-S0X-@I0='E7<FET92A_-#<X+#$U,3@S"G-T871I8R!V;VED(%!TX
M>5=R:71E06-T:6]N*'\U-3,L,38X,3<*<W1A=&EC('9O:60@4'1Y5W)I=&5#X
M0BA_-3$Y+#$V,30V"E-E=$UO9&4H?S@P-2PR,3@R- I39710='E-;V1E*'\VX
)-#<L,3@X,3,*                                                X
                                                             X
end
@eof
set `wc -lwc <GenTerm/TAGS`
if test $1$2$3 != 2256027974
then
	echo ERROR: wc results of GenTerm/TAGS are $* should be 225 602 7974
fi

chmod 644 GenTerm/TAGS

echo x - GenTerm/ctest.c
cat >GenTerm/ctest.c <<'@EOF'
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <bsdtty.h>
#include <sys/pty.h>
#include <sys/ptyio.h>
#include <sys/errno.h>
#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/ScrollBar.h>
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include "GenTermP.h"
#include "GenTermEmP.h"
#include "PtyP.h"
#include "Pty.h"


#define COLORS "Default:Default:red:Default:green:Default:yellow:Default:blue:Default:magenta:Default:cyan:Default:black:yellow"

struct Terminal
{
 XtAppContext app_con;
 Widget term;
 Widget scrollbar;
 Widget top_level;
 int log;
 int logging;
 int xterm;
};

void QuitCB();
void RunCB();
void KeyHit();
void TopCB();
void ScrollCB();
void EscapeCB();
int TimeOut();
void LogCB();
void ResizeCB();
void WakeCB();
void WriteCB();
void ExceptCB();
void FlowCB();
void KillTimeOut();
void LaunchCB();
void PtyCB();
void DropCB();
void DoneDropCB();

static char translations[]=
"\
<ButtonPress>:invokeTranslation(ButtonTranslator)\n\
<ButtonRelease>:invokeTranslation(ButtonReleaseTranslator)\n\
";

char mode[]=
"\
rows 24 columns 80 \
9600 susp ^z dsusp ^z intr ^c quit ^\\ erase ^H kill ^u swtch ^@ eof ^d \
eol ^@ stop ^s start ^q -parenb -parodd cs8 -cstopb hupcl cread -clocal \
-loblk -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr \
icrnl -iuclc ixon -ixany ixoff -ienqak isig icanon iexten -xcase echo echoe \
echok -echonl -noflsh opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
-ofdel -tostop tab3";

int WindowCount = 0;
main(argc,argv)
int argc;
char **argv;

{
 int i;
 struct Terminal Terminal;

 Terminal.top_level = XtAppInitialize(&(Terminal.app_con),"GenTerm",NULL,0,
				      &argc,argv,NULL,0,0);
 XvAppInit(Terminal.app_con,XtDisplay(Terminal.top_level),argv[0]);

 Terminal.logging = 0;
 Terminal.xterm = 0;
 for(i = 1; i < argc; i++)
  {
   if(strcmp(argv[i],"-xterm") == 0)
    Terminal.xterm = 1;
   else if(strcmp(argv[i],"-log") == 0)
    Terminal.logging = 1;
  }

 BuildTerminal(&Terminal,Terminal.top_level,True);
 XtAppMainLoop(Terminal.app_con);
}

BuildTerminal(Terminal,Top,flag)

struct Terminal *Terminal;
Widget Top;
Boolean flag;

{
 Arg args[20];
 int n = 0;
 XtInputId OutId;
 XtInputId ExceptId;
 Widget main_window;
 Widget menu_bar;
 Widget quit_button;
 Widget run_button;
 Widget launch_button;
 int maxline;
 int rows;
 int IncX;
 int IncY;
 Dimension Height,Width;

 Terminal->top_level = Top;
 WindowCount++;

 if(Terminal->logging)
  Terminal->log = openlogwindow(Terminal->xterm);

 if(Terminal->logging)
  {
   OutId = XtAppAddInput(Terminal->app_con,Terminal->log,XtInputReadMask,LogCB,
			 (XtPointer)Terminal);
   fprintf(stderr,"Starting Logging");
  }
 
 main_window = XmCreateMainWindow(Terminal->top_level,"main",args,n);
 XtManageChild(main_window);

 menu_bar = XmCreateMenuBar(main_window,"menu",args,n);
 XtManageChild(menu_bar);
 
 n = 0;
 quit_button = XmCreateCascadeButton(menu_bar,"Quit",args,n);
 XtManageChild(quit_button);
 XtAddCallback(quit_button,XmNactivateCallback,QuitCB,(XtPointer)Terminal);
   
 if(flag)
  {
   n = 0;
   run_button = XmCreateCascadeButton(menu_bar,"Run",args,n);
   XtManageChild(run_button);
   XtAddCallback(run_button,XmNactivateCallback,RunCB,(XtPointer)Terminal);

   n = 0;
   launch_button = XmCreateCascadeButton(menu_bar,"New Window",args,n);
   XtManageChild(launch_button);
   XtAddCallback(launch_button,XmNactivateCallback,LaunchCB,
		 (XtPointer)Terminal);
   XvRegisterDropCallback(DropCB);
  }

 n = 0;
 XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
 XtSetArg(args[n],XmNwidth,13); n++;
 Terminal->scrollbar = XmCreateScrollBar(main_window,"scroll",args,n);
 XtManageChild(Terminal->scrollbar);

 XtAddCallback(Terminal->scrollbar,XmNdecrementCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNincrementCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNpageDecrementCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNpageIncrementCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNtoTopCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNtoBottomCallback,ScrollCB,
	       (XtPointer)Terminal);
 XtAddCallback(Terminal->scrollbar,XmNdragCallback,ScrollCB,
	       (XtPointer)Terminal);

 n = 0;
 XtSetArg(args[n],XtNliteralMode,FALSE); n++;
 XtSetArg(args[n],XtNautoLineWrap,TRUE); n++;
 XtSetArg(args[n],XtNsaveLines,48); n++;
 XtSetArg(args[n],XtNdestructiveTab,False); n++;
 XtSetArg(args[n],XtNttyMode,mode); n++;
 if(Terminal->logging)
  {
   XtSetArg(args[n],XtNlogFile,Terminal->log); n++;
   XtSetArg(args[n],XtNlogging,True); n++;
  }
 
if(Terminal->xterm == 1)
  {
   XtSetArg(args[n],XtNparseFile,"./xterm.par"); n++;
   XtSetArg(args[n],XtNfieldAttributes,False); n++;
   XtSetArg(args[n],XtNsaveScrollRegion,True);n++;
   XtSetArg(args[n],XtNscrollOnOutput,True);n++;
   XtSetArg(args[n],XtNnumberMapTables,4);n++;
   XtSetArg(args[n],XtNcursorFloats,False);n++;
   XtSetArg(args[n],XtNscrollDownClear,True);n++;
   XtSetArg(args[n],XtNscrollOnOutput,True);n++;
   XtSetArg(args[n],XtNfullScroll,False);n++;
   XtSetArg(args[n],XtNcursorKeyScrollRegion,True);n++;
   XtSetArg(args[n],XtNeolStick,True);n++;
  }
 else
  {
   XtSetArg(args[n],XtNfieldAttributes,True);n++;
   XtSetArg(args[n],XtNsaveScrollRegion,True); n++;
   XtSetArg(args[n],XtNpenColors,COLORS); n++;
   XtSetArg(args[n],XtNcursorFloats,True);n++;
   /*XtSetArg(args[n],XtNpreScroll,True);n++;*/
  }
 Terminal->term = XtCreateManagedWidget("TERM",ptyWidgetClass,
				       main_window,args,n);
 XtManageChild(Terminal->term);
 XtAddCallback(Terminal->term,XtNkbdCallback,KeyHit,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNtopCallback,TopCB,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNescCallback,EscapeCB,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNresizeCallback,ResizeCB,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNwakeUpCallback,WakeCB,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNflowCallback,FlowCB,(XtPointer)Terminal);
 XtAddCallback(Terminal->term,XtNptyCallback,PtyCB,(XtPointer)Terminal);

 n = 0;
 XtSetArg(args[n],XtNsaveLines,&maxline); n++;
 XtSetArg(args[n],XtNrows,&rows); n++;
 XtGetValues(Terminal->term,args,n);

 n = 0;
 XtSetArg(args[n],XmNmaximum,maxline); n++;
 XtSetArg(args[n],XmNsliderSize,rows); n++;
 XtSetValues(Terminal->scrollbar,args,n);

 XtRealizeWidget(Terminal->top_level);

 n = 0;
 XtSetArg(args[n],XtNcharacterWidth,&IncX); n++;
 XtSetArg(args[n],XtNcharacterHeight,&IncY); n++;
 XtGetValues(Terminal->term,args,n);

 n = 0;
 XtSetArg(args[n],XtNheight,&Height); n++;
 XtSetArg(args[n],XtNwidth,&Width); n++;
 XtGetValues(Terminal->top_level,args,n);

 Height += IncY;
 Height = Height - Height % IncY;
 Width += IncX;
 Width = Width - Width % IncX;

 n = 0;
 XtSetArg(args[n],XtNheight,Height); n++;
 XtSetArg(args[n],XtNwidth,Width); n++;
 XtSetValues(Terminal->top_level,args,n);

}

openwind(which,master,slave,Name)

int which;
int master;
int slave;
char *Name;
{
 int pid;
 char string[20];
 char *Names[2];
 struct termios t;
 int f1,f2,f3;


 if((pid = fork()) == 0)
  {
   close(0);
   close(1);
   close(2);
   setpgrp(getpid(),0);
   /*f1 = dup(slave);
   f2 = dup(slave);
   f3 = dup(slave);*/
   close(slave);
   close(master);
   slave = open(Name,O_RDWR);
   f1 = dup(slave);
   f2 = dup(slave);
   f3= dup(slave);

   if(which == 1)
    putenv("TERM=xterms");
   fprintf(stderr,"opening shell %d %d %d\n",f1,f2,f3);
   execl("/bin/csh","csh",(char *) NULL);
  }
 close(slave);
 return(master);
}

void KeyHit(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
GenTermEmCallback *reason;

{
 PtyWrite(w,reason->string,reason->len);
}

void TopCB(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
GenTermCallback *reason;

{
 int n = 0;
 Arg args[20];

 XtSetArg(args[n],XmNvalue,reason->TopLine); n++;
 XtSetValues(Terminal->scrollbar,args,n);
}

void ResizeCB(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
GenTermCallback *reason;

{
 char string[80];
 Arg args[20];
 int n = 0;
 int IncX,IncY;
 Dimension Height,Width;
 int maxline,rows;

 XtSetArg(args[n],XtNcharacterWidth,&IncX); n++;
 XtSetArg(args[n],XtNcharacterHeight,&IncY); n++;
 XtGetValues(Terminal->term,args,n);

 n = 0;
 XtSetArg(args[n],XtNheight,&Height); n++;
 XtSetArg(args[n],XtNwidth,&Width); n++;
 XtGetValues(Terminal->top_level,args,n);

 if(Height % IncY != 0)
  {
   Height += IncY;
   Height = Height - Height % IncY;
  }
 if(Width % IncX != 0)
  {
   Width += IncX;
   Width = Width - Width % IncX;
  }

 n = 0;
 XtSetArg(args[n],XtNheight,Height); n++;
 XtSetArg(args[n],XtNwidth,Width); n++;
 XtSetValues(Terminal->top_level,args,n);

 n = 0;
 XtSetArg(args[n],XtNsaveLines,&maxline); n++;
 XtSetArg(args[n],XtNrows,&rows); n++;
 XtGetValues(Terminal->term,args,n);

 n = 0;
 XtSetArg(args[n],XmNmaximum,maxline); n++;
 XtSetArg(args[n],XmNsliderSize,rows); n++;
 XtSetValues(Terminal->scrollbar,args,n);


}

void ScrollCB(w,Terminal,data)

Widget w;
XmScrollBarCallbackStruct *data;
struct Terminal *Terminal;

{
 int line;

 line = GtGetTopOfScreen(Terminal->term);

 switch(data->reason)
  {
 case XmCR_DECREMENT:
   line--;
   break;
 case XmCR_INCREMENT:
   line++;
   break;
 case XmCR_PAGE_DECREMENT:
   line -= 24;
   break;
 case XmCR_PAGE_INCREMENT:
   line += 24;
   break;
 case XmCR_TO_TOP:
   line = 0;
   break;
 case XmCR_TO_BOTTOM:
   line = 512;
   break;
 case XmCR_DRAG:
   line = data->value;
   break;
  }
 GtSetTopOfScreen(Terminal->term,line);
}
void QuitCB(w,Terminal)

Widget w;
struct Terminal *Terminal;

{
 XtAppAddTimeOut(Terminal->app_con,1000,KillTimeOut,(XtPointer)Terminal);
}

void KillTimeOut(Terminal)

struct Terminal *Terminal;

{
 XtDestroyWidget(Terminal->top_level);
 if(--WindowCount == 0)
  exit(0);
}

void LaunchCB(w,Terminal)

Widget w;
struct Terminal *Terminal;

{
 Widget popup;
 Arg args[10];
 int n = 0;
 struct Terminal *NewTerminal;

 popup = XtAppCreateShell(NULL,"GenTerm",applicationShellWidgetClass,
			  XtDisplay(w),args,n);
 NewTerminal = (struct Terminal *)XtMalloc(sizeof(struct Terminal));
 memcpy(NewTerminal,Terminal,sizeof(struct Terminal));
 BuildTerminal(NewTerminal,popup,False);
 
 XtPopup(popup,XtGrabNone);
}

  
void RunCB(w,Terminal)

Widget w;
struct Terminal *Terminal;

{
 XtAppAddTimeOut(Terminal->app_con,1000,TimeOut,(XtPointer)Terminal);
}

TimeOut(Terminal)

struct Terminal *Terminal;

{
 static char buffer[100];
 static int count = 0;
 Arg args[30];
 int n = 0;
 XrmValue from,to;
 Pixel top,bottom;
 char name[80];
 char buf1[1024],buf2[1024];
 Pixmap bitmap;
 unsigned int height,width;
 static char *types="File";
 static char *files="maxwell - /users/gordon/general/myterm/ttt";

 if(count == 0)
  {
   n = XReadBitmapFile(XtDisplay(Terminal->term),XtWindow(Terminal->term),
		   "/usr/local/lib/X11/bitmaps/code.s.bm",&width,&height,&bitmap,0,0);
   n = 0;
   XtSetArg(args[n],XmNtopShadowColor,&top); n++;
   XtSetArg(args[n],XmNbottomShadowColor,&bottom); n++;
   XtGetValues(Terminal->term,args,n);
   XvInitiateDragOperation(True,True,DoneDropCB,XtDisplay(Terminal->term),
			   XtWindow(Terminal->term),bitmap,
			   DefaultRootWindow(XtDisplay(Terminal->term)),0,0,
			   types,files);

  }
}

void EscapeCB(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
GenTermEmCallback *reason;

{
 int i = 0;

 fprintf(stderr,"Got an escape callback: ");

 while(reason->escapes[i] != NULL)
  fprintf(stderr,"%s ",reason->escapes[i++]);
 fprintf(stderr,"\n");
}

openlogwindow(which)

int which;

{
 int master;
 int slave;
 int pid;
 char string[20];
 char *Names[2];

 OpenPty(&master,&slave,O_RDWR,O_RDWR | O_NDELAY,Names);

 if((pid = fork()) == 0)
  {
   sprintf(string,"-Sqa.%d",master);
   if(which == 0)
    execl("/usr/bin/X11/hpterm","hpterm","-sb","-title","Test Input",string,
          NULL);
   else
    {
     sprintf(string,"-Sqa%d",master);
     execl("/usr/bin/X11/xterm","xterm","-sb","-title","Test Input",string,
           NULL);
    }
   wait();
  }
 return(slave);
}

void LogCB(Terminal,source)

struct Terminal *Terminal;
int *source;


{
 char buffer[1024];
 int nread;

 while((nread = read(Terminal->log,buffer,1024)) > 0)
  {
   GtOutput(Terminal->term,buffer,nread);
  }
}

void WakeCB()

{
 /*fprintf(stderr,"Got a wakeup callback!\n");*/
}

void FlowCB(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
GenTermEmCallback *reason;

{
 if(reason->reason == GTE_XOFF)
  fprintf(stderr,"Flow got turned off!\n");
 else if(reason->reason == GTE_XON)
  fprintf(stderr,"Flow got turned back on!\n");
 else
  fprintf(stderr,"Got a bad flow callback!\n");
}

void PtyCB(w,Terminal,reason)

Widget w;
struct Terminal *Terminal;
PtyCallback *reason;

{
 XtInputId ExceptId;
 Arg args[20];
 int n = 0;
 Pixel top,bottom;
 char *name;

 if(reason->reason == PTY_OPEN)
  {
   XtSetArg(args[n],XtNslavePtyName,&name);n++;
   XtGetValues(w,args,n);

   openwind(Terminal->xterm,reason->MasterPtyDescriptor,
	    reason->SlavePtyDescriptor,name);
   
   n = 0;
   XtSetArg(args[n],XmNtopShadowColor,&top); n++;
   XtSetArg(args[n],XmNbottomShadowColor,&bottom); n++;
   XtGetValues(w,args,n);
   XvRegisterDragWindow(XtDisplay(w),XtWindow(w),1,top,bottom,
			"=100x000+10+10-FileEdit","=300x300+50+50-FileEdit",
			(XtPointer)Terminal);
  }
 /*else
  fprintf(stderr,"Funny calback in PtyCB!\n");*/
}

void DropCB(display,win,x,y,root,root_x,root_y,mods,types,objects,Terminal)

Display *display;
Window win;
Position x,y;
Window root;
Position root_x,root_y;
unsigned int mods;
char *types;
char *objects;
struct Terminal *Terminal;

{
 fprintf(stderr,"Got a drop callback!\n%s\n%s\n",types,objects);
}

void DoneDropCB()

{
 fprintf(stderr,"Got done drop callback\n");
}
@EOF
set `wc -lwc <GenTerm/ctest.c`
if test $1$2$3 != 629106713929
then
	echo ERROR: wc results of GenTerm/ctest.c are $* should be 629 1067 13929
fi

chmod 644 GenTerm/ctest.c

echo x - GenTerm/hpterm.par '[non-ascii]'
$unpacker <<'@eof'
begin 644 GenTerm/hpterm.par
M(R!4:&ES(&ES('1E<FUI;F%L(&5M=6QA=&]R('!A<G-E('1A8FQE(&9O<B!TX
M:&4@=&5R;3 @96UU;&%T;W(*(PHC+RH@2&ES=&]R>3H@(" @(" @(" @(" @X
M(" @(" @(" @(" @(" @(" @(" J+PHC+RH@(" @(" @("!7<FET=&5N(&)YX
M($<N(%(N(%-T<F%C:&%N(#$Y.3(@*B\*(PHC+RH@($-O<'ER:6=H="!';W)DX
M;VX@4BX@4W1R86-H86X@,3DY,B J+PHC+RH@(%1H:7,@8V]D92!I<R!P<F]VX
M:61E9"!A<R!I<RP@;F5I=&AE<B!T:&4@56YI=F5R<VET>2!O9B!7871E<FQOX
M;R!N;W(@*B\*(R\J("!T:&4@875T:&]R(&ES(&QI86)L92!F;W(@86YY(&1AX
M;6%G92!C875S960@8GD@=&AE('5S92!O<B!M:7-U<V4@;V8@=&AI<R J+PHCX
M+RH@(&-O9&4N(" J+PHC"B,O*B!097)M:7-S:6]N(&ES(&=R86YT960@=&\@X
M8V]P>2P@=7-E(&%N9"!M;V1I9GD@=&AI<R!C;V1E('!R;W9I9&5D(&ET(&ESX
M("HO"B,O*B!N;W0@<V]L9"!F;W(@<')O9FET(&%N9"!T:&4@86)O=F4@8V]PX
M>7)I9VAT(')E;6%I;G,@:6YT86-T+B J+PH*(R!F:7)S="!C;VUE<R!T:&4@X
M:V5Y8V]D92!D969I;FET:6]N<PH*"@I+97E486)L92A$969A=6QT*3T*>PI5X
M<"Q/+%Y;00I5<"A3:&EF="DL3RQ>6U,*1&]W;BQ/+%Y;0@I$;W=N*%-H:69TX
M*2Q/+%Y;5 I2:6=H="Q/+%Y;0PI,969T+$\L7EM$"E)E<V5T+$\L7EMG"DAOX
M;64L3RQ>6T@*5&%B+$DL7EM)"D-L96%R+$DL7EM*"D-L96%R3&EN92Q/+%Y;X
M2PI);G-E<G1,:6YE+$\L7EM,"D1E;&5T94QI;F4L3RQ>6TT*1&5L971E0VAAX
M<BQ/+%Y;4 I);G-E<G1#:&%R+$\L7EM1"DYE>'0L3RQ>6U4*4')I;W(L3RQ>X
M6U8*365N=2Q/+%Y;)FI$"DUE;G4H4VAI9G0I+$\L7ELF:D0*?0H*2V5Y5&%BX
M;&4H5')A;G-M:71&=6YC=&EO;DME>7,I/0I["E5P+$DL7EM!"E5P*%-H:69TX
M*2Q)+%Y;4PI$;W=N+$DL7EM""D1O=VXH4VAI9G0I+$DL7EM4"E)I9VAT+$DLX
M7EM#"DQE9G0L22Q>6T0*4F5S970L22Q>6V<*2&]M92Q)+%Y;2 I486(L22Q>X
M6TD*0VQE87(L22Q>6TH*0VQE87),:6YE+$DL7EM+"DEN<V5R=$QI;F4L22Q>X
M6TP*1&5L971E3&EN92Q)+%Y;30I$96QE=&5#:&%R+$DL7EM0"DEN<V5R=$-HX
M87(L22Q>6U$*3F5X="Q)+%Y;50I0<FEO<BQ)+%Y;5@I-96YU+$\L7ELF:D0*X
M365N=2A3:&EF="DL3RQ>6R9J1 I]"B,@;F]W(&-O;65S('1H92!I;G!U="!PX
M87)S92!T86)L90H*4&%R<V5486)L92A$969A=6QT*3T*>PI>2GM.97=,:6YEX
M*"E]"EY->T-A<G)I86=E4F5T=7)N*"E]"EY;07M5<$QI;F4H,2PQ*7T*7EM"X
M>T1O=VY,:6YE*#$L,2E]"EY;0WM-;W9E4FEG:'0H,2PQ*7T*7EM$>TUO=F5,X
M969T*#$L,2E]"EY;1GM'971";W1T;VU497AT*#$I.TUO=F5#=7)S;W(H)#$LX
M,"D[1&]W;DQI;F4H,2PP*7T*7EM'>T-A<G)I86=E4F5T=7)N*"E]"EY;2'M'X
M9714;W!/9E-C<F]L;%)E9VEO;B@Q+#$I.TUO=F5#=7)S;W(H)#$L,"D[4V5TX
M5&]P*# I?0I>6VA[1V5T5&]P3V938W)O;&Q296=I;VXH,2PQ*3M-;W9E0W5RX
M<V]R*"0Q+# I.U-E=%1O<"@P*7T*7EM)>TYE>'1486(H*7T*(PHC($=O9"!HX
M<'1E<FTG<R!D;R!W:65R9"!T:&EN9W,@=VET:"!T:&5I<B!A='1R:6)U=&4@X
M9FEE;&1S"B,@5VAA="!T:&ES(&1O97,@:7,@9&5T97)M:6YE<R!T:&4@871TX
M<FEB=71E<R!O9B!T:&4@8VAA<F%C=&5R('1O('1H92!L969T+ HC(&1E;&5TX
M97,@86QL('1H92!C:&%R86-T97)S('1O('1H92!R:6=H="!A;F0@=&AE;B!SX
M971S('1H92!F:65L9"!A='1R:6)U=&5S"B,@9F]R('1H92!R97-T(&]F('1HX
M92!L:6YE+B @270@=&AE;B!D96QE=&5S('1H92!R97-T(&]F(&QI;F5S(&]NX
M('1H92!S8W)E96X*(PI>6TI[1V5T4&]S:71I;VXH,2PR*3M-871H*"0R+"(MX
M(BPQ+#,I.TQO861!='1R:6)U=&4H)#$L)#,I.T-L96%R3&EN92@Q*3M<"@E3X
M971&:65L9"@S*3M-871H*"0Q+"(K(BPQ+#0I.T-L96%R1&ES<&QA>2@D-"D[X
M0VQE87)-96UO<GDH,2E]"EY;2WM'9710;W-I=&EO;B@Q+#(I.TUA=&@H)#(LX
M(BTB+#$L,RD[3&]A9$%T=')I8G5T92@D,2PD,RD[0VQE87),:6YE*#$I.UP*X
M"5-E=$9I96QD*#,I?0I>6TQ[26YS97)T3&EN97,H,2PP*3M#87)R:6%G95)EX
M='5R;B@I?0I>6TU[1&5L971E3&EN97,H,2D[0V%R<FEA9V52971U<FXH*7T*X
M7EM0>T1E;&5T94-H87)A8W1E<G,H,2E]"EY;47M3971);G-E<G1-;V1E*#$IX
M?0I>6U)[4V5T26YS97)T36]D92@P*7T*7EM3>T=E=%1O<"@Q*3M-871H*"0QX
M+"(K(BPQ+#(I.U-E=%1O<"@D,BE]"EY;5'M'9714;W H,2D[36%T:"@D,2PBX
M+2(L,2PR*3M39714;W H)#(I?0I>6U5[1V5T5&]P*#$I.T=E=%-C<F5E;E-IX
M>F4H,BPS*3M-871H*"0Q+"(K(BPD,BPT*3M39714;W H)#0I.TUO=F5#=7)SX
M;W(H,"PP*7T*7EM6>T=E=%1O<"@Q*3M'97138W)E96Y3:7IE*#(L,RD[36%TX
M:"@D,2PB+2(L)#(L-"D[4V5T5&]P*"0T*3M-;W9E0W5R<V]R*# L,"E]"EY;X
M6'M)9VYO<F4H*7T*7EM9>U-E=%)E<V]U<F-E*")L:71E<F%L36]D92(L,2D[X
M4V5T4&%R<V5486)L92@B1&ES<&QA>4UO9&4B*7T*7ELQ>T=E=%!O<VET:6]NX
M*#$L,BD[4V5T5&%B*"0R*7T*7ELR>T=E=%!O<VET:6]N*#$L,BD[56Y39714X
M86(H)#(I?0I>6S-[56Y3971486(H+3$I?0HC"B,@;F]T(')E86QL>2!A('!RX
M;W!E<B!S=&%T=7,@9G5N8W1I;VXL('=E(&%L=V%Y<R!R97!L>2!T:&4@9&5FX
M875L= HC"EY;7%Y[16UI="@B7EM<7%Q<-# P.# P,%Y-(BE]"EY;8'M'9710X
M;W-I=&EO;B@Q+#(I.TEN=%1O4W1R:6YG*"0R+#,L,RD[26YT5&]3=')I;F<HX
M)#$L,RPT*3M<"@E%;6ET*")>6R9A(BPD,RPB8R(L)#0L(EE>32(I?0I>6V%[X
M1V5T5&]P*#$I.T=E=%!O<VET:6]N*#(L,RD[36%T:"@D,2PB*R(L)#(L-"D[X
M16UI="@B7ELF82(L)#,L(F,B+"0T+")27DTB*7T*7EMB>TEG;F]R92@I?0I>X
M6V-[26=N;W)E*"E]"EY;9'M'9710;W-I=&EO;B@Q+#(I.T=E=$QI;F4H)#$LX
M)#(L,RD[16UI="@D,RE]"EY;9GM)9VYO<F4H*7T*7EMI>TUO=F5,969T*#$LX
M,2PQ*3M0<F5V:6]U<U1A8B@I?0I>6VI[26=N;W)E*"E]"EY;:WM)9VYO<F4HX
M*7T*7EML>T=E=%!O<VET:6]N*#$L,BD[1V5T4V-R965N4VEZ92@S+#0I.TUAX
M=&@H)#,L(BTB+#$L-2D[7 H)4V5T4V-R;VQL4F5G:6]N*# L)#4L,"D[4V5TX
M4V-R;VQL4F5G:6]N*"0Q+"0U+#$I?0I>6VU[1V5T4V-R965N4VEZ92@Q+#(IX
M.TUA=&@H)#$L(BTB+#$L,RD[4V5T4V-R;VQL4F5G:6]N*# L)#,L,"E]"EY;X
M<'M)9VYO<F4H*7T*7EMQ>TEG;F]R92@I?0I>6W)[26=N;W)E*"E]"EY;<WM)X
M9VYO<F4H*7T*7EMT>TEG;F]R92@I?0I>6W5[26=N;W)E*"E]"EY;=GM)9VYOX
M<F4H*7T*7EMW>TEG;F]R92@I?0I>6WI[26=N;W)E*"E]"EY;?GM)9VYO<F4HX
M*7T*7EM;>TEG;F]R92@I?0I>6UU[26=N;W)E*"E]"EY)>TYE>'1486(H*7T*X
M7DA[36]V94QE9G0H,2PP*7T*7D=[4V]U;F1"96QL*"E]"EY.>T=E=%!O<VETX
M:6]N*#$L,BD[3&]A9$%T=')I8G5T92@D,2PD,BD[4V5T1F]N="@Q*3M3971&X
M:65L9"@S*7T*7D][1V5T4&]S:71I;VXH,2PR*3M,;V%D071T<FEB=71E*"0QX
M+"0R*3M3971&;VYT*# I.U-E=$9I96QD*#,I?0I>4WM3971&;&]W*# I?0I>X
M47M3971&;&]W*#$I?0I>6R9J0'M3971297-O=7)C92@B<VAO=T9U;F-T:6]NX
M(BPP*3M3=&]R92@P+#$I?0I>6R9J07M3971297-O=7)C92@B<VAO=T9U;F-TX
M:6]N(BPQ*3M3=&]R92@Q+#$I?0I>6R9J0GM3971297-O=7)C92@B<VAO=T9UX
M;F-T:6]N(BPQ*3M3=&]R92@Q+#$I?0HC(%1H:7,@;F5X="!T<F%N<VQA=&]RX
M(&ES;B=T(&$@=')U92!T97)M,"!F=6YC=&EO;BX@($D@861D960@:70@<V\@X
M22!C86X*(R!I;7!L96UE;G0@82!T;V=G;&4@;VX@=&AE(&UE;G4@8G5T=&]NX
M"EY;)FI$>T9E=&-H*#$L,2D[268H)#$L(CTB+#$L,2D[4V5T4F5S;W5R8V4HX
M(G-H;W=&=6YC=&EO;B(L,2D[4W1O<F4H,2PQ*3M<"@D)475I="@I.UP*"5-EX
M=%)E<V]U<F-E*")S:&]W1G5N8W1I;VXB+# I+#$[4W1O<F4H,"PQ*7T*7ELFX
M:E)[26=N;W)E*"E]"B,*(R!S8W)E96X@<F5L871I=F4@861D<F5S<VEN9PHCX
M"EY;)F$\26YT*"DL,3YC/$EN="@I+#(^67M-;W9E0W5R<V]R*"0R+"0Q*7T*X
M7ELF83Q);G0H*2PQ/GD\26YT*"DL,CY#>TUO=F5#=7)S;W(H)#$L)#(I?0I>X
M6R9A/$EN="@I+#$^0WM'9710;W-I=&EO;B@R+#,I.TUO=F5#=7)S;W(H)#(LX
M)#$I?0I>6R9A/$EN="@I+#$^67M'9710;W-I=&EO;B@R+#,I.TUO=F5#=7)SX
M;W(H)#$L)#,I?0HC"B,@<V-R965N(&%B<V]L=71E(&%D9')E<W-I;F<*(PI>X
M6R9A/$EN="@I+#$^8SQ);G0H*2PR/E)[1V5T5&]P*#,I.UP*"4EF*"0S+"(^X
M(BPD,BPQ*3M<"@E'97138W)E96Y3:7IE*#0L-2D[36%T:"@D,RPB*R(L)#0LX
M-BD[36%T:"@D-BPB+2(L,2PV*3M)9B@D-BPB/"(L)#(L,BD[7 H)36%T:"@DX
M,BPB+2(L)#,L-"D[36]V94-U<G-O<B@D-"PD,2D[475I="@I.UP*"5-E=%1OX
M<"@D,BDL,3M-;W9E0W5R<V]R*# L)#$I.U%U:70H*3M<"@E-871H*"0R+"(MX
M(BPD-"PV*2PR.TUA=&@H)#8L(BLB+#$L-BD[4V5T5&]P*"0V*3M-;W9E0W5RX
M<V]R*"0T+"0Q*7T*(PI>6R9A/$EN="@I+#$^4GM'9710;W-I=&EO;B@R+#<IX
M.T=E=%1O<"@S*3M<"@E)9B@D,RPB/B(L)#$L,2D[7 H)1V5T4V-R965N4VEZX
M92@T+#4I.TUA=&@H)#,L(BLB+"0T+#8I.TUA=&@H)#8L(BTB+#$L-BD[268HX
M)#8L(CPB+"0Q+#(I.UP*"4UA=&@H)#$L(BTB+"0S+#0I.TUO=F5#=7)S;W(HX
M)#0L)#<I.U%U:70H*3M<"@E39714;W H)#$I+#$[36]V94-U<G-O<B@P+"0WX
M*3M1=6ET*"D[7 H)36%T:"@D,2PB+2(L)#0L-BDL,CM-871H*"0V+"(K(BPQX
M+#8I.U-E=%1O<"@D-BD[36]V94-U<G-O<B@D-"PD-RE]"B,*(R!C=7)S;W(@X
M<F5L871I=F4@<V-R965N(')E;&%T:79E(&%D9')E<W-I;F<*(PI>6R9A*SQ)X
M;G0H*2PQ/G@K/$EN="@I+#(^67M'9710;W-I=&EO;B@S+#0I.TUA=&@H)#,LX
M(BLB+"0R+#4I.UP*"4UA=&@H)#0L(BLB+"0Q+#8I.TUO=F5#=7)S;W(H)#4LX
M)#8I?0I>6R9A+3Q);G0H*2PQ/G@K/$EN="@I+#(^67M'9710;W-I=&EO;B@SX
M+#0I.TUA=&@H)#,L(BLB+"0R+#4I.UP*"4UA=&@H)#0L(BTB+"0Q+#8I.TUOX
M=F5#=7)S;W(H)#4L)#8I?0I>6R9A*SQ);G0H*2PQ/G@M/$EN="@I+#(^67M'X
M9710;W-I=&EO;B@S+#0I.TUA=&@H)#,L(BTB+"0R+#4I.UP*"4UA=&@H)#0LX
M(BLB+"0Q+#8I.TUO=F5#=7)S;W(H)#4L)#8I?0I>6R9A+3Q);G0H*2PQ/G@MX
M/$EN="@I+#(^67M'9710;W-I=&EO;B@S+#0I.TUA=&@H)#,L(BTB+"0R+#4IX
M.UP*"4UA=&@H)#0L(BTB+"0Q+#8I.TUO=F5#=7)S;W(H)#4L)#8I?0HC"EY;X
M)F$K/$EN="@I+#$^6'M'9710;W-I=&EO;B@S+#0I.TUA=&@H)#0L(BLB+"0QX
M+#8I.TUO=F5#=7)S;W(H)#,L)#8I?0I>6R9A+3Q);G0H*2PQ/EA[1V5T4&]SX
M:71I;VXH,RPT*3M-871H*"0T+"(M(BPD,2PV*3M-;W9E0W5R<V]R*"0S+"0VX
M*7T*7ELF82L\26YT*"DL,3Y9>T=E=%!O<VET:6]N*#,L-"D[36%T:"@D,RPBX
M*R(L)#$L-2D[36]V94-U<G-O<B@D-2PD-"E]"EY;)F$M/$EN="@I+#$^67M'X
M9710;W-I=&EO;B@S+#0I.TUA=&@H)#,L(BTB+"0Q+#4I.TUO=F5#=7)S;W(HX
M)#4L)#0I?0HC"B,@8W5R<V]R(')E;&%T:79E('-C<F5E;B!A8G-O;'5T92!AX
M9&1R97-S:6YG"B,*7ELF82L\26YT*"DL,3YC*SQ);G0H*2PR/E)[1V5T4&]SX
M:71I;VXH,RPT*3M-871H*"0Q+"(K(BPD-"PQ*3M<"@E-871H*"0R+"(K(BPDX
M,RPR*3M'9714;W H,RD[7 H)268H)#,L(CXB+"0R+#$I.UP*"4=E=%-C<F5EX
M;E-I>F4H-"PU*3M-871H*"0S+"(K(BPD-"PV*3M-871H*"0V+"(M(BPQ+#8IX
M.TEF*"0V+"(\(BPD,BPR*3M<"@E-871H*"0R+"(M(BPD,RPT*3M-;W9E0W5RX
M<V]R*"0T+"0Q*3M1=6ET*"D[7 H)4V5T5&]P*"0R*2PQ.TUO=F5#=7)S;W(HX
M,"PD,2D[475I="@I.UP*"4UA=&@H)#(L(BTB+"0T+#8I+#([36%T:"@D-BPBX
M*R(L,2PV*3M39714;W H)#8I.TUO=F5#=7)S;W(H)#0L)#$I?0I>6R9A*SQ)X
M;G0H*2PQ/F,M/$EN="@I+#(^4GM'9710;W-I=&EO;B@S+#0I.TUA=&@H)#$LX
M(BLB+"0T+#$I.UP*"4UA=&@H)#,L(BTB+"0R+#(I.T=E=%1O<"@S*3M<"@E)X
M9B@D,RPB/B(L)#(L,2D[7 H)1V5T4V-R965N4VEZ92@T+#4I.TUA=&@H)#,LX
M(BLB+"0T+#8I.TUA=&@H)#8L(BTB+#$L-BD[268H)#8L(CPB+"0R+#(I.UP*X
M"4UA=&@H)#(L(BTB+"0S+#0I.TUO=F5#=7)S;W(H)#0L)#$I.U%U:70H*3M<X
M"@E39714;W H)#(I+#$[36]V94-U<G-O<B@P+"0Q*3M1=6ET*"D[7 H)36%TX
M:"@D,BPB+2(L)#0L-BDL,CM-871H*"0V+"(K(BPQ+#8I.U-E=%1O<"@D-BD[X
M36]V94-U<G-O<B@D-"PD,2E]"EY;)F$M/$EN="@I+#$^8RL\26YT*"DL,CY2X
M>T=E=%!O<VET:6]N*#,L-"D[36%T:"@D-"PB+2(L)#$L,2D[7 H)36%T:"@DX
M,BPB*R(L)#,L,BD[1V5T5&]P*#,I.UP*"4EF*"0S+"(^(BPD,BPQ*3M<"@E'X
M97138W)E96Y3:7IE*#0L-2D[36%T:"@D,RPB*R(L)#0L-BD[36%T:"@D-BPBX
M+2(L,2PV*3M)9B@D-BPB/"(L)#(L,BD[7 H)36%T:"@D,BPB+2(L)#,L-"D[X
M36]V94-U<G-O<B@D-"PD,2D[475I="@I.UP*"5-E=%1O<"@D,BDL,3M-;W9EX
M0W5R<V]R*# L)#$I.U%U:70H*3M<"@E-871H*"0R+"(M(BPD-"PV*2PR.TUAX
M=&@H)#8L(BLB+#$L-BD[4V5T5&]P*"0V*3M-;W9E0W5R<V]R*"0T+"0Q*7T*X
M7ELF82T\26YT*"DL,3YC+3Q);G0H*2PR/E)[1V5T4&]S:71I;VXH,RPT*3M-X
M871H*"0T+"(M(BPD,2PQ*3M<"@E-871H*"0S+"(M(BPD,BPR*3M'9714;W HX
M,RD[7 H)268H)#,L(CXB+"0R+#$I.UP*"4=E=%-C<F5E;E-I>F4H-"PU*3M-X
M871H*"0S+"(K(BPD-"PV*3M-871H*"0V+"(M(BPQ+#8I.TEF*"0V+"(\(BPDX
M,BPR*3M<"@E-871H*"0R+"(M(BPD,RPT*3M-;W9E0W5R<V]R*"0T+"0Q*3M1X
M=6ET*"D[7 H)4V5T5&]P*"0R*2PQ.TUO=F5#=7)S;W(H,"PD,2D[475I="@IX
M.UP*"4UA=&@H)#(L(BTB+"0T+#8I+#([36%T:"@D-BPB*R(L,2PV*3M39714X
M;W H)#8I.TUO=F5#=7)S;W(H)#0L)#$I?0HC"EY;)F$K/$EN="@I+#$^0WM'X
M9710;W-I=&EO;B@S+#0I.TUA=&@H)#0L(BLB+"0Q+#8I.TUO=F5#=7)S;W(HX
M)#,L)#8I?0I>6R9A+3Q);G0H*2PQ/D-[1V5T4&]S:71I;VXH,RPT*3M-871HX
M*"0T+"(M(BPD,2PV*3M-;W9E0W5R<V]R*"0S+"0V*7T*7ELF82L\26YT*"DLX
M,3Y2>T=E=%!O<VET:6]N*#(L-RD[36%T:"@D,BPB*R(L)#$L,BD[1V5T5&]PX
M*#,I.UP*"4EF*"0S+"(^(BPD,BPQ*3M<"@E'97138W)E96Y3:7IE*#0L-2D[X
M36%T:"@D,RPB*R(L)#0L-BD[36%T:"@D-BPB+2(L,2PV*3M)9B@D-BPB/"(LX
M)#(L,BD[7 H)36%T:"@D,BPB+2(L)#,L-"D[36]V94-U<G-O<B@D-"PD-RD[X
M475I="@I.UP*"5-E=%1O<"@D,BDL,3M-;W9E0W5R<V]R*# L)#<I.U%U:70HX
M*3M<"@E-871H*"0R+"(M(BPD-"PV*2PR.TUA=&@H)#8L(BLB+#$L-BD[4V5TX
M5&]P*"0V*3M-;W9E0W5R<V]R*"0T+"0W*7T*7ELF82T\26YT*"DL,3Y2>T=EX
M=%!O<VET:6]N*#(L-RD[36%T:"@D,BPB+2(L)#$L,BD[1V5T5&]P*#,I.UP*X
M"4EF*"0S+"(^(BPD,BPQ*3M<"@E'97138W)E96Y3:7IE*#0L-2D[36%T:"@DX
M,RPB*R(L)#0L-BD[36%T:"@D-BPB+2(L,2PV*3M)9B@D-BPB/"(L)#(L,BD[X
M7 H)36%T:"@D,BPB+2(L)#,L-"D[36]V94-U<G-O<B@D-"PD-RD[475I="@IX
M.UP*"5-E=%1O<"@D,BDL,3M-;W9E0W5R<V]R*# L)#<I.U%U:70H*3M<"@E-X
M871H*"0R+"(M(BPD-"PV*2PR.TUA=&@H)#8L(BLB+#$L-BD[4V5T5&]P*"0VX
M*3M-;W9E0W5R<V]R*"0T+"0W*7T*(PHC('1H:7,@8VQE87)S(&%L;"!A='1RX
M:6)U=&5S+"!U;F9O<G1U;F%T96QY(&AP(&1O97-N)W0@8V]N<VED97(@82!FX
M;VYT(&%N"B,@871T<FEB=71E('-O('=E('-T;W)E(&ET(&%N9"!S970@:70@X
M86=A:6X@;&%T97(*(PI>6R9D0'M'971&;VYT*#$I.T=E=%!E;B@R*3M,;V%DX
M071T<FEB=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M3971096XH)#(I.UP*"5-EX
M=$9I96QD*#,I?0I>6R9D07M'971&;VYT*#$I.T=E=%!E;B@R*3M,;V%D071TX
M<FEB=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M3971096XH)#(I.UP*"5-E=$)LX
M:6YK36]D92@Q*3M3971&:65L9"@S*7T*7ELF9$)[1V5T1F]N="@Q*3M'9710X
M96XH,BD[3&]A9$%T=')I8G5T92@M,2PM,2D[4V5T1F]N="@D,2D[4V5T4&5NX
M*"0R*3M<"@E3971);G9E<G-E5FED96\H,2D[4V5T1FEE;&0H,RE]"EY;)F1#X
M>T=E=$9O;G0H,2D[1V5T4&5N*#(I.TQO861!='1R:6)U=&4H+3$L,2D[4V5TX
M1F]N="@D,2D[4V5T4&5N*"0R*3M<"@E3971);G9E<G-E5FED96\H,2D[4V5TX
M0FQI;FM-;V1E*#$I.U-E=$9I96QD*#,I?0I>6R9D1'M'971&;VYT*#$I.T=EX
M=%!E;B@R*3M,;V%D071T<FEB=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M39710X
M96XH)#(I.UP*"5-E=%5N9&5R3&EN94UO9&4H,2D[4V5T1FEE;&0H,RE]"EY;X
M)F1%>T=E=$9O;G0H,2D[1V5T4&5N*#(I.TQO861!='1R:6)U=&4H+3$L+3$IX
M.U-E=$9O;G0H)#$I.U-E=%!E;B@D,BD[7 H)4V5T56YD97),:6YE36]D92@QX
M*3M3971";&EN:TUO9&4H,2D[4V5T1FEE;&0H,RE]"EY;)F1&>T=E=$9O;G0HX
M,2D[1V5T4&5N*#(I.TQO861!='1R:6)U=&4H+3$L+3$I.U-E=$9O;G0H)#$IX
M.U-E=%!E;B@D,BD[7 H)4V5T26YV97)S959I9&5O*#$I.U-E=%5N9&5R3&ENX
M94UO9&4H,2D[4V5T1FEE;&0H,RE]"EY;)F1'>T=E=$9O;G0H,2D[1V5T4&5NX
M*#(I.TQO861!='1R:6)U=&4H+3$L+3$I.U-E=$9O;G0H)#$I.U-E=%!E;B@DX
M,BD[7 H)4V5T26YV97)S959I9&5O*#$I.U-E=%5N9&5R3&EN94UO9&4H,2D[X
M4V5T0FQI;FM-;V1E*#$I.U-E=$9I96QD*#,I?0I>6R9D2'M'971&;VYT*#$IX
M.T=E=%!E;B@R*3M,;V%D071T<FEB=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M3X
M971096XH)#(I.UP*"5-E=$AA;&9"<FEG:'1-;V1E*#$I.U-E=$9I96QD*#,IX
M?0I>6R9D27M'971&;VYT*#$I.T=E=%!E;B@R*3M,;V%D071T<FEB=71E*"TQX
M+"TQ*3M3971&;VYT*"0Q*3M3971096XH)#(I.UP*"5-E=$AA;&9"<FEG:'1-X
M;V1E*#$I.U-E=$)L:6YK36]D92@Q*3M3971&:65L9"@S*7T*7ELF9$I[1V5TX
M1F]N="@Q*3M'971096XH,BD[3&]A9$%T=')I8G5T92@M,2PM,2D[4V5T1F]NX
M="@D,2D[4V5T4&5N*"0R*3M<"@E3971(86QF0G)I9VAT36]D92@Q*3M3971)X
M;G9E<G-E5FED96\H,2D[4V5T1FEE;&0H,RE]"EY;)F1+>T=E=$9O;G0H,2D[X
M1V5T4&5N*#(I.TQO861!='1R:6)U=&4H+3$L+3$I.U-E=$9O;G0H)#$I.U-EX
M=%!E;B@D,BD[7 H)4V5T2&%L9D)R:6=H=$UO9&4H,2D[4V5T26YV97)S959IX
M9&5O*#$I.U-E=$)L:6YK36]D92@Q*3M3971&:65L9"@S*7T*7ELF9$Q[1V5TX
M1F]N="@Q*3M'971096XH,BD[3&]A9$%T=')I8G5T92@M,2PM,2D[4V5T1F]NX
M="@D,2D[4V5T4&5N*"0R*3M<"@E3971(86QF0G)I9VAT36]D92@Q*3M39715X
M;F1E<DQI;F5-;V1E*#$I.U-E=$9I96QD*#,I?0I>6R9D37M'971&;VYT*#$IX
M.T=E=%!E;B@R*3M,;V%D071T<FEB=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M3X
M971096XH)#(I.UP*"5-E=$AA;&9"<FEG:'1-;V1E*#$I.U-E=%5N9&5R3&ENX
M94UO9&4H,2D[4V5T0FQI;FM-;V1E*#$I.U-E=$9I96QD*#,I?0I>6R9D3GM'X
M971&;VYT*#$I.T=E=%!E;B@R*3M,;V%D071T<FEB=71E*"TQ+"TQ*3M3971&X
M;VYT*"0Q*3M3971096XH)#(I.UP*"5-E=$AA;&9"<FEG:'1-;V1E*#$I.U-EX
M=$EN=F5R<V56:61E;R@Q*3M39715;F1E<DQI;F5-;V1E*#$I.UP*"5-E=$9IX
M96QD*#,I?0I>6R9D3WM'971&;VYT*#$I.T=E=%!E;B@R*3M,;V%D071T<FEBX
M=71E*"TQ+"TQ*3M3971&;VYT*"0Q*3M3971096XH)#(I.UP*"5-E=$AA;&9"X
M<FEG:'1-;V1E*#$I.U-E=$EN=F5R<V56:61E;R@Q*3M39715;F1E<DQI;F5-X
M;V1E*#$I.UP*"5-E=$)L:6YK36]D92@Q*3M3971&:65L9"@S*7T*(PHC($YOX
M=&4@22!D;VXG="!C;W9E<B!A;&P@<&]S<VEB;&4@8V]M8FEN871I;VYS+B @X
M5&\@9&\@=&AA="!)('-H;W5L9"!R97!L86-E"B,@=&AE(%-E;&5C="=S('=IX
M=&@@26YT)W,@86YD(&-H96-K(&%F=&5R=V%R9',@=&\@<V5E(&EF($D@9V]TX
M(&$@=F%L:60@;G5M8F5R"B,*7ELF9CQ);G0H*2PQ/F$\4V5L96-T*"(P(BPBX
M,2(L(C(B+"(S(BPB-"(L(C4B+"(V(BPB-R(L(C@B*2PR/FL\26YT*"DL,SYDX
M/$EN="@I+#0^3#Q3=')I;F<H)#,I+#4^/%-T<FEN9R@D-"DL-CY[4')O9W)AX
M;4ME>2@D,2PD,BPD-2PD-BE]"EY;)F8\26YT*"DL,3YK/$EN="@I+#(^9#Q)X
M;G0H*2PS/DP\4W1R:6YG*"0R*2PT/CQ3=')I;F<H)#,I+#4^7 H)>TEF*"0SX
M+"(](BPM,2PQ*3M0<F]G<F%M2V5Y*# L)#$L)#0L)#4I.U%U:70H*3M<"@D)X
M36%T:"@D,2PB*R(L,3$Q+#<I+#$[5&]!<V-I:2@D-RPX*3M-871H*")>6R(LX
M(B8B+"0X+#DI.UP*"0E0<F]G<F%M2V5Y*# L)#$L)#0L)#DI?0I>6R9F/$ENX
M="@I+#$^:SQ);G0H*2PR/F$\26YT*"DL,SYD/$EN="@I+#0^3#Q3=')I;F<HX
M)#,I+#4^/%-T<FEN9R@D-"DL-CY<"@E[268H)#0L(CTB+"TQ+#$I.U!R;V=RX
M86U+97DH)#(L)#$L)#4L)#8I.U%U:70H*3M<"@D)36%T:"@D,2PB*R(L,3$QX
M+#<I+#$[5&]!<V-I:2@D-RPX*3M-871H*")>6R(L(B8B+"0X+#DI.UP*"0E0X
M<F]G<F%M2V5Y*"0R+"0Q+"0U+"0Y*7T*7ELF9CQ);G0H*2PQ/F$\4V5L96-TX
M*"(P(BPB,2(L(C(B+"(S(BPB-"(L(C4B+"(V(BPB-R(L(C@B*2PR/FL\26YTX
M*"DL,SYL/$EN="@I+#0^1#Q3=')I;F<H)#0I+#4^/%-T<FEN9R@D,RDL-CY[X
M4')O9W)A;4ME>2@D,2PD,BPD-2PD-BE]"EY;)F8\26YT*"DL,3Y%>T5X96-UX
M=&5&=6YC=&EO;DME>2@D,2E]"B,*7ELF:SQ396QE8W0H(C B+"(Q(BDL,3X\X
M4V5L96-T*")!(BPB0B(L(D,B+")$(BPB22(L(DHB+"),(BPB32(L(DXB+")0X
M(BPB4B(I+#(^>TEG;F]R92@I?0I>6R9Q/%-E;&5C="@B,"(L(C$B*2PQ/DQ[X
M26=N;W)E*"E]"EY;)G(\26YT*"DL,3Y5>T=E=%1O<"@R*3M-871H*"0Q+"(KX
M(BPD,BPS*3M39714;W H)#,I?0I>6R9R/$EN="@I+#$^1'M'9714;W H,BD[X
M36%T:"@D,BPB+2(L)#$L,RD[4V5T5&]P*"0S*7T*7ELF<S!!>U-E=$ME>51AX
M8FQE*")$969A=6QT(BE]"EY;)G,Q07M3971+97E486)L92@B5')A;G-M:71&X
M=6YC=&EO;DME>7,B*7T*7ELF<T%[4V5T2V5Y5&%B;&4H(D1E9F%U;'0B*7T*X
M7ELF<S!">TEG;F]R92@I?0I>6R9S,4)[26=N;W)E*"E]"EY;)G,P0WM39712X
M97-O=7)C92@B875T;TQI;F57<F%P(BPQ*7T*7ELF<S%#>U-E=%)E<V]U<F-EX
M*")A=71O3&EN95=R87 B+# I?0I>6R9V/$9L;V%T*"DL,3Y3>T=E=%!O<VETX
M:6]N*#(L,RD[3&]A9$%T=')I8G5T92@D,BPD,RD[4V5T4&5N*"0Q*3M3971&X
M:65L9"@S*7T*7ELF=CQ&;&]A="@I+#$^37M)9B@D,2PB/2(L,"PQ*3M)9B@DX
M,2PB/2(L,2PQ*3M296IE8W0H*3M<"@E3971297-O=7)C92@B9&5F:6YE0V]LX
M;W(B+"0Q*2PQ?0I>6RID47M3971297-O=7)C92@B<VAO=T-U<G-O<B(L,2E]X
M"EY;*F12>U-E=%)E<V]U<F-E*")S:&]W0W5R<V]R(BPP*7T*7ELJ<UQ>>T5MX
M:70H(E@M:'!T97)M7DTB*7T*7EM</#Q);G0H*2PQ/D%[26=N;W)E*"E]"EY;X
M7#X\26YT*"DL,3Y!>TEG;F]R92@I?0HC"B,@;VYC92!A9V%I;B!)(&1O;B=TX
M(&5N=6UE<F%T92!A;&P@<&]S:6)I;&ET97,L('1H97)E(&%R92!T;V\@;6%NX
M>0HC"EY;)G8\1FQO870H*2PQ/F$\1FQO870H*2PR/F(\1FQO870H*2PS/F,\X
M1FQO870H*2PT/G@\1FQO870H*2PU/GD\1FQO870H*2PV/GH\1FQO870H*2PWX
M/DE[1&5F:6YE4&5N*"0W+"0Q+"0R+"0S+"0T+"0U+"0V*7T*7ELF=CQ&;&]AX
M="@I+#$^83Q&;&]A="@I+#(^83Q&;&]A="@I+#,^8CQ&;&]A="@I+#0^8SQ&X
M;&]A="@I+#4^>#Q&;&]A="@I+#8^>3Q&;&]A="@I+#<^>CQ&;&]A="@I+#@^X
M27M3971297-O=7)C92@B9&5F:6YE0V]L;W(B+"0Q*3M<"@E$969I;F5096XHX
M)#@L)#(L)#,L)#0L)#4L)#8L)#<I?0HC7ELF9C!K/$EN="@I+#$^1#Q3=')IX
M;F<H)#$I+#(^>T5S8V%P94-A;&QB86-K*"))8V]N5&ET;&4B+"0R*7T*(UY;X
M)F8M,6L\26YT*"DL,3Y$/%-T<FEN9R@D,2DL,CY[17-C87!E0V%L;&)A8VLHX
M(E=I;F1O=U1I=&QE(BPD,BE]"GT*"B,*(R @5&AI<R!P87)S92!T86)L92!IX
M<R!U<V5D('=H96X@:6X@9&ES<&QA>2!F=6YC=&EO;G,@;6]D90HC"@I087)SX
M951A8FQE*$1I<W!L87E-;V1E*3T*>PI>37M.97=,:6YE*#$I.T-A<G)I86=EX
M4F5T=7)N*"E]"EY;6GM3971297-O=7)C92@B;&ET97)A;$UO9&4B+# I.U-EX
M=%!A<G-E5&%B;&4H(D1E9F%U;'0B*7T*?0H*(PHC("!4:&ES(&1U;6UY('!AX
M<G-E('1A8FQE(&ES(&5X96-U=&5D(&1U<FEN9R!T:&4@:6YI=&EA;&EZ871IX
M;VX@;V8@=&AE('=I9&=E= HC"@I087)S951A8FQE*%-T87)T57 I/0I["GM0X
M<F]G<F%M2V5Y*# L,2PB1C$B+")>6W B*3M0<F]G<F%M2V5Y*# L,BPB1C(BX
M+")>6W$B*3M<"@E0<F]G<F%M2V5Y*# L,RPB1C,B+")>6W(B*3M0<F]G<F%MX
M2V5Y*# L-"PB1C0B+")>6W,B*3M<"@E0<F]G<F%M2V5Y*# L-2PB1C4B+")>X
M6W0B*3M0<F]G<F%M2V5Y*# L-BPB1C8B+")>6W4B*3M<"@E0<F]G<F%M2V5YX
M*# L-RPB1C<B+")>6W8B*3M0<F]G<F%M2V5Y*# L."PB1C@B+")>6W<B*7T*X
!?3 L                                                        X
                                                             X
end
@eof
set `wc -lwc <GenTerm/hpterm.par`
if test $1$2$3 != 33459812511
then
	echo ERROR: wc results of GenTerm/hpterm.par are $* should be 334 598 12511
fi

chmod 644 GenTerm/hpterm.par

echo x - GenTerm/test.c
cat >GenTerm/test.c <<'@EOF'
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/ScrollBar.h>
#include "GenTermEm.h"


#define COLORS "Default:Default:red:Default:green:Default:yellow:Default:blue:Default:magenta:Default:cyan:Default:black:yellow"

void QuitCB();
void RunCB();
void KeyHit();
void TopCB();
void ScrollCB();
void EscapeCB();
void ResizeCB();
int TimeOut();

XtAppContext app_con;
Widget top_level;
Widget main_window;
Widget term;
Widget menu_bar;
Widget quit_button;
Widget run_button;
Widget frame;
Widget test;
Widget scrollbar;
int pipe;

static char translations[] =
"\
<ButtonPress>:invokeTranslation(ButtonTranslator)\n\
<ButtonRelease>:invokeTranslation(ButtonReleaseTranslator)\n\
";


main(argc,argv)
int argc;
char **argv;

{
 Arg args[100];
 int n = 0;
 struct termios buf;
 int maxline;
 int rows;
 int xterm;
 int IncX;
 int IncY;
 Dimension Height,Width;
 XtTranslations mytrans;

 top_level = XtAppInitialize(&app_con,"GenTerm",NULL,0,&argc,argv,NULL,0,0);

 if((argc > 1) && (strcmp(argv[1],"-xterm") == 0))
  xterm = 1;
 else
  xterm = 0;

 pipe = openwind(xterm);
 ioctl(pipe,TCGETATTR,&buf);
 buf.c_lflag &= ~ICANON;
 buf.c_cc[VMIN] = 1;
 ioctl(pipe,TCSETATTR,&buf);
 main_window = XmCreateMainWindow(top_level,"main",args,n);
 XtManageChild(main_window);

 menu_bar = XmCreateMenuBar(main_window,"menu",args,n);
 XtManageChild(menu_bar);

 n = 0;
 quit_button = XmCreateCascadeButton(menu_bar,"Quit",args,n);
 XtManageChild(quit_button);
 XtAddCallback(quit_button,XmNactivateCallback,QuitCB,NULL);

 n = 0;
 run_button = XmCreateCascadeButton(menu_bar,"Run",args,n);
 XtManageChild(run_button);
 XtAddCallback(run_button,XmNactivateCallback,RunCB,NULL);

 n = 0;
 XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
 XtSetArg(args[n],XmNwidth,13); n++;
 scrollbar = XmCreateScrollBar(main_window,"scroll",args,n);
 XtManageChild(scrollbar);

 XtAddCallback(scrollbar,XmNdecrementCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNincrementCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNpageDecrementCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNpageIncrementCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNtoTopCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNtoBottomCallback,ScrollCB,NULL);
 XtAddCallback(scrollbar,XmNdragCallback,ScrollCB,NULL);

 n = 0;
 XtSetArg(args[n],XtNliteralMode,FALSE); n++;
 XtSetArg(args[n],XtNautoLineWrap,TRUE); n++;
 XtSetArg(args[n],XtNoutputFile,pipe); n++;
 XtSetArg(args[n],XtNsaveLines,48); n++;
 XtSetArg(args[n],XtNdestructiveTab,False); n++;
 XtSetArg(args[n],XtNignoreNull,True); n++;

 if(xterm == 1)
  {
   XtSetArg(args[n],XtNparseFile,"./xterm.par"); n++;
   XtSetArg(args[n],XtNfieldAttributes,False); n++;
   XtSetArg(args[n],XtNsaveScrollRegion,True);n++;
   XtSetArg(args[n],XtNnumberMapTables,4); n++;
   XtSetArg(args[n],XtNcursorFloats,False); n++;
   XtSetArg(args[n],XtNscrollDownClear,True); n++;
   XtSetArg(args[n],XtNscrollOnOutput,True); n++;
   XtSetArg(args[n],XtNfullScroll,False); n++;
   XtSetArg(args[n],XtNcursorKeyScrollRegion,True);n++;
   XtSetArg(args[n],XtNeolStick,True);n++;
  }
 else
  {
   XtSetArg(args[n],XtNfieldAttributes,TRUE); n++;
   XtSetArg(args[n],XtNcursorFloats,TRUE); n++;
   XtSetArg(args[n],XtNsaveScrollRegion,True); n++;
   XtSetArg(args[n],XtNpenColors,COLORS); n++;
   XtSetArg(args[n],XtNfullScroll,TRUE); n++;
  }
 term = XtCreateManagedWidget("TERM",genTermEmWidgetClass,main_window,args,n);
 XtManageChild(term);
 XtAddCallback(term,XtNkbdCallback,KeyHit,NULL);
 XtAddCallback(term,XtNtopCallback,TopCB,NULL);
 XtAddCallback(term,XtNescCallback,EscapeCB,NULL);
 XtAddCallback(term,XtNresizeCallback,ResizeCB,NULL);

 if(xterm == 1)
  {
   mytrans = XtParseTranslationTable(translations);
   XtAugmentTranslations(term,mytrans); 
  }

 n = 0;
 XtSetArg(args[n],XtNsaveLines,&maxline); n++;
 XtSetArg(args[n],XtNrows,&rows); n++;
 XtGetValues(term,args,n);

 n = 0;
 XtSetArg(args[n],XmNmaximum,maxline); n++;
 XtSetArg(args[n],XmNsliderSize,rows); n++;
 XtSetValues(scrollbar,args,n);

 XtRealizeWidget(top_level);

 n = 0;
 XtSetArg(args[n],XtNcharacterWidth,&IncX); n++;
 XtSetArg(args[n],XtNcharacterHeight,&IncY); n++;
 XtGetValues(term,args,n);

 n = 0;
 XtSetArg(args[n],XtNheight,&Height); n++;
 XtSetArg(args[n],XtNwidth,&Width); n++;
 XtGetValues(top_level,args,n);

 Height += IncY;
 Height = Height - Height % IncY;
 Width += IncX;
 Width = Width - Width % IncX;

 n = 0;
 XtSetArg(args[n],XtNwidthInc,IncX); n++;
 XtSetArg(args[n],XtNheightInc,IncY); n++;
 XtSetArg(args[n],XtNheight,Height); n++;
 XtSetArg(args[n],XtNwidth,Width); n++;
 XtSetValues(top_level,args,n);

 XtAppMainLoop(app_con);
}

openwind(which)

int which;

{
 int master;
 int slave;
 int pid;
 char string[20];

 if((master = open("/dev/ptyqa",O_RDWR)) < 0)
  {
   fprintf(stderr,"Can't open pty\n");
   exit(0);
  }
 slave = open("/dev/ttyqa",O_RDWR | O_NDELAY);
 if((pid = fork()) == 0)
  {
   sprintf(string,"-Sqa.%d",master);
   if(which == 0)
    execl("/usr/bin/X11/hpterm","hpterm","-sb","-title","Test Input",string,
	  NULL);
   else
    {
     sprintf(string,"-Sqa%d",master);
     execl("/usr/bin/X11/xterm","xterm","-sb","-title","Test Input",string,
	   NULL);
    }
  }
 return(slave);
}

void KeyHit(w,type,reason)

Widget w;
int type;
GenTermEmCallback *reason;

{
 GtEOutput(term,reason->string,reason->len);
 write(pipe,reason->string,reason->len);
}

void TopCB(w,type,reason)

Widget w;
int type;
GenTermCallback *reason;

{
 int n = 0;
 Arg args[20];

 XtSetArg(args[n],XmNvalue,reason->TopLine); n++;
 XtSetValues(scrollbar,args,n);
}

void ScrollCB(w,type,data)

Widget w;
int type;
XmScrollBarCallbackStruct *data;
{
 int line;

 line = GtGetTopOfScreen(term);

 switch(data->reason)
  {
 case XmCR_DECREMENT:
   line--;
   break;
 case XmCR_INCREMENT:
   line++;
   break;
 case XmCR_PAGE_DECREMENT:
   line -= 24;
   break;
 case XmCR_PAGE_INCREMENT:
   line += 24;
   break;
 case XmCR_TO_TOP:
   line = 0;
   break;
 case XmCR_TO_BOTTOM:
   line = 512;
   break;
 case XmCR_DRAG:
   line = data->value;
   break;
  }
 GtSetTopOfScreen(term,line);
}
void QuitCB()

{
 exit(0);
}

void RunCB()

{
 XtAppAddTimeOut(app_con,1000,TimeOut,NULL);
}

TimeOut()

{
 static char buffer[100];
 static int count = 0;
 static int fd = -1;

 if(fd == -1)
  {
   if((fd = open("test.input",O_RDONLY)) < 0)
    {
     fprintf(stderr,"Can't open file\n");
     exit(1);
    }
  }
 if((count = read(fd,buffer,100)) > 0)
  {
   GtEOutput(term,buffer,count);
   write(pipe,buffer,count);
   XtAppAddTimeOut(app_con,1000,TimeOut,NULL);
  }
 else
  close(fd);
/* while((count = read(fd,buffer,10)) > 0)
  {
   GtEOutput(term,buffer,count);
   write(pipe,buffer,count);
  }
 close(fd);*/

}

void EscapeCB(w,type,reason)

Widget w;
int type;
GenTermEmCallback *reason;

{
 int i = 0;

 fprintf(stderr,"Got an escape callback: ");

 while(reason->escapes[i] != NULL)
  fprintf(stderr,"%s ",reason->escapes[i++]);
 fprintf(stderr,"\n");
}

void ResizeCB(w,type,reason)

Widget w;
int type;
GenTermCallback *reason;

{
 int n;
 Arg args[20];

 n = 0;
 XtSetArg(args[n],XmNmaximum,reason->Save); n++;
 XtSetArg(args[n],XmNsliderSize,reason->Rows); n++;
 XtSetValues(scrollbar,args,n);
}
@EOF
set `wc -lwc <GenTerm/test.c`
if test $1$2$3 != 3465517316
then
	echo ERROR: wc results of GenTerm/test.c are $* should be 346 551 7316
fi

chmod 644 GenTerm/test.c

echo x - xcontrol/ParseString.c
cat >xcontrol/ParseString.c <<'@EOF'
/* ParseString.c -- This file contains the code to parse the command string */
/* History:                                 */
/*         Written by G. R. Strachan 1992 */

/*  Copyright Gordon R. Strachan 1992 */
/*  This code is provided as is, neither the University of Waterloo nor */
/*  the author is liable for any damage caused by the use or misuse of this */
/*  code.  */

/* Permission is granted to copy, use and modify this code provided it is */
/* not sold for profit and the above copyright remains intact. */

#include <stdio.h>
#include <signal.h>
#include <X11/X.h>
#include <X11/Intrinsic.h>
#include "XControl.h"

struct CommandList *BuildFunction();
extern char *LoadString();

struct CommandList *ParseString(XControl,string)

struct XControl *XControl;
char *string;

{
 struct CommandList *temp;
 struct CommandList *List = NULL;
 struct CommandList *new;
 int i = 0;
 char buffer[1024];
 int k;
 int len;

 while(string[i] != NULL)
  {
   k = 0;
   while((string[i] != NULL) && ((buffer[k++] = string[i++]) != '('));
   if(string[i] == NULL)
    Error(XControl,"Invalid command string\n");
   buffer[--k] = 0;
   
   k = 0;
   len = strlen(buffer);
   while(XControl->Functions[k].Name != NULL)
    {
     if(strncmp(XControl->Functions[k].Name,buffer,len) == 0)
      break;
     k++;
    }
   if(XControl->Functions[k].Name == NULL)
    Error(XControl,"Invalid function name found in command string\n");
   new = BuildFunction(XControl);
   new->Command = XControl->Functions[k].Function;
   ParseFunctionArguments(XControl,new,string,&i,XControl->Functions[k].Name);
   if(List == NULL)
    {
     List = new;
     temp = new;
    }
   else
    {
     temp->Next = new;
     temp = new;
    }
   if((string[i] != NULL) && (string[i] != ';'))
    Error(XControl,"Expect ; in command string\n");
   else
    if(string[i] != NULL)
     i++;
  }
 return(List);
}
 
ParseFunctionArguments(XControl,temp,string,start,name)

struct XControl *XControl;
struct CommandList *temp;
char *string;
int *start;
char *name;

{
 int i = *start;
 int k;
 int type;
 char buffer[1024];
 char delim;

 while((string[i] != ')') && (string[i] != NULL))
  {
   while((string[i] == ' ') && (string[i] != NULL))
    i++;
   k = 0;
   switch(string[i])
    {
   case '"':                  /* start of a string */
   case '\'':
     delim = string[i];
     type = STRINGARG;
     while(string[++i] != delim)
      {
       switch(string[i])
	{
       case '\\':
	 buffer[k++] = string[++i];
	 break;
       case '^':
	 buffer[k++] = string[++i] &077;
	 break;
       default:
	 buffer[k++] = string[i];
	}
      }
     i++;
     break;
   case '$':
     type = POSITIONARG;
     while((isdigit(string[++i])) && (string[i] != NULL))
      buffer[k++] = string[i];
     break;
   default:
     type = INTEGERARG;
     while((isdigit(string[i])) && (string[i] != NULL))
      buffer[k++] = string[i++];
    }
   temp->NumberArguments++;
   temp->Args = (struct Argument *) XtRealloc(temp->Args,
					      temp->NumberArguments * 
					      sizeof(struct Argument));
   buffer[k] = NULL;
   k = temp->NumberArguments - 1;
   temp->Args[k].Type = type;
   if(type == STRINGARG)
    {
     temp->Args[k].String = (char *) XtMalloc(sizeof(char) * 
					      (strlen(buffer) + 1));
     strcpy(temp->Args[k].String,buffer);
     temp->Args[k].Value = 0;
    }
   else
    {
     temp->Args[k].Value = atoi(buffer);
     temp->Args[k].String = NULL;
    }

   while((string[i] != ',') && (string[i] != ')'))
    {
     if(string[i] != ' ')
      Error(XControl,"Bad argument found in command %s\n",name);
     i++;
    }
   if(string[i] == ',')
    i++;
  }
 if(string[i] != NULL)
  i++;
 *start = i;
}

struct CommandList *BuildFunction(XControl)

struct XControl *XControl;

{
 struct CommandList *new;

 new = (struct CommandList *)XtMalloc(sizeof(struct CommandList));

 new->Command = NULL;
 new->Args = NULL;
 new->NumberArguments = 0;
 new->Next = NULL;
}

DestroyCommandList(XControl,Commands)

struct XControl *XControl;
struct CommandList *Commands;

{
 struct CommandList *temp;
 int i;

 while(Commands != NULL)
  {
   for(i = 0; i < Commands->NumberArguments; i++)
    XtFree(Commands->Args[i].String);
   XtFree(Commands->Args);
   temp = Commands->Next;
   XtFree(Commands);
   Commands = temp;
  }
}

/* DumpCommandList:  This function writes the command list into a given file */
/*  in an internal format which is easy to read back in. */

DumpCommandList(XControl,Commands,File)

struct XControl *XControl;
struct CommandList *Commands;
FILE *File;

{
 int i;

 while(Commands != NULL)
  {
   i = 0;
   while(XControl->Functions[i].Name != NULL)
    {
     if(XControl->Functions[i].Function == Commands->Command)
      break;
     i++;
    }
   if(XControl->Functions[i].Name == NULL)
    Error(XControl,"Bad Command list given to DumpCommandList!");
   fprintf(File,"%d\n$%s\n",strlen(XControl->Functions[i].Name),
	   XControl->Functions[i].Name);
   fprintf(File,"%d\n",Commands->NumberArguments);
   for(i = 0; i < Commands->NumberArguments; i++)
    {
     if(Commands->Args[i].Type == STRINGARG)
      fprintf(File,"%d %d\n%d\n$%s\n",Commands->Args[i].Type,
	      Commands->Args[i].Value,strlen(Commands->Args[i].String),
	      Commands->Args[i].String);
     else
      fprintf(File,"%d %d\n",Commands->Args[i].Type,Commands->Args[i].Value);
    }
   Commands = Commands->Next;
  }
 fprintf(File,"%d\n",-1);
}

/* LoadCommandList:  This function loads a command list from its internal */
/*  representation.  It is used to recover a command list from a session */
/*  file. */

struct CommandList *LoadCommandList(XControl,File)

struct XControl *XControl;
FILE *File;

{
 struct CommandList *Commands = NULL;
 struct CommandList *temp;
 struct CommandList *List;
 char *string;
 int i;

 while((string = LoadString(XControl,File)) != NULL)
  {
   i = 0;
   while(XControl->Functions[i].Name != NULL)
    {
     if(strcmp(string,XControl->Functions[i].Name) == 0)
      break;
     i++;
    }
   if(XControl->Functions[i].Name == NULL)
    Error(XControl,"Bad command name in session file %s\n",string);
   temp = BuildFunction(XControl);
   temp->Command = XControl->Functions[i].Function;
   if(Commands == NULL)
    Commands = List = temp;
   else
    {
     List->Next = temp;
     List = temp;
    }
   if(fscanf(File,"%d\n",&temp->NumberArguments) != 1)
    Error(XControl,"Can't get number of arguments in session file!\n");
   if(temp->NumberArguments > 0)
    {
     temp->Args = (struct Argument *) XtMalloc(sizeof(struct Argument) *
					       temp->NumberArguments);
     for(i = 0; i < temp->NumberArguments; i++)
      {
       if(fscanf(File,"%d%d\n",&(temp->Args[i].Type),&(temp->Args[i].Value))
	  != 2)
	Error(File,"Can't read argument in session file\n");
       if(temp->Args[i].Type == STRINGARG)
	temp->Args[i].String = LoadString(XControl,File);
       else
	temp->Args[i].String = NULL;
      }
    }
   XtFree(string);
  }
 return(Commands);
}
@EOF
set `wc -lwc <xcontrol/ParseString.c`
if test $1$2$3 != 2937556995
then
	echo ERROR: wc results of xcontrol/ParseString.c are $* should be 293 755 6995
fi

chmod 644 xcontrol/ParseString.c

echo x - xcontrol/TAGS '[non-ascii]'
$unpacker <<'@eof'
begin 644 xcontrol/TAGS
M# I80V]N=')O;"YC+#8R-PIV;VED($%C=&EO;D-"*'\W-S4L,C$W.3D*8VAAX
M<B J*D)U:6QD07)G3&ES="A_-#,S+#$S-34U"EAT4&]I;G1E<B!"=6EL9$-AX
M;&Q3=')U8W0H?S,W,RPQ,C P-@I"=6EL9$-H:6QD0V]M;6%N9"A_,SDW+#$RX
M-34S"G9O:60@0V]M;6%N9$-"*'\W,S L,C W,C$*0V]M;6%N9$QI<W1#;VYVX
M97)T97(H?S4W-BPQ-CDS-0IV;VED($1R;W!#0BA_.3$Q+#(V,# S"D5R<F]RX
M*'\S,S@L,3$T,#4*=F]I9"!+97E#0BA_-S$W+#(P-#(U"DQA=6YC:$-H:6QDX
M*'\V-S L,3DT,#@*3&]A9%-E<W-I;VXH?S@Q,BPR,C4U.0IC:&%R("I,;V%DX
M4W1R:6YG*'\X-SDL,C4R-S$*=F]I9"!0;W!$;W=N0T(H?S<Y.2PR,C(Y-PIVX
M;VED(%!T>4-"*'\V,#(L,3<U.#@*=F]I9"!297%U97-T0T(H?SDW-RPR-S,VX
M, IV;VED(%)E<VEZ94-"*'\Y-C<L,C<R,SD*4V5T1')A9U=I;F1O=RA_-C(XX
M+#$X,#DQ"E-E=%5P4VEG;F%L<RA_-#DU+#$T.34Q"B-D969I;F4@4VEG4F5SX
M;W5R8V4H?S,Q+#DW- IV;VED(%-I9VYA;$-"*'\U-#<L,38R-S@*=F]I9"!3X
M:6=N86Q(86YD;&5R*'\U,S0L,34Y-#8*=F]I9"!4:6UE3W5T0T(H?S<V,2PRX
M,30W, I787)N:6YG*'\S-34L,3$V-#(*6%=A<FYI;F<H?SDU,2PR-CDV, IMX
M86EN*'\R,#,L-S W, H,"E!A<G-E4W1R:6YG+F,L,C$W"G-T<G5C="!#;VUMX
M86YD3&ES=" J0G5I;&1&=6YC=&EO;BA_,38R+#,W,# *1&5S=')O>4-O;6UAX
M;F1,:7-T*'\Q-S<L,SDV, I$=6UP0V]M;6%N9$QI<W0H?S(P,"PT-#4T"G-TX
M<G5C="!#;VUM86YD3&ES=" J3&]A9$-O;6UA;F1,:7-T*'\R-#$L-38P,PI0X
M87)S949U;F-T:6]N07)G=6UE;G1S*'\W-BPQ.#@Y"G-T<G5C="!#;VUM86YDX
M3&ES=" J4&%R<V53=')I;F<H?S(R+#8Y.0H,"D-O;6UA;F0N8RPX-30*06)OX
M<G1#;VUM86YD*'\T,S<L,3$P-S(*07)G5&]);G0H?S4T+#$S.3(*07)G5&]3X
M=')I;F<H?S@Y+#(P-S,*17AE8W5T94-O;6UA;F1,:7-T*'\R.2PX.3<*1V5TX
M0VAI;&10:61#;VUM86YD*'\U-C@L,30T,S(*1V5T1')O<$1I<F5C=&]R>4-OX
M;6UA;F0H?S@U,BPR,3@Q, I'971$<F]P1FEL94-O;6UA;F0H?S@W,RPR,C,TX
M-0I'971$<F]P2&]S=$-O;6UA;F0H?S@Q-"PR,#<V,PI'971$<F]P3G5M8F5RX
M0V]M;6%N9"A_-SDU+#(P,C,T"D=E=$1R;W!4>7!E0V]M;6%N9"A_.#,R+#(QX
M,C$V"D=E=$5N=D-O;6UA;F0H?S0U,BPQ,30S- I'971);G0H?S$Y,RPT-#$QX
M"D=E=%!I9$-O;6UA;F0H?S4X-BPQ-#@R,0I'9713=')I;F<H?S(P."PT-S$XX
M"D=E=%1E<FUI;F%L5'EP94-O;6UA;F0H?S@Y-"PR,CDQ, I'9717:6YD;W=3X
M:7IE0V]M;6%N9"A_.3$R+#(S,S8R"DEF0V]M;6%N9"A_-3 W+#$R.#,V"DUAX
M=&A#;VUM86YD*'\V,#4L,34S,C(*4')O;7!T0V]M;6%N9"A_,S$S+#<R,#D*X
M475I=$-O;6UA;F0H?S(U,2PU-C,S"FEN="!296%P0V]M;6%N9"A_,C(V+#4QX
M-38*4F5M;W9E5&EM94]U=$-O;6UA;F0H?S0P,RPQ,#,W-@I3879E4V5S<VEOX
M;D-O;6UA;F0H?S<P,BPQ-S(X-PI3971%;G9#;VUM86YD*'\T-S<L,3(P-#@*X
M4VEG;F%L0V]M;6%N9"A_,C@W+#8S,3@*4VQE97!#;VUM86YD*'\T,C L,3 WX
M-S(*4W1O<F5);G0H?S$R.2PR.#$Y"E-T;W)E4W1R:6YG*'\Q-C(L,S8S.0I3X
M=&]R95-T<FEN9T-O;6UA;F0H?S8U-"PQ-C(P. I3=')I;F=#871#;VUM86YDX
M*'\V-S8L,38V.#8*5&EM94]U=$-O;6UA;F0H?S,W-2PY-#DQ"E=A<FYI;F=#X
I;VUM86YD*'\W-S0L,3DW,C8*5W)I=&5#;VUM86YD*'\R-C8L-3@Y. II    X
                                                             X
end
@eof
set `wc -lwc <xcontrol/TAGS`
if test $1$2$3 != 70891751
then
	echo ERROR: wc results of xcontrol/TAGS are $* should be 70 89 1751
fi

chmod 644 xcontrol/TAGS

echo x - xcontrol/XControl.ad
cat >xcontrol/XControl.ad <<'@EOF'
*Pty*literalMode:	False
*Pty*autoLineWrap:	True
*Pty*saveLines:		48
*Pty*destructiveTab:	False
*Pty*ttyMode:		rows 24 columns 80 \
9600 susp ^z dsusp ^z intr ^c quit ^\\ erase ^H kill ^u swtch ^@ eof ^d \
eol ^@ stop ^s start ^q -parenb -parodd cs8 -cstopb hupcl cread -clocal \
-loblk -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr \
icrnl -iuclc ixon -ixany ixoff -ienqak isig icanon iexten -xcase echo echoe \
echok -echonl -noflsh opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
-ofdel -tostop tab3
*Pty*ignoreNull:	True
*hpterm*parseFile:	PARSEDIR/hpterm.par
*hpterm*fieldAttributes: True
*hpterm*saveScrollRegion:	True
*hpterm*penColors:	Default:Default:red:Default:green:Default:yellow:\
Default:blue:Default:magenta:Default:cyan:Default:black:yellow"
*xterm*parseFile:	PARSEDIR/xterm.par
*xterm*fieldAttributes:	False
*xterm*saveScrollRegion:	True
*xterm*scrollOnOutput:	True
*xterm*numberMapTables:	4
*xterm*cursorFloats:	False
*xterm*scrollDownClear:	True
*xterm*fullScroll:	False
*xterm*cursorKeyScrollRegion:	True
*xterm*eolStick:	True
*xterm*translations:	#override\n\
<ButtonPress>:invokeTranslation(ButtonTranslator)\n\
<ButtonRelease>:invokeTranslation(ButtonReleaseTranslator)\n
!
*closeWindowCommands:	Signal(9);Quit(0);
*remoteDropsAllowed:	True
*dropCommands:		GetDropNumber(1,2);GetDropHost(3);GetDropDirectory(4);\
GetDropType(1,5);GetDropFile(1,6);\
Write("T=",$1," F=",$2," Host ",$3," Dir ",$4," Type ",$5," Name ",$6);
*dropZoneType:		FileEdit
*sigChildCommands:	Reap(1);GetChildPid(2);If($1,"==",$2,"Quit(0)",\
"Abort()")
*childForkCommands:	GetTerminalType(2);SetEnv("TERM",$2);
*saveSessionCommands:	SaveSession();
*startupCommands:	GetWindowSize(1,2);SetEnv("LINES",$1);\
SetEnv("COLUMNS",$2);
@EOF
set `wc -lwc <xcontrol/XControl.ad`
if test $1$2$3 != 431481740
then
	echo ERROR: wc results of xcontrol/XControl.ad are $* should be 43 148 1740
fi

chmod 644 xcontrol/XControl.ad

rm -f /tmp/unpack$$
exit 0