From: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Subject: XControl program and terminal emulator 2/4
Reply-To: gordon@maxwell.uwaterloo.ca (Gordon R. Strachan)
Organization: University of Waterloo
Date: Sun, 24 Jan 1993 03:49:14 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:42 1993
#
# This archive contains:
#	GenTerm/GenTerm.man	GenTerm/GenTermEm.c	
#	GenTerm/GenTermEm.man	GenTerm/LoadParser.c	
#	GenTerm/Makefile	GenTerm/Parser.h	
#	GenTerm/Pty.h		GenTerm/PtyP.h		
#	GenTerm/Xmu.h		xcontrol/Makefile	
#
# Error checking via wc(1) will be performed.

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

echo x - GenTerm/GenTerm.man
sed 's/^@//' >GenTerm/GenTerm.man <<'@EOF'
@.\" Man page for the GenTerm 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 GenTerm 3X
@.SH NAME
\fBGenTerm \- The Generalized terminal widget class.\fP
@.sp 1
@.SH SYNOPSIS
\fB#include "/usr/local/include/GenTerm.h"\fP
@.SH DESCRIPTION
The \fBGenTerm\fP widget is a general terminal widget.  It does not
emulate any specific terminal but rather implements a set of support
functions that any terminal would require.  Widgets emulating specific
terminals can then be built on top of this.
@.PP
The \fBGenTerm\fP widget
presents a window into which text can be written and manipulated.  The
widget supports two simultaneous fonts, but both must be the same size
and fixed space.  The text can be written in a number of different
colours.  In addition, the widget implements an off screen memory to
store text which has scrolled off the visible screen.  Finally, the
widget implements a number of functions for manipulating the text and
for moving the visible screen around the scroll memory.
@.SH CLASSES
GenTerm inherits behavior and resources from \fBCore\fP and
\fBComposite\fP classes.
@.PP
The class pointer is \fBgenTermWidgetClass\fP
@.PP
The class name is \fBGenTerm\fP
@.SH "NEW RESOURCES"
The following table lists the resources recognized by the
\fBGenTerm\fP widget.  The programmer can also set the resources of
the inherited classes.  To set these resources in the resource database
remove the \fBXtN\fP and \fBXtC\fP portions of the resource name.
@.sp 1
@.KS
@.sp 1
@.TS
center;
cB sss
lB lB lB lB
llll.
GenTerm Resource Set
Name	Class	Type	Default
_
XtNalternateFont	XtCAlternateFont	String	7x13bold
XtNautoLineWrap	XtCAutoLineWrap	Boolean	False
XtNbackground	XtCBackground	Pixel	DefaultBackground
XtNbaseFont	XtCBaseFont	String	7x13
XtNblinkRate	XtCBlinkRate	Int	500
XtNbottomMargin	XtCBottomMargin	Dimension	0
XtNcharacterHeight	XtCCharacterHeight	Int	13
XtNcharacterWidgth	XtCCharacterWidth	Int	7
XtNcolumns	XtCColumns	Int	80
XtNcursorColor	XtCCursorColor	Pixel	orange
XtNcursorFloats	XtCCursorFloats	Boolean	True
XtNcursorKeyScrollRegion	XtCCursorKeyScrollRegion	Boolean	False
XtNdefineColor	XtCDefineColor	Int	GTRGB
XtNeolStick	XtCEolStick	Boolean	False
XtNfieldAttributes	XtCFieldAttributes	Boolean	True
XtNforeground	XtCForeground	Pixel	DefaultForeground
XtNfullScroll	XtCFullScroll	Boolean	False
XtNignoreNull	XtCIgnoreNull	Boolean	False
XtNinsertMode	XtCInsertMode	Boolean	False
XtNkbdCallback	XtCKbdCallback	Callback	Null
XtNliteralMode	XtCLiteralMode	Boolean	False
XtNlockCallback	XtCLockCallback	Callback	Null
XtNlockScreen	XtCLockScreen	Boolean	False
XtNmargin	XtCMargin	Int	8
XtNmarginBell	XtCMarginBell	Boolean	False
XtNnumberColors	XtCNumberColors	Int	8
XtNpenColors	XtCPenColors	String	Default:Default
XtNresizeCallback	XtCResizeCallback	Callback	Null
XtNrows	XtCRows	Int	24
XtNsaveLines	XtCSaveLines	Int	512
XtNsaveScrollRegion	XtCSaveScrollRegion	Boolean	False
XtNscrollDownClear	XtCScrollDownClear	Boolean	False
XtNscrollOnOutput	XtCScrollOnOutput	Boolean	False
XtNshowCursor	XtCShowCursor	Boolean	True
XtNtopCallback	XtCTopCallback	Callback	Null
@.TE
@.KE
@.sp 1
@.IP "\fBXtNalternateFont\fP"
This resource specifies the name of the font to use when the alternate
font attribute is in effect.  This is typically used to set a bold
font.  The alternate font must be fixed space and have the same size
as the \fBXtNbaseFont\fP resource.
@.IP "\fBXtNautoLineWrap\fP"
This resource controls the behavior of the cursor when it reaches the
end of the line.  If the resource is \fBTrue\fP then the cursor will
move automatically to the beginning of the next line, forcing a scroll
if necessary.  If the resource is \fBFalse\fP then the cursor will
remain at the end of the line and any new text sent to the widget will
be truncated.
@.IP "\fBXtNbackground\fP"
This resource specifies the background colour to use in the window.
It also specifies the colour to use for a pen whose background colour
was given as \fBDefault\fP.
@.IP "\fBXtNbaseFont\fP"
This resource specifies the name of the font that is normally used.
It must be a fixed space font and have the same size as the
\fBXtNalternateFont\fP resource setting.
@.IP "\fBXtNblinkRate\fP"
This resource specifies the rate at which text which has the blink
attribute set is flashed on the screen.  The time is specified in
milliseconds.
@.IP "\fBXtNbottomMargin\fP"
This resource  specifies the amount of space that is left at the
bottom of the window.  It is typically used to reserve space for
function keys or other visual effects such as a status line.
@.IP "\fBXtNcharacterHeight\fP"
This is a read only resource which returns the height of the currently
used font in pixels.  Any attempt to set this resource will have no
effect.
@.IP "\fBXtNcharacterWidth\fP"
This is a read only resource which returns the width of the currently
used font in pixels.  Any attempt to set this resource will have no
effect.
@.IP "\fBXtNcolumns\fP"
This resource specifies the number of columns to show on the visible
screen.  The window width will be adjust accordingly.
@.IP "\fBXtNcursorColor\fP"
This resource specifies the colour to use for the cursor.
@.IP "\fBXtNcursorFloats\fP"
This resource specifies the behavior of the cursor when the screen is
scrolled.  If the resource is \fBTrue\fP then the cursor floats with
respect to the text.  That is to say, the position of the cursor
relative to the top of the screen remains fixed when a scroll takes
place but the text moves.  With the resource set to \fBTrue\fP the
cursor can not be scrolled off the screen.  If the resource is set to
\fBFalse\fP then the cursor maintains its position relative to the
text.  When a scroll takes place, the cursor position, relative to the
top of the window changes.  With the resource set to \fBFalse\fP, the
cursor can be scrolled off of the visible screen.
@.IP "\fBXtNcursorKeyScrollRegion\fP"
This resource defines the behavior of the cursor keys when a scroll
region is encountered.  If the resource is \fBFalse\fP, then the
cursor keys ignore the scroll region and the cursor can be moved about
as if the scroll region was not defined.  If the resource if
\fBTrue\fP then the cursor keys are sensitive to the scroll region.
In this case, when the cursor encounters the boundary of a scroll
region it behaves as it would if it encountered the boundary of the
physical screen.  It may stick at the edge of the scroll region, wrap
around to the other side or force a scroll depending on the desired
behavior.
@.IP "\fBXtNdefineColor\fB"
This resource specifies how colours are defined through the
\fIGtDefinePenColour\fP function.  If the resource is set to
\fIGTRGB\fP then colour is specified through its red green blue
triplet.  If the resource is set to \fIGTHSL\fP then the colour is
defined by it hue saturation and luminance triplet.
@.IP "\fBXtNeolStick\fB"
This resource specifies the behavior of the cursor when it is put on
the last column.  If it is \fBFalse\fP then the cursor will be brought
to the next line.  If it is \fBTrue\fP then the cursor will stick at
the end of the line until the next character is written.  The cursor
will then move to the next line prior to printing the character.
@.IP "\fBXtNfieldAttributes\fP"
This resource specifies how attributes are associated with characters.
Attributes are modes which affect the way text is displayed such as
embolding, underlining or highlighting.  The widget supports two
attribute modes: normal and field mode.  In normal mode, the character
inherits the attribute that is in effect at the time it is written.
In field attribute, the attributes are written into a section of the
screen.  This is referred to as a field.  The character inherits its
attribute from the field into which it is written.  If the resource is
set to \fBTrue\fP, the field mode is in effect.  Otherwise, the normal
attribute mode is used.
@.IP "\fBXtNforeground\fP"
This resource specifies the colour to use when drawing text with a pen
colour whose foreground is given as \fIDefault\fP.
@.IP "\fBXtNfullScroll\fP"
This resource defines the behavior of the scrolling with in the saved
screen.  If the resource is \fBTrue\fP then the visible screen can be
scrolled through the entire saved screen buffer.  If the resource is
\fBFalse\fP then the visible screen can only be scrolled through the
portion of the saved screen which has saved text.  Areas which have
not yet been accessed will be inaccessible.
@.IP "\fBXtNignoreNull\fP"
This resource defines the behavior of the widget when it is sent a
null character.  If the resource is set to \fBTrue\fP, then the
character is discarded.  If the resource is set to \fBFalse\fP then
the character is translated through the current mapping table and
printed (usually as a space).
@.IP "\fBXtNinsertMode\fP"
This resource controls how new text is placed on the screen.  If the
resource is set to \fBFalse\fP then any text currently on the screen
will be overwritten by the new text if they occupy the same screen
location.  If the resource is set to \fBTrue\fP then the text that
would have over written is pushed behind the inserted text.  The
behavior of the moved text when it encounters the end of the line is
controlled by the \fBXtNautoLineWrap\fP resource.
@.IP "\fBXtNkbdCallback\fP"
This resource specifies the list of callback function to call when
ever a key press is encountered or an insert action takes place.  The
reason will be set to \fBGT_INPUT\fP if a key press event happened or
\fBGT_PASTE\fP if an insert action occurred.
@.IP "\fBXtNliteralMode\fP"
This resource controls the displaying to non displayable characters.
If the resource is \fBFalse\fP then all non displayable characters are
processed through the normal mapping table and printed.  If the
resource is \fBTrue\fP then non displayable characters are displayed
as a \fI^C\fP sequence.
@.IP "\fBXtNlockCallback\fP"
This resource specifies the list of callback functions to call when
the lock state of the widget changes.  The lock state changes when
either the resource \fBXtNlockScreen\fP is changed or the widget needs
to freeze the screen pending some internal events.  An example is
selecting text with the mouse.  The callback is called with a reason
of \fBGT_LOCK\fP.
@.IP "\fBXtNlockScreen\fP"
This resource defines whether the screen is locked or not.  Usually
this resource is controlled by the widget itself but it may also be
set by external applications.  If the resource is \fBTrue\fP, then the
widget will refuse to perform any action that will alter the
appearance of the text on the screen.  When the lock state changes,
the widget will invoke the \fBXtNlockCallback\fP call backs.  Note
that the widget may alter the value of this resource at any time.
@.IP "\fBXtNmargin\fP"
This resource defines the size of the righthand margin.  When the cursor
crosses into the righthand margin then the margin bell will sound
providing the \fBXtNmarginBell\fP resource is set.
@.IP "\fBXtNmarginBell\fP"
This resource specifies whether the widget should sound the margin
bell when the cursor enters the righthand margin.  If the resource is
set to \fBTrue\fP then the bell will sound, otherwise it will not.
@.IP "\fBXtNnumberColors\fP"
This resource defines how many unique pens can be defined.  A pen is
a foreground and background colour combination and is part of the text
attribute.
@.IP "\fBXtNpenColors\fP"
This resource defines the colours of the pens.  The format is a colon
separated list of valid colour names or the keyword \fIDefault\fP.  If
the colour is specified as \fIDefault\fP then either the widget's
current foreground or background colour will be substituted as
appropriate.  For each pen, two colours must be specified, the
foreground followed by the background.  Therefore the pen colour list
should contain 2 * n colours where n is the value of the
\fBXtNnumberColors\fP resource.  If not enough colours are specified
then the remaining pens will use the default colours.
@.IP "\fBXtNresizeCallback\fP"
This resource specifies the list of callback functions to call when
ever the widget resizes itself.  The reason for the callback will be
set to \fIGT_RESIZE\fP.
@.IP "\fBXtNrows\fP"
This resource specifies the number of rows of text to be shown in the
window.  The widget will be sized accordingly.
@.IP "\fBXtNsaveLines\fP"
This resources defines how many rows of text are to be stored in the
off screen memory.  This area is for saving text so that it can be
scrolled back onto the screen.  The value of this resource must be at
least as big as the value of \fBXtNrows\fP.
@.IP "\fBXtNsaveScrollRegion\fP"
This resource specifies the behavior of the widget when scrolling
takes place inside of a scroll region.  If it is set to \fBTrue\fP
then text that is scrolled out of the scroll region is stored in the
off screen memory.  If the value is \fBFalse\fP then the text is
discarded.  Note that text will be saved in the proper order but that
this order will no longer make sense once the scroll region is removed
or changed.
@.IP "\fBXtNscrollDownClear\fP"
This resource defines the behavior of the widget when is scrolls down
one line as the result of new text (as opposed to cursor movement or
changing the top of screen).  If the resource is \fBTrue\fP then the
new line will be cleared prior to being brought into the visible
screen.  If it is \fBFalse\fP then any text on the new line remains in
it when the text is brought onto the screen.
@.IP "\fBXtNscrollOnOutput\fP"
This resource controls the behavior of the widget when new text is
output to the screen.  If the resource is set to \fBTrue\fP and the
last line of text is currently not on the visible screen, then the
widget forces a scroll until the last line becomes visible.  The text
is then placed at the current cursor position.  If the resource is
\fBFalse\fP, then the text is simply placed at the current cursor
position.
@.IP "\fBXtNtopCallback\fP"
This resource specifies the list of callback functions to call when
ever the widget changes the position of the top line of the visible
screen in relation to the saved screen.  This typically takes place
when a scroll occurs.  In the callback the reason will be set to
\fIGT_TOP\fP.
@.sp 1
@.SH "CALLBACK INFORMATION"
A pointer to the following structure is passed to each callback:
@.sp .5
@.nf
@.ta .25i 1.1i
\fBtypedef struct\fP
{
	\fBint\fP	\fIreason\fP;
	\fBXEvent\fP	\fI* event\fP
	\fBint\fP	\fITopLine\fP;
	\fBint\fP	\fIRows\fP;
	\fBint\fP	\fIColumns\fP;
	\fBint\fP	\fISave\fP;
	\fBchar\fP	\fI* Selection\fP;
	\fBint\fP	\fIValue\fP;
} \fBGenTermCallback\fP;
@.fi
@.sp .5
@.IP "\fIreason\fP"
Indicates why the callback was called.
@.IP "\fIevent\fP"
Points to the \fBXEvent\fP structure which triggered this callback.
The value is defined on if \fIreason\fP is equal to \fBGT_INPUT\fP
@.IP "\fITopLine\fP"
Indicates the position of the top line of the screen is in the virtual
screen.  Its value ranges from 0 to \fBXtNsaveLine\fP.  It defined
only if the reason is \fBGT_TOP\fP.
@.IP "\fIRows\fP"
Indicates the current number of rows in the visible screen.  This
value is defined only if the reason is \fBGT_RESIZE\fP.
@.IP "\fIColumns\fP"
Indicates the current number of columns in the visible screen.  This
value is defined only if the reason is \fBGT_RESIZE\fP.
@.IP "\fISave\fP"
Indicates the number of rows that can be saved in the virtual screen.
This value is defined only if the reason is \fBGT_RESIZE\fP.
@.IP "\fISelection\fP"
Points to the text was pasted by an insert selection action.  This
value is defined if the reason is \fBGT_PASTE\fP.
@.IP "\fIValue\fP"
If reason is \fBGT_LOCK\fP then \fIValue\fP is the current value of
the lock setting.
@.SH "TRANSLATIONS"
The \fIGenTerm\fP widget has the following default translations:
\fB
@.nf
@.ta 1.8i
@.sp 0.5
<KeyPress>:	input()
<Expose>:	expose()
<GraphicsExpose>:	expose()
<NoExpose>:	noexpose()
<Btn1Down>:	StartSelection()
<Btn1Motion>:	ExtendSelection()
<Btn1Up>:	MakeSelection(PRIMARY,CUT_BUFFER0)
<Btn2Up>:	InsertSelection(PRIMARY)
@.fi
\fP
@.SH "ACTIONS"
The \fIGenTerm\fP action routines are:
@.IP "\fBinput()\fP"
Invokes the \fBXtNkbdCallback\fP with a reason of \fBGT_INPUT\fP and
the event field pointing to the event that caused this action.
@.IP "\fBexpose()\fP"
Causes the widget to redraw part of its screen.  If this action was
caused by a graphics expose event then the exposure count will be
decremented.
@.IP "\fBExtendSelection()\fP"
Alters the highlighted section on the screen to track the mouse
motion.
@.IP "\fBInsertSelection(Source)\fP"
Inserts text from the specified source.  \fBSource\fP and be any of
\fIPRIMARY\fP, \fISECONDARY\fP or \fICUT_BUFFERn\fP where n is an
integer from 0 to 7.  You can specify multiple sources in which case
the action takes the text from the first source that contains text.
The action then invokes a \fIXtNkbdCallback\fP with a reason of \fBGT_PASTE\fP.
@.IP "\fBMakeSelection(Destinations...)\fP"
The selected region is copied into an internal buffer, the selected
area is unhighlighted and the widget unlocks itself.  If the
\fIDestination\fP is \fBPRIMARY\fP or \fBSECONDARY\fP, then the
selection is copied into the appropriate X selection.  If
\fIDestination\fP is of the form \fBCUT_BUFFERn\fP where n is a number
from 0 to 7, then the selection is copied into the appropriate cut
buffer.  Multiple destinations can be specified.
@.IP "\fBnoexpose()\fP"
Causes the widget to decrement its internal exposure count.
@.IP "\fBoutput(String)\fP"
The argument of the action is sent to the widget and show on the
screen.
@.IP "\fBStartSelection()\fP"
Causes the widget to start a mouse selection.  It sets the starting
point for the selected region.  The widget is locked to
allow the selection to complete.
@.sp 1
@.SH "ENTRY POINTS"
In addition to the normal widget functions the GenTerm widget also
contains the following functions which can be called from the
application program.
@.ta .2i 1.2i
@.\"
@.IP "\fBint GtClearMemory(Term,Which)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tWhich\fP
@.fi
@.sp
This function clears data from the screen save memory.  \fBTerm\fP is
the widget instance record.  \fBWhich\fP specifies which memory is be
cleared.  If \fBWhich\fP is equal to 1, then all data saved below the
visible screen is deleted.  If \fBWhich\fP is equal to 2 then all data
saved above the visible screen is deleted.  In both case, the data on
the visible screen is not affected.  If \fBWhich\fP is equal to 0,
then the entire memory is cleared and the visible screen is also
cleared.  The function returns \fIGTGOOD\fP if the request completed
successfully of \fIGTLOCKED\fP if the widget is currently locked.  In
this case the calling routine should try again later.
@.\"
@.IP "\fBint GtClearRegion(Term,StartRow,StartColumn,EndRow,EndColumn)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tStartRow
\tint\tStartColumn
\tint\tEndRow
\tint\tEndColumn\fP
@.fi
@.sp
This function clears a rectangular region on the visible screen.
\fBTerm\fP is the widget instance record.  \fBStartRow\fP and
\fBStartColumn\fP specify of the upper left corner of the rectangle
while \fBEndRow\fP and \fBEndColumn\fP specify the lower right corner.
If any of the coordinates fall outside of the visible screen then they
are truncated to the nearest edge.  The function returns \fIGTGOOD\fP
if the request completed successfully or \fIGTLOCKED\fP if the widget
is currently locked.  In this case the request is not performed and
the calling routine should try again later.
@.\"
@.IP "\fBint GtCursorDown(Term,Dist,WrapType)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tDist
\tint\tWrapType\fP
@.fi
@.sp
This function moves the current cursor position down \fBDist\fP lines.
\fBTerm\fP is the widget instance record.  \fBDist\fP is the number of
lines to move the cursor down.  \fBWrapType\fP controls the behavior
of the widget
when the cursor hits the bottom of the screen.  If \fBWrapType\fP is
equal to \fI0\fP then the screen is scrolled up the required number of
lines.  If \fBWrapType\fP is equal to \fI1\fP then, when the cursor
encounters the bottom of the screen, it will wrap around to the top.
Finally, if \fBWrapType\fP is equal to \fI2\fP, then the cursor will
stop and stick at the bottom of the screen.  The function returns
\fIGTGOOD\fP if the request completed successfully.  It returns
\fIGTLOCKED\fP is the widget is currently locked.  In this case the
request is not performed and the calling routine should try again
later.
@.\"
@.IP "\fBint GtCursorLeft(Term,Dist,WrapType,RollType)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tDist
\tint\tWrapType
\tint\tRollType\fP
@.fi
@.sp
This function moves the current cursor position \fBDist\fP spaces to
the left.  \fBTerm\fP is the widget instance record.  \fBDist\fP is
the number of spaces to move the cursor.  \fBWrapType\fP controls the
behavior of the widget when the cursor encounters the leftmost
column of the screen.  If \fBWrapType\fP is equal to \fI0\fP then the
cursor will stick in the leftmost column.  If \fBWrapType\fP is equal
to \fI1\fP then the cursor will move to the rightmost column on the
previous line.  \fBRollType\fP defines the behavior of the widget
when the cursor is on the leftmost column of the top line.  If
\fBRollType\fP is equal to \fI0\fP, then the cursor will move to the
rightmost column of the bottom line.  If \fBRollType\fP is equal to
\fI1\fP then the screen will be scrolled down and the cursor will move
to the rightmost position on the previous line.  The function returns
\fIGTGOOD\fP if the request completed successfully.  It returns
\fIGTLOCKED\fP if the widget is currently locked.  In this case the
request is not performed and the calling routine should try again
later.
@.\"
@.IP "\fBint GtCursorReturn(Term)\fP"
@.sp
@.nf
\fB\tWidget\tTerm\fP
@.fi
@.sp
This function returns the current cursor position to the leftmost
column on the current line.  \fBTerm\fP is the widget instance record.
The function returns \fIGTGOOD\fP if the request completed
successfully.  It returns \fIGTLOCKED\fP if the widget is locked.  In
this case the current position is not changed and the calling routine
should try again later.
@.\"
@.IP "\fBint GtCursorRight(Term,Dist,WrapType,RollType)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tDist
\tint\tWrapType
\tint\tRollType\fP
@.fi
@.sp
This function moves the current cursor position \fBDist\fP spaces to
the right.  \fBTerm\fP is the widget instance record.  \fBDist\fP is
the number of spaces move the cursor.  \fBWrapType\fP controls
the behavior of the widget when the cursor encounters the rightmost
column of the screen.  If \fBWrapType\fP is equal to \fI0\fP then the
cursor will stick in the rightmost column.  If \fBWrapType\fP is equal
to \fI1\fP then the cursor will move to the leftmost column on the
next line.  \fBRollType\fP defines the behavior of the widget when
the cursor is on the rightmost column of the bottom line.  If
\fBRollType\fP is equal to \fI0\fP, then the cursor will move to the
leftmost column of the first line.  If \fBRollType\fP is equal to
\fI1\fP then the screen will be scrolled up and the cursor will move
to the leftmost column on the next line.  The function returns
\fIGTGOOD\fP if the request completed successfully.  It returns
\fIGTLOCKED\fP if the widget is currently locked.  In this case the
request is not performed and the calling routine should try again later.
@.\"
@.IP "\fBint GtCursorUp(Term,Dist,WrapType)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tDist
\tint\tWrapType\fP
@.fi
@.sp
This function moves the current cursor position up \fBDist\fP lines.
\fBTerm\fP is the widget instance record.  \fBDist\fP is the number of
lines to move the cursor up.  \fBWrapType\fP controls the behavior of
the widget when the cursor encounters the top of the screen.  If
\fBWrapType\fP is equal to \fI0\fP then the screen is scrolled down
the required number of lines.  If \fBWrapType\fP is equal to \fI1\fP
then when the cursor encounters the top of the screen it will wrap
around to the bottom.  If \fBWrapType\fP is equal to \fI2\fP then
cursor will stop and stick at the top of the screen.  The function
returns \fIGTGOOD\fP if the request completed successfully.  It
returns \fIGTLOCKED\fP if the widget is currently locked.  In this
case the request is not performed and the calling routine should try
again later.
@.\"
@.IP "\fBint GtDefinePenColour(Term,Pen,FRed,FGreen,FBlue,BRed,BGreen,BBlue)\fP"
@.sp 
@.nf
\fB\tWidget\tTerm
\tint\tPen
\tfloat\tFRed
\tfloat\tFGreen
\tfloat\tFBlue
\tfloat\tBRed
\tfloat\tBGreen
\tfloat\tBBlue\fP
@.fi
@.sp
This function defines the foreground and background colour of a
specified pen. \fBTerm\fP is the widget instance record.  \fBPen\fP is
the number of the pen to define the colour for.  If \fBPen\fP is not
with in the range of 0 to \fBXtNnumberColors\fP - 1, then its value
will be adjusted.  \fBFRed\fP, \fBFGreen\fP and \fBFBlue\fP are the
RGB values of the foreground colours.  The values are ranges between 0
and 1.  If the resource \fBXtNdefineColor\fP is equal to \fIGTHSL\fP
then these values are the hue saturation and luminous values of the
foreground colour.  Similarly, \fBBRed\fP, \fBBGreen\fP and
\fBBBlue\fP specify the RGB (or HSL) values of the background colour.
The function always returns the value \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtDeleteCharacters(Term,Num)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tNum\fP
@.fi
@.sp
This function deletes a number of characters from the current row
starting at the current position.  \fBTerm\fP is widget instance
record and \fBNum\fP is the number of characters to delete.  The
characters to the right of the deleted characters are moved left
\fBNum\fP positions.  The function returns \fIGTGOOD\fP if the request
completed successfully or \fIGTLOCKED\fP if the widget is currently locked.
@.\"
@.IP "\fBint GtDeleteLines(Term,Num)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tNum\fP
@.fi
@.sp
This function deletes a number of lines from the visible screen
starting at the current row.  \fBTerm\fP is the widget instance
record.  \fBNum\fP is the number of lines to delete.  When lines are
deleted, the lines below them are pushed up on the screen.  Any data
saved in the screen memory below the visible screen are scrolled onto
the screen.  If there is no data in the memory then blank lines are
pushed onto the bottom.  The function returns \fIGTGOOD\fP if the
request completed successfully and \fIGTLOCKED\fP if the widget is
currently locked.
@.\"
@.IP "\fBint GtInsertLines(Term,Row,Num)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tRow
\tint\tNum\fP
@.fi
@.sp
This function inserts a number of blank lines at a given position on
the visible screen.  \fBTerm\fP is the widget instance record.
\fBRow\fP is the row on the screen to insert the lines at.  \fBNum\fP
is the number of blank lines to insert.  All lines below \fBRow\fP are
pushed down.  Any lines pushed off of the visible screen are stored in
the screen memory.  The function returns \fIGTBAD\fP if \fBRow\fP is not in
the visible screen, \fIGtGOOD\fP if the request completed successfully
and \fIGTLOCKED\fP if the widget is currently locked.
@.\"
@.IP "\fBint GtGetAttribute(Term,Attribute,Value)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tAttribute
\tint *\tValue\fP
@.fi
@.sp
This function returns the current setting of a specific attribute.
\fBTerm\fP is the widget instance record.  \fBAttribute\fP specifies
the attribute to return the value of.  Valid values are: \fIGTFONT\fP,
\fIGTINVERSEVIDEO\fP, \fIGTUNDERLINE\fP, \fIGTHALFBRIGHT\fP,
\fIGTBLINKMODE\fP or \fIGTPEN\fP.  Upon return, \fBValue\fP will
contain the current setting of the attribute.  See the entry point
\fBGtSetAttribute\fP for a list of values \fBValue\fP can take on.
The function always returns the value \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtGetCursorPosition(Term,Row,Column)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint *\tRow
\tint *\tColumn\fP
@.fi
@.sp
This function returns the row and column numbers of the current cursor
position.  The topmost line is row 0 and the leftmost column is column
0.  \fBTerm\fP is the widget instance record.  \fBRow\fP and
\fBColumn\fP are pointers to integers in which the row and column
positions will be returned.  The function always returns a value of
\fIGTGOOD\fP.
@.\"
@.IP "\fBint GtGetLine(Term,Row,String,Len)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tRow
\tchar *\tString
\tint *\tLen\fP
@.fi
@.sp
This function gets the characters that are currently stored in a
specified row.  \fBTerm\fP is the widget instance record.  \fBRow\fP
is the number of the row in the visible screen to get the characters
from.  \fBRow\fP can have a value ranging from \fI0\fP to
\fBXtNRows\fP - 1.  \fBString\fP is the address of where to store the
characters.  The calling routine is responsible for ensuring there is
enough space to store the data in.  \fBLen\fP is a pointer to an
integer to return the number of characters put into \fBString\fP.  The
function returns \fIGTBAD\fP if \fBRow\fP contained an invalid value
and \fIGTGOOD\fP otherwise.
@.\"
@.IP "\fBint GtGetMapTable(Term,Table)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tchar\tTable[NMAP]\fP
@.fi
@.sp
This function returns a copy of the current output mapping table.  The
mapping table defines the translation table that is used for printing
ascii characters.  Each character is used as an offset into the table.
The value stored at that position will be the character that is
printed.  \fBTerm\fP is the widget instance record.  Upon return
\fBTable\fP contains a copy of the current table.  The function always
returns \fIGTGOOD\fP
@.\"
@.IP "\fBint GtGetScreenSize(Term,Row,Column)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint *\tRow
\tint *\tColumn\fP
@.fi
@.sp
This function returns the number of rows and columns currently in the
visible screen.  \fBTerm\fP is the widget instance record.  Upon
return \fBRow\fP contains the number of rows and \fBColumn\fP contains
the number of columns in the visible screen.  The function always
returns \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtGetScrollRegion(Term,Id,Start,End)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tId
\tint *\tStart
\tint *\tEnd\fP
@.fi
@.sp
This function returns the starting and ending rows of a specific
scroll region.  \fBTerm\fP is the widget instance record.  \fBId\fP is
scroll region identifier corresponding to the scroll region to return.
\fBStart\fP and \fBEnd\fP will contain the starting and end rows of
the scroll region upon returning from the function.  If the scroll
region is not currently defined then \fBStart\fP will have a value of
\fI-1\fP.  The function always returns a value of \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtGetTopOfScreen(Term)\fP"
@.sp
@.nf
\fB\tWidget\tTerm\fP
@.fi
@.sp
This function returns the position of the top line of the screen in
the virtual save screen.  It returns a value between 0 (the top of the
save screen) and \fBXtNsaveLines\fP - \fBXtNrows\fP (the bottom of the
save screen).  \fBTerm\fP is the widget instance record.
@.\"
@.IP "\fBint GtLoadAttribute(Term,Row,Column)\fP"
@.sp
@.nf
\fBWidget\tTerm
\tint\tRow
\tint\tColumn\fP
@.fi
@.sp
This function sets the current attribute to match those of the
character at position \fBRow\fP,\fBColumn\fP.  \fBTerm\fP is the
widget instance record.  \fBRow\fP and \fBColumn\fP is the character
position to copy the attributes from.  If the position is invalid or
specifies a point that is not in the visible screen then the default
attributes are loaded.  The function always returns \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtMarginBell(Term)\fP"
@.sp
@.nf
\fB\tWidget\tTerm\fP
@.fi
@.sp
This function tests whether the margin bell should be rung.  If the
answer is yes then it rings the bell.  \fBTerm\fP is the widget
instance record.  The function always returns a value of \fIGTGOOD\fP.
@.IP "\fBint GtNewLine(Term,Num)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tNum\fP
@.fi
@.sp
This function causes the current cursor position to move down
\fBNum\fP lines.  If this would cause the cursor to move off the
bottom of the screen, a scroll is performed.  \fBTerm\fP is the widget
instance records and \fBNum\fP is the number of lines to move down.
The function returns \fIGTGOOD\fP if the request completed
successfully.  It returns \fIGTLOCKED\fP if the widget is currently
locked.  In this case, the request is not performed and the calling
routine should try again later.
@.IP "\fBint GtOutput(Term,String,Len)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tchar *\tString
\tint\tLen\fP
@.fi
@.sp
This is the main output routine for the widget.  \fBTerm\fP is the
widget instance record.  \fBString\fP is a pointer to a character
string and \fBLen\fP is the number of characters in the string.  This
function stores the string in the screen array at the cursor current
cursor position.  If this is in the visible screen then the string
will be printed.  The characters are stored with the current
attributes, if \fBXtNfieldAttributes\fP is \fIFalse\fP.  Otherwise,
the field attributes already in the screen array are used.  If
\fBXtNliteralMode\fP is \fIFalse\fP then the characters in
\fBString\fP are translated using the current mapping table prior to
being stored.  If \fBXtNliteralMode\fP is \fITrue\fP, then any
nondisplayable characters are are printed aS a \fI^\fP character
followed by the character with its seventh bit set.  The function
returns \fIGTGOOD\fP if the string was successfully stored.  The
function returns \fIGTLOCKED\fP if the widget is currently locked.  In
this case, the string was not saved and the caller should try again
later after receiving an \fBXtNlockCallback\fP.
@.\"
@.IP "\fBint GtPositionToRowColumn(Term,X,Y,Row,Column)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tDimension\tX
\tDimension\tY
\tint *\tRow
\tint *\tColumn\fP
@.fi
@.sp
This function takes an \fB(X,Y)\fP position, such as those returned by
an XEvent and converts it to its equivalent \fBRow\fP and \fBColumn\fP
with in the visible screen.  \fBTerm\fP is the widget instance record.
\fBX\fP and \fBY\fP is the position coordinate relative to the top
left of the widget's window.  \fBRow\fP and \fBColumn\fP are pointers
to integers in which the result will be stored.  The function always
returns the value \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtSetCursorPosition(Term,Row,Column)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tRow
\tint\tColumn\fP
@.fi
@.sp
This function sets the cursor position.  \fBTerm\fP is the widget
instance record.  \fBRow\fP and \fBColumn\fP are the row and column
numbers of the new cursor position.  Row 0 is the top row of the screen
and column 0 is the leftmost column.  If either the row of column are
outside the visible screen then the cursor position will be set to the
closest point that is still inside the screen.  The function returns
\fIGTGOOD\fP if the request was completed and \fIGTLOCKED\fP if the
widget is currently locked.  In the latter case, the request is not
performed and the calling routine should try again later.
@.\"
@.IP "\fBint GtSetAttribute(Term,Attribute,Value)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tAttribute
\tint\tPosition\fP
@.fi
@.sp
This function sets the value of one of the attributes of the current
text attribute.  \fBTerm\fP is the widget instance record.
\fBAttribute\fP specifies which attribute's value is to be altered.
Valid values are: \fIGTFONT\fP, \fIGTINVERSEVIDEO\fP,
\fIGTUNDERLINE\fP, \fIGTHALFBRIGHT\fP, \fIGTBLINKMODE\fP or
\fIGTPEN\fP.  If \fBAttribute\fP is equal to \fIGTFONT\fP and
\fBValue\fP is equal to \fIGTBASE\fP then the normal font is set for
the current attribute.  If \fBValue\fP is equal to \fIGTALTERNATE\fP
then the current font is set to the alternate font.  If
\fBAttribute\fP is equal to \fIGTINVERSEVIDEO\fP and \fBValue\fP is equal
to \fIGTINVERSE\fP then the current foreground and background colours
are swapped.  If \fBValue\fP is equal to \fIGTNORMAL\fP then the
foreground and background correspond to the specified foreground and
background colours.  If \fBAttribute\fP is equal to \fIGTUNDERLINE\fP
and \fBValue\fP is equal to \fIGTON\fP then all text will be
underlined as it is printed.  If \fBValue\fP is equal to \fIGTOFF\fP
then all text is written as normal.  If \fBAttribute\fP is equal to
\fIGTHALFBRIGHT\fP and \fBValue\fP is equal to \fIGTON\fP then the
current default background colour is altered so that the difference in
luminance between the foreground and background colours is
approximately half the default value.  If \fBValue\fP is equal to
\fIGTOFF\fP then the normal default background colour is used.  If
\fBAttribute\fP is equal to \fIGTBLINKMODE\fP and \fBValue\fP is equal
to \fIGTON\fP then the blink attribute is set.  All text written with
this attribute will be flashed on the screen one and off.  If
\fBValue\fP is equal to \fIGTOFF\fP, then the blink attribute is
reset.  If \fBAttribute\fP is equal to \fIGTPEN\fP then the pen number
of the attribute is set.  \fBValue\fP specifies the pen number to use
and should be in the range of 0 to the \fINumberColors\fP resource.
The pen number defines the normal default foreground and background
colour pair.  An attribute remains in effect until it is explicitly
reset.  Multiple resources (such as bold and underline) can be
specified by multiple calls to this function.  If \fBValue\fP does not
contains a valid value for the given value of \fBAttribute\fP then the
request is ignored.  The function always
returns a value of \fIGTGOOD\fP.
@.\"
@.IP "\fBint GtSetFieldAttribute(Term)\fP"
@.sp
@.nf
\fB\tWidget\tTerm\fP
@.fi
@.sp
This function copies the current attribute settings through out the current
field.  As a side effect, it may also create a new field.  A field is
a section of text on the screen which have the same attributes.  When
text is written onto the screen it inherits its resources from the
field it is written into and not the current settings.  If the current
cursor position is at the beginning of a defined field, then the
attribute is set through out that field.  If the current cursor
position is inside a currently defined field then the current field is
truncated to the position immediately to the left of the current
position.  A new field is then defined from the current position to
the end of the old field.  The current attribute is copied into this
new field.  Initially, each line contains one field extending from the
first to the last column.  The function sets the attributes only if the
\fBFieldAttributes\fP resource is \fITrue\fP, otherwise a value of
\fIGTBAD\fP is returned.  The function returns a value of \fIGTGOOD\fP
if it succeeded to set the attributes and a value of \fIGTLOCKED\fP if
the screen is currently locked.
@.\"
@.IP "\fBint GtSetMapTable(Term,Table)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tchar\tTable[NMAP]\fP
@.fi
@.sp
This function defines the output mapping table to use. The
mapping table defines the translation table that is used printing
ascii characters.  Each character is used as an offset into the table.
The value stored at that position will be the character that is
printed.  \fBTerm\fP is the widget instance record.
\fBTable\fP is the new mapping table.  The function always returns \fIGTGOOD\fP
@.\"
@.IP "\fBint GtSetScrollRegion(Term,Start,End,Id)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tStart
\tint\tEnd
\tint\tId\fP
@.fi
@.sp
This function enable a scroll region within a certain portion of the
visible screen.  \fBTerm\fP is the widget instance record.
\fBStart\fP and \fBEnd\fP specify the starting and end rows of the
scroll region.  \fBId\fP the identify to assign to the scroll region.
It should not be the same as any other currently defined scroll region
unless you are overwritting that scroll region.  The function returns
\fIGTBAD\fP if either the starting or ending rows are invalid.  It
returns \fIGTGOOD\fP if the request completed successfully.
@.\"
@.IP "\fBint GtSetTopOfScreen(Term,Position)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tint\tPosition\fP
@.fi
@.sp
This function sets the position of the visible screen within the
virtual screen save area.  \fBTerm\fP is the widget instance record.
\fBPosition\fP is the position the top line of the visible screen
should have in the save screen.  Its value can range from 0 (the top
of the save screen) to \fBXtNsaveLines\fP - \fBXtNrows\fP (the bottom
of the save screen).  If \fBPosition\fP is not within this range then
its value will be adjusted accordingly.  The function returns
\fIGTGOOD\fP if the request completed normally or \fIGTLOCKED\fP if
the widget is currently locked.  In the latter case, the request is
not performed and the calling routine should try again later.
@.sp 1
@.SH "RELATED INFORMATION"
\fBCore(3X)\fP, \fBComposite(3X)\fP
@EOF
set `wc -lwc <GenTerm/GenTerm.man`
if test $1$2$3 != 953611640490
then
	echo ERROR: wc results of GenTerm/GenTerm.man are $* should be 953 6116 40490
fi

chmod 644 GenTerm/GenTerm.man

echo x - GenTerm/GenTermEm.c
cat >GenTerm/GenTermEm.c <<'@EOF'
/* GenTermEm -- A generalized terminal emulator 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 <ctype.h>
#include <fcntl.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/Shell.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include "GenTermEmP.h"
#include "Parser.h"

extern GenTermClassRec genTermClassRec;

extern struct InputArguments *GtEPushArgs();
extern void GtEPopArgs();

static XtResource resources[] = {
 {XtNwidth,XtCWidth,XtRDimension,sizeof(Dimension),
  XtOffset(GenTermEmWidget,core.width),XtRImmediate,(caddr_t)(7*80)},
 {XtNheight,XtCHeight,XtRDimension,sizeof(Dimension),
   XtOffset(GenTermEmWidget,core.height),XtRImmediate,(caddr_t)(13*24)},
 {XtNname,XtCName,XtRString,sizeof(char *),
   XtOffset(GenTermEmWidget,genTermEm.name),XtRString,"term0"},
 {XtNparseFile,XtCParseFile,XtRString,sizeof(char *),
   XtOffset(GenTermEmWidget,genTermEm.ParseFile),XtRString,"./hpterm.par"},
 {XtNshowFunction,XtCShowFunction,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermEmWidget,genTermEm.ShowKey),XtRImmediate,(caddr_t)FALSE},
 {XtNfunctionSize,XtCFunctionSize,XtRDimension,sizeof(Dimension),
   XtOffset(GenTermEmWidget,genTermEm.FuncKeyHeight),XtRImmediate,(caddr_t)39},
 {XtNfunctionLabelWidth,XtCFunctionLabelWidth,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.FuncLabelWidth),XtRImmediate,(caddr_t)8},
 {XtNnumberFunctionKeys,XtCNumberFunctionKeys,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.NumberFunctionKeys),XtRImmediate,
   (caddr_t)8},
 {XtNoutputFile,XtCOutputFile,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.OutputDescriptor),XtRImmediate,
   (caddr_t)-1},
 {XtNlogging,XtCLogging,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermEmWidget,genTermEm.Logging),XtRImmediate,(caddr_t)False},
 {XtNlogFile,XtCLogFile,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.LogFileDescriptor),XtRImmediate,
   (caddr_t)-1},
 {XtNdestructiveTab,XtCDestructiveTab,XtRBoolean,sizeof(Boolean),
   XtOffset(GenTermEmWidget,genTermEm.DestructiveTab),XtRImmediate,
   (caddr_t)TRUE},
 {XtNkbdCallback,XtCKbdCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermEmWidget,genTermEm.KbdCallbacks),XtRCallback,(caddr_t)NULL},
 {XtNescCallback,XtCEscCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermEmWidget,genTermEm.EscCallbacks),XtRCallback,(caddr_t)NULL},
 {XtNwakeUpCallback,XtCWakeUpCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermEmWidget,genTermEm.WakeUpCallbacks),XtRCallback,
   (caddr_t)NULL},
 {XtNflowCallback,XtCFlowCallback,XtRCallback,sizeof(caddr_t),
   XtOffset(GenTermEmWidget,genTermEm.FlowCallbacks),XtRCallback,(caddr_t)NULL},
 {XtNnumberMapTables,XtCNumberMapTables,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.NumMapTables),XtRImmediate,(caddr_t)1},
 {XtNnumberStorageArguments,XtCNumberStorageArguments,XtRInt,sizeof(int),
   XtOffset(GenTermEmWidget,genTermEm.NumStoreArgs),XtRImmediate,(caddr_t)20},
 {XtNpreScroll,XtCPreScroll,XtCBoolean,sizeof(Boolean),
   XtOffset(GenTermEmWidget,genTermEm.PreScroll),XtRImmediate,(caddr_t)False},
 {XtNscrollChar,XtCScrollChar,XtRUnsignedChar,sizeof(unsigned char),
   XtOffset(GenTermEmWidget,genTermEm.ScrollChar),XtRImmediate,(caddr_t)'\n'},
 {XtNscrollAbortChar,XtCScrollAbortChar,XtRUnsignedChar,sizeof(unsigned char),
   XtOffset(GenTermEmWidget,genTermEm.ScrollAbortChar),XtRImmediate,
   (caddr_t)'\033'},
 };

static void GtEClassInitialize();
static void GtEInput();
int GtEOutput();
static void GtEOutputAction();
static void GtEInvokeTranslation();
static void GtEInitialize();
static void GtERealize();
static void GtERealizeFunctionKeys();
static void GtEDestroy();
static void GtEResize();
static Boolean GtESetValues();
static void GtEDestroyFunctionKeys();
static void GtEOutputDescriptorCallBack();
static XtGeometryResult GtEGeometryManager();
static int GtEFunctionKeyPress();
static void GtEAWaitGraphicsExpose();
static void GtEInsertSelection();
static void GtEInsertCallback();
static void GtELockCallback();
static void GtEAddToStorage();
static void GtEPreScroll();
static Boolean GtEGetClassParseFile();

static XtActionsRec actions[] = {
 {"input",GtEInput},
 {"output",GtEOutputAction},
 {"invokeTranslation",GtEInvokeTranslation},
 {"awaitgraphicsexpose",GtEAWaitGraphicsExpose},
 {"InsertSelection",GtEInsertSelection},
};

static char translations[] =
"\
<KeyPress>:input()\n\
<Expose>:expose()\n\
<GraphicsExpose>:expose() awaitgraphicsexpose()\n\
<NoExpose>:noexpose() awaitgraphicsexpose()\n\
<Btn1Down>:StartSelection()\n\
<Btn1Motion>:ExtendSelection()\n\
<Btn1Up>:MakeSelection(PRIMARY,CUT_BUFFER0)\n\
<Btn2Up>:InsertSelection(PRIMARY,CUT_BUFFER0)\n\
";

GenTermEmClassRec genTermEmClassRec =
{
 {  /* core fields */
    /* superclass               */      (WidgetClass) &genTermClassRec,
    /* class_name               */      "GenTermEm",
    /* widget_size              */      sizeof(GenTermEmRec),
    /* class_initialize         */      GtEClassInitialize,
    /* class_part_initialize    */      NULL,
    /* class_inited             */      FALSE,
    /* initialize               */      GtEInitialize,
    /* initialize_hook          */      NULL,
    /* realize                  */      GtERealize,
    /* 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                  */      GtEDestroy,
    /* resize                   */      GtEResize,
    /* expose                   */      XtInheritExpose,
    /* set_values               */      GtESetValues,
    /* set_values_hook          */      NULL,
    /* set_values_almost        */      XtInheritSetValuesAlmost,
    /* get_values_hook          */      NULL,
    /* accept_focus             */      XtInheritAcceptFocus,
    /* version                  */      XtVersion,
    /* callback_private         */      NULL,
    /* tm_table                 */      translations,
    /* query_geometry           */      XtInheritQueryGeometry,
    /* display_accelerator      */      XtInheritDisplayAccelerator,
    /* extension                */      NULL
  },
     { /* composite_class fields */
    /* geometry_manager   */   GtEGeometryManager,
    /* change_managed     */   XtInheritChangeManaged,
    /* insert_child       */   XtInheritInsertChild,
    /* delete_child       */   XtInheritDeleteChild,
    /* extension          */   NULL
  },
     { NULL},

};


WidgetClass genTermEmWidgetClass = (WidgetClass) &genTermEmClassRec;

static struct StateTable Mods[] =
{
 {"Shift",ShiftMask},
 {"Caps",LockMask},
 {"Control",ControlMask},
 {"Mod1",Mod1Mask},
 {"Mod2",Mod2Mask},
 {"Mod3",Mod3Mask},
 {"Mod4",Mod4Mask},
 {"Mod5",Mod5Mask},
 {"Button1",Button1Mask},
 {"Button2",Button2Mask},
 {"Button3",Button3Mask},
 {"Button4",Button4Mask},
 {"Button5",Button5Mask},
 {NULL,0},
};

/* GtEClassInitialize:  This is the class initialization method for the GtEm */
/*  class widget.  It simply initializes all class fields to NULL. */

static void GtEClassInitialize()

{
 genTermEmClassRec.genTermEm_class.ParseFiles = NULL;
}

/* GtEInitialize:  This is the initialization method for the widget.  It */
/*  initializes all fields in the widget structure, allocates any needed */
/*  memory and then loads the parse table.  It first checks to see if the */
/*  parse file has already been loaded.  If it has it extracts the parse */
/*  table from the class structure.  If it hasn't, it loads the parse file */
/*  and then adds it to the list of parse file loaded in the class structure */

static void GtEInitialize(request,new)

GenTermEmWidget request,new;

{
 int i,j,count;
 int rows,columns;
 struct GtEParseFile *temp;

 new->genTermEm.FKeys = (struct FunctionKey *) 
  XtMalloc(sizeof(struct FunctionKey)* new->genTermEm.NumberFunctionKeys);
 for(i = 0; i < new->genTermEm.NumberFunctionKeys; i++)
  {
   new->genTermEm.FKeys[i].Label = (char *) XtMalloc(sizeof(char)*3);
   sprintf(new->genTermEm.FKeys[i].Label,"F%d",i+1);

   new->genTermEm.FKeys[i].String = (char *) XtMalloc(sizeof(char) * 3);
   strcpy(new->genTermEm.FKeys[i].String,new->genTermEm.FKeys[i].Label);

   new->genTermEm.FKeys[i].Type = 0;
  }
 new->genTermEm.FunctionRealized = FALSE;
 new->genTermEm.Mods = Mods;

 if(!GtEGetClassParseFile(new))
  {
   GtELoadParseFile(new);
   temp = (struct GtEParseFile *)XtMalloc(sizeof(struct GtEParseFile));
   temp->Name = (char *) XtMalloc(strlen(new->genTermEm.ParseFile)+1);
   strcpy(temp->Name,new->genTermEm.ParseFile);
   temp->ParseTables = new->genTermEm.ParseList;
   temp->KeyTables = new->genTermEm.KeyList;
   temp->Next = genTermEmClassRec.genTermEm_class.ParseFiles;
   genTermEmClassRec.genTermEm_class.ParseFiles = temp;
  }

 new->genTermEm.CurrentPoint = new->genTermEm.ParseTable;
 new->genTermEm.TopStack = 0;

 GtGetScreenSize(new,&rows,&columns);
 count = columns / 8;

 for(i = 0; i < count; i++)
  new->genTermEm.TabStops[i] = (i + 1) * 8;
 for(i = 10; i < NTABS; i++)
  new->genTermEm.TabStops[i] = columns;

 new->genTermEm.MapTables = (char **) XtMalloc(sizeof(char *) * 
					      new->genTermEm.NumMapTables);
 for(i = 0; i < new->genTermEm.NumMapTables; i++)
  {
   new->genTermEm.MapTables[i] = (char *) XtMalloc(sizeof(char ) * NMAP);
   for(j = 0; j < ' '; j++)
    new->genTermEm.MapTables[i][j] = ' ';
   for(j = ' '; j < 128; j++)
    new->genTermEm.MapTables[i][j] = j;
   for(j = 128; j < NMAP; j++)
    new->genTermEm.MapTables[i][j] = ' ';
  }
 GtSetMapTable(new,new->genTermEm.MapTables[0]);

 new->genTermEm.StoreArgs = (struct InputArgument *) 
  XtMalloc(sizeof(struct InputArgument) * new ->genTermEm.NumStoreArgs);
 for(i = 0; i < new->genTermEm.NumStoreArgs; i++)
  new->genTermEm.StoreArgs[i].valid = 0;

 new->genTermEm.InputArgs = (struct InputArgument *)
  XtMalloc(sizeof(struct InputArgument) * NUMARGS);
 for(i = 0; i < NUMARGS; i++)
  new->genTermEm.InputArgs[i].valid = 0;

 new->genTermEm.Storage = NULL;
 new->genTermEm.NumInStorage = 0;
 new->genTermEm.StorageSize = 0;
 new->genTermEm.InputBlocked = False;
 new->genTermEm.WidgetLocked = False;
 new->genTermEm.NeedWakeUp = False;
 new->genTermEm.SpecialVars.Started = 0;
}

/* GtEGetClassParseFile:  This function looks into the class structure to */
/*  determine if the required parse file has previously been loaded.  It */
/*  walks the list of cached parse files.  If it finds the required file */
/*  it sets up the parse table and key table fields in the instance record */
/*  returns true.  Otherwise it returns false.  */

static Boolean GtEGetClassParseFile(w)

GenTermEmWidget w;

{
 struct GtEParseFile *files = genTermEmClassRec.genTermEm_class.ParseFiles;
 struct GtEList *temp;

 while(files != NULL)
  {
   if(strcmp(files->Name,w->genTermEm.ParseFile) == 0)
    {
     w->genTermEm.ParseList = files->ParseTables;
     w->genTermEm.KeyList = files->KeyTables;

     temp = w->genTermEm.ParseList;
     while(temp != NULL)
      {
       if(strcmp(temp->Name,DEFAULT) == 0)
	{
	 w->genTermEm.ParseTable = temp->Point.ParseTable;
	 break;
	}
       temp = temp->Next;
      }
     if(temp == NULL)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget doesn't find default parse table");
     
     temp = w->genTermEm.KeyList;
     while(temp != NULL)
      {
       if(strcmp(temp->Name,DEFAULT) == 0)
	{
	 w->genTermEm.Keys = temp->Point.KeyTable;
	 w->genTermEm.NumKeys = temp->Num;
	 break;
	}
       temp = temp->Next;
      }
     if(temp == NULL)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget doesn't find default key table"); 
     return(True);
    }
   files = files->Next;
  }
 return(False);
}

/* GtERealize:  This is the realize method for the widget.  It simply */
/*  realizes all the superclasses and then, if required, builds the function */
/*  key widgets.  Next, if there is a Output file descriptor defined we */
/*  create a callback to executed when ever there is data ready to be read */
/*  on it. Finally, we execute the translators associated with the StartUp */
/*  parse table, if there is any. */

static void GtERealize(w,valueMask,attributes)

GenTermEmWidget w;
XtValueMask *valueMask;
XSetWindowAttributes *attributes;

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

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

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

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

 if(w->genTermEm.ShowKey)
  GtERealizeFunctionKeys(w);

 if(w->genTermEm.OutputDescriptor >= 0)
  w->genTermEm.OutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
				       w->genTermEm.OutputDescriptor,
				       XtInputReadMask,
				       GtEOutputDescriptorCallBack,(caddr_t)w);
 XtAddCallback(w,XtNlockCallback,GtELockCallback,(caddr_t)w);
 GtEExecuteParseTable(w,"StartUp",0);
}

/* GtERealizeFunctionKeys:  This function creates the widgets which */
/*  implement the function keys.  At the moment, I use the XmPushButton */
/*  widget to do this.  I suppose it would be better if I didn't and */
/*  created my own or, somehow merged it into this widget, but for now this */
/*  will have to do.  What it does is figure out how big the widget currently*/
/*  is.  It then requests that the widget resize it self to fit in the */
/*  function keys and requests a bottom margin be established to put the */
/*  widgets into.  Finally, it creates the widgets at the correct location */

static void GtERealizeFunctionKeys(w)

GenTermEmWidget w;

{
 Arg args[20];
 int n = 0;
 int i;
 Dimension Height,OldHeight;
 Dimension Width;
 char buffer[1024];
 
 if(w->genTermEm.FunctionRealized == FALSE)
  {
   XtSetArg(args[n],XtNheight,&Height); n++;
   XtSetArg(args[n],XtNwidth,&Width); n++;
   XtGetValues(w,args,n);
   
   OldHeight = Height;
   Height += w->genTermEm.FuncKeyHeight;
   n = 0;
   XtSetArg(args[n],XtNheight,Height); n++;
   XtSetArg(args[n],XtNbottomMargin,w->genTermEm.FuncKeyHeight); n++;
   XtSetValues(w,args,n);
   
   Width = Width/w->genTermEm.NumberFunctionKeys;
   for(i = 0; i < w->genTermEm.NumberFunctionKeys; i++)
    {
     n = 0;
     XtSetArg(args[n],XtNy,OldHeight); n++;
     XtSetArg(args[n],XtNx,Width * i); n++;
     XtSetArg(args[n],XtNheight,w->genTermEm.FuncKeyHeight); n++;
     XtSetArg(args[n],XtNwidth,Width);n++;
     if(strlen(w->genTermEm.FKeys[i].Label) > w->genTermEm.FuncLabelWidth)
      {
       memcpy(buffer,w->genTermEm.FKeys[i].Label,w->genTermEm.FuncLabelWidth);
       buffer[w->genTermEm.FuncLabelWidth] = '\n';
       strcpy(&(buffer[w->genTermEm.FuncLabelWidth + 1]),
	      &(w->genTermEm.FKeys[i].Label[w->genTermEm.FuncLabelWidth]));
      }
     else
      strcpy(buffer,w->genTermEm.FKeys[i].Label);
     XtSetArg(args[n],XmNlabelString,
	      XmStringCreateLtoR(buffer,XmSTRING_DEFAULT_CHARSET)); n++;
     XtSetArg(args[n],XmNalignment,XmALIGNMENT_CENTER); n++;
     XtSetArg(args[n],XmNrecomputeSize,False); n++;
     XtSetArg(args[n],XmNtraversalOn,False); n++;
     w->genTermEm.FKeys[i].FuncKey = (Widget) 
      XmCreatePushButton(w,w->genTermEm.FKeys[i].Label,args,n);
     XtManageChild(w->genTermEm.FKeys[i].FuncKey);
     XtAddCallback(w->genTermEm.FKeys[i].FuncKey,XmNactivateCallback,
		   GtEFunctionKeyPress,(caddr_t)i);
    }
   w->genTermEm.FunctionRealized = TRUE;
  }

}

/* GtEFunctionKeyPress:  This is a callback routine for the function keys. */
/*   It is called whenever a function key is selected from the mouse. */
/*   Depending on what type of function is associated with that function */
/*   key, it will dispatch the associated string to either the widget, or */
/*   the managing application or both.  This function can generate a */
/*   kbdCallback with the reason being GTE_INPUT. */

static int GtEFunctionKeyPress(button,client_data,call_data)

Widget button;
caddr_t client_data;
caddr_t call_data;

{
 GenTermEmWidget w = (GenTermEmWidget) XtParent(button);
 XmPushButtonCallbackStruct *ReasonCalled = 
  (XmPushButtonCallbackStruct *)call_data;
 int num = (int) client_data;
 GenTermEmCallback ReasonSent;
 char buffer[1024];

 ReasonSent.reason = GTE_INPUT;
 ReasonSent.event = ReasonCalled->event;
 ReasonSent.string = buffer;
 ReasonSent.len = 0;

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

/*  GtEGeometryManager:  This is the geometry manager method for the widget. */
/*   As you can see, I doubt this function is really correct but it seems to */
/*   do roughly what I want.  This section (and GtEResize) needs more work. */

static XtGeometryResult GtEGeometryManager(w,request,reply)

GenTermEmWidget w;
XtWidgetGeometry *request, *reply;

{
 return(XtGeometryYes);
}

/* GtEInput:  This is the input action handler for the widget.  It is */
/*  typically called each time there is a key press.  It first calles */
/*  GtMarginBell to sound the margin bell, if needed.  It then processes */
/*  the key event.  There are three possible things that can happen.  First, */
/*  the key is a normal key in which case the kbdCallback is activated and */
/*  the passed the result from XLookupString.  The second case is that the */
/*  key is a function key.  In this case, the key press is processed as a */
/*  normal function key.  Depending on whether it is an input or output key */
/*  the associated string for the key is processed or passed to the */
/*  kdbCallback function.  The final case is that the key is in the key */
/*  mapping table.  In this case the key is translated according to the */
/*  mapping table and then either processed via GtEOutput or passed to the */
/*  kbdCallback. */

static void GtEInput(w,event,x,y)

GenTermEmWidget w;
XEvent *event;
String *x[];
Cardinal *y;

{
 char buffer[1024];
 GenTermEmCallback reason;
 int n;
 KeySym keysym;
 int i;

 GtMarginBell(w);

 reason.reason = GTE_INPUT;
 reason.event = event;
 reason.string = buffer;
 reason.len = 0;

 n = XLookupString((XKeyEvent *)event,buffer,sizeof(buffer),&keysym,
		   &(w->genTermEm.ComposeStatus));
 reason.len = n;
 
 if(IsFunctionKey(keysym))
  {
   i = keysym - XK_F1;
   if((i >= 0) && (i < w->genTermEm.NumberFunctionKeys))
    {
     if((w->genTermEm.FKeys[i].Type == 0) || (w->genTermEm.FKeys[i].Type == 2))
      {
       strcpy(buffer,w->genTermEm.FKeys[i].String);
       reason.len = strlen(buffer);
      }
     if((w->genTermEm.FKeys[i].Type == 0) || (w->genTermEm.FKeys[i].Type == 1))
      {
       GtEOutput(w,w->genTermEm.FKeys[i].String,
		 strlen(w->genTermEm.FKeys[i].String));
      }
    }
  }
 else
  {
   for(i = 0; i < w->genTermEm.NumKeys; i++)
    if((keysym == w->genTermEm.Keys[i].sym) && 
       (event->xkey.state == w->genTermEm.Keys[i].state))
     {
      if((w->genTermEm.Keys[i].type == 'I') || 
	 (w->genTermEm.Keys[i].type == 'B'))
       {
	memcpy(buffer,w->genTermEm.Keys[i].string,w->genTermEm.Keys[i].len);
	reason.len = w->genTermEm.Keys[i].len;
       }
      if((w->genTermEm.Keys[i].type == 'O') ||
	 (w->genTermEm.Keys[i].type == 'B'))
       {
	GtEOutput(w,w->genTermEm.Keys[i].string,w->genTermEm.Keys[i].len);
	reason.len = 0;
       }
      break;
     }
  }
 if(reason.len > 0)
  XtCallCallbacks(w,XtNkbdCallback,(caddr_t) &reason);
}

/* GtEInvokeTranslation:  This is the invokeTranslation action handler */
/*  function.  It takes the name of a parse table and executes the */
/*  translations bound to the top of it. */

static void GtEInvokeTranslation(w,event,names,num)

GenTermEmWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 int i;

 memcpy(&(w->genTermEm.LastEvent),event,sizeof(XEvent));
 for(i = 0; i < *num; i++)
  {
   GtEExecuteParseTable(w,names[i],True);
  }
}

/* GtEOutputAction:  This is the output action handler for the widget.  It */
/*  will send the given strings to the widget to be displayed on the screen */

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

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

{
 int i;

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

/* GtEAWaitGraphicsExpose:  This is the graphics exposure wakeup routine. */
/*  When the widget goes to sleep waiting for a graphics expose it stops */
/*  processing all input and shuts down its read handler on the output */
/*  file descriptor.  This function gets the widget processing events again. */
/*  First it checks to make sure the widget is ready to be woken up.  If it */
/*  is and there is stored input waiting to be processed, it calls GtEParse */
/*  to process them.  Finally, if after the reprocessing, the widget is */
/*  still ready to run, the read handler is once again enabled. Before */
/*  leaving, it checks to see if the application should be notified that we */
/*  are once again alive and if it should it call GtEDoWakeUpCallbacks to */
/*  generate the required callback. */

static void GtEAWaitGraphicsExpose(w,event,names,num)

GenTermEmWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 int len = w->genTermEm.NumInStorage;

 if((w->genTerm.ExposureCount == 0) && (w->genTermEm.WidgetLocked == False));
  {
   w->genTermEm.NumInStorage = 0;
   if(len > 0)
    GtEParse(w,w->genTermEm.Storage,len);
   if((w->genTerm.ExposureCount == 0) && (w->genTermEm.WidgetLocked == False)
      && (w->genTermEm.InputBlocked == True))
    {  /* GtEParse might have shut us down again! */
     if(w->genTermEm.OutputDescriptor >= 0)
      w->genTermEm.OutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
					   w->genTermEm.OutputDescriptor,
					   XtInputReadMask,
					   GtEOutputDescriptorCallBack,
					   (caddr_t)w);
     w->genTermEm.InputBlocked = False;
     if(w->genTermEm.NeedWakeUp)
      GtEDoWakeUpCallbacks(w);
    }
  }
}

/* GtESetWaitForGraphicsExpose:  Whenever the GenTerm widget performs a */
/*   scroll it uses the XCopyArea function.  However, the region we copy */
/*   from might not have been available for copying.  If this is the case */
/*   then a Graphics Expose event will eventually be generated and handled */
/*   by the GenTerm widget.  However, the GenTermEm widget is sitting in a */
/*   tight loop processing characters from its input stream.  Therefore it */
/*   possible for this widget to block the Graphics Expose events which will */
/*   put us way out of sync and will cause blank regions to be left on the */
/*   the screen.  To avoid this, GtEParse checks to see if there are any */
/*   graphics expose events pending.  If there are, this function is called */
/*   to store the characters which are still to be processed.  The input */
/*   desciptor is then blocked and the function returns.  This will pass */
/*   control back to the X event dispatcher which will generate the expose */
/*   events we need.  GtEAWaitGraphicsExpose will detect the arrival of */
/*   these events and restart the processing loop. */

void GtESetWaitForGraphicsExpose(w,string,start,len)

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

{
 int size = len - start;
 
 if(size > 0)
  {
   if(w->genTermEm.StorageSize < size)
    {
     w->genTermEm.Storage = XtRealloc(w->genTermEm.Storage,size * 2 *
				     sizeof(char));
     w->genTermEm.StorageSize = size * 2;
    }
   memcpy(w->genTermEm.Storage,&(string[start]),size);
   w->genTermEm.NumInStorage = size;
  }
 else
  w->genTermEm.NumInStorage = 0;

 if((w->genTermEm.InputBlocked == False) && (w->genTermEm.OutputDescriptor >= 0))
  {
   w->genTermEm.InputBlocked = True;
   XtRemoveInput(w->genTermEm.OutputId);
  }
}

/* GtEAddToStorage:  This function adds data to the queue of characters */
/*  waiting to be processed.  It is called by GtEOutput when ever it is */
/*  when the widget is locked or waiting for a graphics expose. */

static void GtEAddToStorage(w,string,len)

GenTermEmWidget w;
char *string;
int len;

{
 if(w->genTermEm.NumInStorage + len >= w->genTermEm.StorageSize)
  {
   w->genTermEm.StorageSize += 2 + len;
   w->genTermEm.Storage = XtRealloc(w->genTermEm.Storage,w->genTermEm.StorageSize
				   * sizeof(char));
  }
 memcpy(&(w->genTermEm.Storage[w->genTermEm.NumInStorage]),string,len);
 w->genTermEm.NumInStorage += len;
}

/* GtEOutput:  This is the main output routine for the widget.  It takes a */
/*  characters string and the len of the character string and displays them */
/*  in the widget.  It first checks to see if the widget is ready to display */
/*  any characters.  If it has been locked or is waiting for a graphics */
/*  expose it simply enqueues the data, makes a note that the caller's */
/*  request has been delayed  and returns a value of GTE_WAIT.  The calling */
/*  routine should honour the GTE_WAIT value by not issuing any more calls */
/*  to GtEOutput until the WakeUpCallback has been activated.   If the */
/*  caller does not honour this then the widget will be forced to allocate */
/*  large amount of memory to buffer the requests but no data will be lost. */
/*  If PreScroll has been asserted the function then performs the prescroll */
/*  and then, if the widget hasn't locked itself, it calls GtEParse to parse */
/*  the input and eventually display it.  Finally, if the widget is */
/*  currently logging its output, it writes a copy of the data to the log */
/*  file. */

int GtEOutput(w,string,len)

GenTermEmWidget w;
char *string;
int len;

{
 int rval = GTE_DONE;

 if((w->genTermEm.WidgetLocked) || (w->genTerm.ExposureCount > 0))
  {
   GtEAddToStorage(w,string,len);
   w->genTermEm.NeedWakeUp = True;
   rval = GTE_WAIT;
  }
 else
  {
   if(w->genTermEm.PreScroll == TRUE)
    GtEPreScroll(w,string,len);
   if(w->genTerm.ExposureCount > 0)
    {
     GtEAddToStorage(w,string,len);
     w->genTermEm.NeedWakeUp = True;
     rval = GTE_WAIT;
    }
   else
    GtEParse(w,string,len);
  }
 if((w->genTermEm.Logging) && (w->genTermEm.LogFileDescriptor >= 0))
  write(w->genTermEm.LogFileDescriptor,string,len);
 return(rval);
}

/* GtESetValues:  This is the set values method for the widget.  It is called*/
/*  whenever the user changes on of the resource variables. */

static Boolean GtESetValues(cur,req,new,args,numargs)

GenTermEmWidget cur;
GenTermEmWidget req;
GenTermEmWidget new;
ArgList args;
Cardinal *numargs;

{
 Boolean Redraw = False;
 struct GtEParseFile *temp;
 int i,j;

 if((cur->genTermEm.ParseFile != new->genTermEm.ParseFile) &&
    (strcmp(cur->genTermEm.ParseFile,new->genTermEm.ParseFile) != 0))
  {
   /* This is a really nasty thing to change, particularly since GtEParse */
   /* might still be in the middle of parsing some queued up input.  Still */
   /* the user is the boss.  */
   if(!GtEGetClassParseFile(new))
    {
     GtELoadParseFile(new);
     temp = (struct GtEParseFile *)XtMalloc(sizeof(struct GtEParseFile));
     temp->Name = (char *) XtMalloc(strlen(new->genTermEm.ParseFile)+1);
     strcpy(temp->Name,new->genTermEm.ParseFile);
     temp->ParseTables = new->genTermEm.ParseList;
     temp->KeyTables = new->genTermEm.KeyList;
     temp->Next = genTermEmClassRec.genTermEm_class.ParseFiles;
     genTermEmClassRec.genTermEm_class.ParseFiles = temp;
    }
   new->genTermEm.CurrentPoint = new->genTermEm.ParseTable;
  }

 if(cur->genTermEm.NumberFunctionKeys != new->genTermEm.NumberFunctionKeys)
  {
   new->genTermEm.FKeys = (struct FunctionKey *) 
    XtMalloc(sizeof(struct FunctionKey)* new->genTermEm.NumberFunctionKeys);
   for(i = 0; i < new->genTermEm.NumberFunctionKeys; i++)
    {
     if(i < cur->genTermEm.NumberFunctionKeys)
      {
       new->genTermEm.FKeys[i].Label = cur->genTermEm.FKeys[i].Label;
       new->genTermEm.FKeys[i].String = cur->genTermEm.FKeys[i].String;
       new->genTermEm.FKeys[i].Type = cur->genTermEm.FKeys[i].Type;
      }
     else
      {
       new->genTermEm.FKeys[i].Label = (char *) XtMalloc(sizeof(char)*3);
       sprintf(new->genTermEm.FKeys[i].Label,"F%d",i+1);
       
       new->genTermEm.FKeys[i].String = (char *) XtMalloc(sizeof(char) * 3);
       strcpy(new->genTermEm.FKeys[i].String,new->genTermEm.FKeys[i].Label);
       
       new->genTermEm.FKeys[i].Type = 0;
      }
    }
   if(new->genTermEm.FunctionRealized == True)
    {
     GtEDestroyFunctionKeys(cur);
     GtERealizeFunctionKeys(new);
    }
   for(i = new->genTermEm.NumberFunctionKeys; 
       i < cur->genTermEm.NumberFunctionKeys; i++)
    {
     XtFree(cur->genTermEm.FKeys[i].Label);
     XtFree(cur->genTermEm.FKeys[i].String);
    }
   XtFree(cur->genTermEm.FKeys);
  }

 if((cur->genTermEm.FuncKeyHeight != new->genTermEm.FuncKeyHeight) &&
    (new->genTermEm.FunctionRealized == True))
  {
   GtEDestroyFunctionKeys(new);
   GtERealizeFunctionKeys(new);
  }

 if(cur->genTermEm.ShowKey != new->genTermEm.ShowKey)
  {
   if(new->genTermEm.ShowKey)
    GtERealizeFunctionKeys(new);
   else
    GtEDestroyFunctionKeys(new);
  }

 if((cur->genTermEm.OutputDescriptor != new->genTermEm.OutputDescriptor) &&
    (XtIsRealized(new)))
  {
   if(cur->genTermEm.OutputDescriptor >= 0)
    XtRemoveInput(new->genTermEm.OutputId);
   if(new->genTermEm.OutputDescriptor >= 0)
    new->genTermEm.OutputId = XtAppAddInput(XtWidgetToApplicationContext(new),
					   new->genTermEm.OutputDescriptor,
					   XtInputReadMask,
					   GtEOutputDescriptorCallBack,
					   (caddr_t)new);
  }
 if(cur->genTermEm.NumMapTables != new->genTermEm.NumMapTables)
  {
   new->genTermEm.MapTables = (char **) XtMalloc(sizeof(char *) * 
						new->genTermEm.NumMapTables);
   for(i = 0; i < new->genTermEm.NumMapTables; i++)
    {
     if(i < cur->genTermEm.NumMapTables)
      new->genTermEm.MapTables[i] = cur->genTermEm.MapTables[i];
     else
      {
       new->genTermEm.MapTables[i] = (char *) XtMalloc(sizeof(char ) * NMAP);
       for(j = 0; j < ' '; j++)
	new->genTermEm.MapTables[i][j] = ' ';
       for(j = ' '; j < 128; j++)
	new->genTermEm.MapTables[i][j] = j;
       for(j = 128; j < NMAP; j++)
	new->genTermEm.MapTables[i][j] = ' ';
      }
    }
   for(i = new->genTermEm.NumMapTables; i < cur->genTermEm.NumMapTables; i++)
    XtFree(cur->genTermEm.MapTables[i]);
   XtFree(cur->genTermEm.MapTables);
  }
 if(cur->genTermEm.NumStoreArgs != new->genTermEm.NumStoreArgs)
  {
   new->genTermEm.StoreArgs = (struct InputArgument *) 
    XtMalloc(sizeof(struct InputArgument) * new ->genTermEm.NumStoreArgs);
   for(i = 0; i < new->genTermEm.NumStoreArgs; i++)
    {
     if(i < cur->genTermEm.NumStoreArgs)
      {
       new->genTermEm.StoreArgs[i].string = cur->genTermEm.StoreArgs[i].string;
       new->genTermEm.StoreArgs[i].length = cur->genTermEm.StoreArgs[i].length;
       new->genTermEm.StoreArgs[i].valid = cur->genTermEm.StoreArgs[i].valid;
      }
     else
      new->genTermEm.StoreArgs[i].valid = 0;
    }
   for(i = new->genTermEm.NumStoreArgs; i < cur->genTermEm.NumStoreArgs; i++)
    {
     if(cur->genTermEm.StoreArgs[i].valid & AMALLOCED)
      XtFree(cur->genTermEm.StoreArgs[i].string);
    }
   XtFree(cur->genTermEm.StoreArgs);
  }

 return(Redraw);
}

/* GtEResize:  This is the resize method for the widget.  It is called */
/*  whenever the widget has to be resized.  It first make sure the GenTerm */
/*  widget's resize method is called and then proceeds with itself.  If the */
/*  function keys are realized it call XtMoveWidget to move them to the new */
/*  location. */

static void GtEResize(w)

GenTermEmWidget w;
{
 WidgetClass superclass;
 Arg args[20];
 int n,i;
 Dimension Height,Width;
 char buffer[1024];

 superclass = (WidgetClass)genTermWidgetClass;
 (*superclass->core_class.resize)(w);

 if(w->genTermEm.FunctionRealized == True)
  {
   n = 0;
   XtSetArg(args[n],XtNheight,&Height); n++;
   XtSetArg(args[n],XtNwidth,&Width); n++;
   XtGetValues(w,args,n);
   
   Height -= w->genTermEm.FuncKeyHeight;
   Width = Width/w->genTermEm.NumberFunctionKeys;
   for(i = 0; i < w->genTermEm.NumberFunctionKeys; i++)
    {
     XtMoveWidget(w->genTermEm.FKeys[i].FuncKey,Width * i,Height);
    }
  }
}

/* GtEDestroy:  This is the destroy method for the widget.  It is called */
/*  when the widget is being destroyed.  It simply frees all the allocated */
/*  memory.  */

static void GtEDestroy(w)

GenTermEmWidget w;

{
 int i;
 
 for(i = 0; i < w->genTermEm.NumberFunctionKeys; i++)
  {
   XtFree(w->genTermEm.FKeys[i].Label);
   XtFree(w->genTermEm.FKeys[i].String);
  }
 GtEDestroyFunctionKeys(w);
 XtFree(w->genTermEm.FKeys);

 for(i = 0; i < w->genTermEm.NumMapTables; i++)
  {
   XtFree(w->genTermEm.MapTables[i]);
  }
 XtFree(w->genTermEm.MapTables);

 for(i = 0; i < w->genTermEm.NumStoreArgs; i++)
  if(w->genTermEm.StoreArgs[i].valid & AMALLOCED)
   XtFree(w->genTermEm.StoreArgs[i]);
 XtFree(w->genTermEm.StoreArgs);

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

 XtFree(w->genTermEm.Storage);
 if((w->genTermEm.InputBlocked == False) && (w->genTermEm.OutputDescriptor >= 0))
  {
   w->genTermEm.InputBlocked = True;
   XtRemoveInput(w->genTermEm.OutputId);
  }
}

/* GtEDestroyFunctionKeys:  This function removes the function key widgets */
/*  from the screen and then causes the widget to shrink and removes the */
/*  bottom margin. */

static void GtEDestroyFunctionKeys(w)

GenTermEmWidget(w);

{
 int i;
 Arg args[20];
 int n = 0;
 Dimension Height;

 if(w->genTermEm.FunctionRealized)
  {
   w->genTermEm.FunctionRealized = False;

   for(i = 0; i < w->genTermEm.NumberFunctionKeys; i++)
    XtDestroyWidget(w->genTermEm.FKeys[i].FuncKey);
   
   XtSetArg(args[n],XtNheight,&Height); n++;
   XtGetValues(w,args,n);
   
 
   Height -= w->genTermEm.FuncKeyHeight;
   n = 0;
   XtSetArg(args[n],XtNheight,Height); n++;
   XtSetArg(args[n],XtNbottomMargin,0); n++;
   XtSetValues(w,args,n);

   w->genTermEm.FunctionRealized = FALSE;
  }
}

static void GtEOutputDescriptorCallBack(client_data,source,id)

XtPointer client_data;
int *source;
XtInputId *id;

{
 GenTermEmWidget w = (GenTermEmWidget) client_data;
 char buffer[1024];
 int nread;

 while((w->genTerm.ExposureCount <= 0) && (w->genTermEm.WidgetLocked == False) &&
       ((nread = read(*source,buffer,1024)) > 0))
  {
   GtEOutput(w,buffer,nread);
  }
}

/* GtEExecuteParseTable:  This function will execute the translators found */
/*  at the top of the specified parse table, if any. */

int GtEExecuteParseTable(w,name,verbose)

GenTermEmWidget w;
char *name;
int verbose;

{
 struct GtEList *temp = w->genTermEm.ParseList;
 struct Translator *Functions;
 int ReturnVal,k;
 struct InputArguments *Args;

 while(temp != NULL)
  {
   if(strcmp(name,temp->Name) == 0)
    break;
   temp = temp->Next;
  }
 if(temp == NULL)
  {
   if(verbose)
    XtAppWarning(XtWidgetToApplicationContext(w),
		 "Invalid Parse Table encountered in GtEExecuteParseTable");
   return(0);
  }
 else
  {
   Args = GtEPushArgs(w);
   Functions = temp->Point.ParseTable->translators;
    while(Functions != NULL)
     {
      ReturnVal = (Functions->func)(w,Functions->arglist);
      if(ReturnVal == TRANSERROR)
       break;
      else if(ReturnVal == TRANSOKAY)
       Functions = Functions->next;
      else if(ReturnVal == TRANSREJECT)
       break;
      else
       {
	while((Functions != NULL) &&(Functions->label != ReturnVal))
	 Functions = Functions->next;
       }
     }
   /* okay, here walk input argument list to free what ever needed */
   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;
     }
   GtEPopArgs(w,Args);
  }
 return(0);
}

/* GtEInsertSelection:  This is the insertSelection action handler.  It */
/*  merely determines where the selection is coming from and then reqesters */
/*  the handler to to actually get the selection. */

static void GtEInsertSelection(w,event,names,num)

GenTermEmWidget w;
XEvent *event;
char *names[];
Cardinal *num;

{
 Atom which = XA_PRIMARY;
 int i;

 w->genTermEm.CutBuffer = -1;

 for(i = 0; i < *num; i++)
  {
   if(strcmp(names[i],"SECONDARY") == 0)
    which = XA_SECONDARY;
   else if(strncmp(names[i],"CUT_BUFFER",strlen("CUT_BUFFER")) == 0)
    {
     w->genTermEm.CutBuffer = names[i][strlen("CUT_BUFFER")] - '0';
    }
  }

 XtGetSelectionValue(w,which,XA_STRING,GtEInsertCallback,NULL,
		     event->xbutton.time);
}

/* GtEInsertCallback:  This is the procedure which gets the selection.  If */
/*  the selection was coming from a cutbuffer then it gets its from there. */
/*  Once the selection is obtained, it generates a kbdCallback with a reason */
/*  of GTE_INPUT. */

static void GtEInsertCallback(w,client_data,selection,type,value,length,format)

GenTermEmWidget w;
XtPointer client_data;
Atom *selection;
Atom *type;
XtPointer *value;
unsigned long *length;
int *format;

{
 GenTermEmCallback reason;

 if((value == NULL) || ((*value == NULL) && (*length == 0)))
  {
   if(w->genTermEm.CutBuffer >= 0)
    {
     reason.string = XFetchBuffer(XtDisplay(w),&(reason.len),
				  w->genTermEm.CutBuffer);
     if(reason.len > 0)
      {
       reason.reason = GTE_INPUT;
       reason.event = NULL;
       XtCallCallbacks(w,XtNkbdCallback,(caddr_t)&reason);
      }
    }
  }
 else
  {
   reason.reason = GTE_INPUT;
   reason.event = NULL;
   reason.string = (char *)value;
   reason.len = *length;
   XtCallCallbacks(w,XtNkbdCallback,(caddr_t)&reason);
  }
}

/* GtELockCallback: This is the lock callback.  It intercepts the underlying */
/*   GenTerm widget locking itself and records this for our use.  If we are */
/*   unlocking ourself and there is data in our storage buffer it is */
/*   processed.  A wakeupCallback can be generated. */

static void GtELockCallback(w,type,reason)

GenTermEmWidget w;
int type;
GenTermCallback *reason;

{
 int len;
 if(reason->Value)
  {
   w->genTermEm.WidgetLocked = True;
   if((w->genTermEm.InputBlocked == False) && 
      (w->genTermEm.OutputDescriptor >= 0))
    {
     w->genTermEm.InputBlocked = True;
     XtRemoveInput(w->genTermEm.OutputId);
    }
  }
 else
  {
   w->genTermEm.WidgetLocked = False;
   if(w->genTerm.ExposureCount == 0)
    {
     len = w->genTermEm.NumInStorage;
     w->genTermEm.NumInStorage = 0;
     if(len > 0)
      GtEParse(w,w->genTermEm.Storage,len);
     if((w->genTerm.ExposureCount == 0) && (w->genTermEm.InputBlocked == True))
      {
       if(w->genTermEm.OutputDescriptor >= 0)
	w->genTermEm.OutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
					     w->genTermEm.OutputDescriptor,
					     XtInputReadMask,
					     GtEOutputDescriptorCallBack,
					     (caddr_t)w);
       w->genTermEm.InputBlocked = False;
       if(w->genTermEm.NeedWakeUp)
	GtEDoWakeUpCallbacks(w);
      }
    }
  }
}

/* GtEDoWakeUpCallbacks:  This function envokes the wakeup call back.  A */
/*  wakeup callback is asserted whenever the widget has completed processing */
/*  all the queued data after it has asserted GTE_WAIT from GtEOutput. */

GtEDoWakeUpCallbacks(w)

GenTermEmWidget w;

{
 GenTermEmCallback ReasonSent;
 
 ReasonSent.reason = GTE_WAKEUP;
 
 XtCallCallbacks(w,XtNwakeUpCallback,(caddr_t)&ReasonSent);
}

/* GtEPreScroll:  This function attempts to estimate the amount of lines in */
/*  a given piece of text.  In reality it can't determine this with out */
/*  passing it through GtEParse.  However, to implement a jump scroll we need*/
/*  to be able to estimate it.  It does this by counting the occurance of */
/*  a specified ScrollChar (typically \n) in the string.  Because escape */
/*  sequences can make this count invalid we also abort this function if we */
/*  find the start of a possible escape sequence (ScrollAbortChar). Finally */
/*  if the amount of scrolling is large enough it moves the screen down and */
/*  then returns the cursor to its correct position. */

static void GtEPreScroll(w,string,len)

GenTermEmWidget w;
char *string;
int len;

{
 int jump = 0;
 int i;
 int rows,cols;
 int crow,ccol;

 for(i = 0; i < len; i++)
  {
   if(string[i] == w->genTermEm.ScrollAbortChar)
    return;
   if(string[i] == w->genTermEm.ScrollChar)
    jump++;
  }

 if(jump > 2)
  {
   GtGetScreenSize(w,&rows,&cols);
   GtGetCursorPosition(w,&crow,&ccol);
   if(jump > rows)
    jump = rows - 2;
   if(jump + crow > rows + 1)
    {
     GtNewLine(w,jump);
     GtCursorUp(w,jump,0);
    }
  }
}
@EOF
set `wc -lwc <GenTerm/GenTermEm.c`
if test $1$2$3 != 1305417241615
then
	echo ERROR: wc results of GenTerm/GenTermEm.c are $* should be 1305 4172 41615
fi

chmod 644 GenTerm/GenTermEm.c

echo x - GenTerm/GenTermEm.man
sed 's/^@//' >GenTerm/GenTermEm.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 GenTermEm 3X
@.SH NAME
\fBGenTermEm \- The Generalized terminal emulator widget class.\fP
@.sp 1
@.SH SYNOPSIS
\fB#include "/usr/local/include/GenTermEm.h"\fP
@.SH DESCRIPTION
The \fBGenTermEm\fP widget is a generalized terminal emulator widget.
It inherits all capabilities and resources of the \fBGenTerm\fP widget
and adds the capability of emulating a specific terminal.  The widget
does not emulate any one terminal but, instead, can be configured to
emulate many different types of terminals.  The widget consists of a
translation table which defines the behavior of each key on the
keyboard and a parse table which defines the escape sequences the
terminal supports and the actions they perform.  In addition, the widget
also supports a set of programmable function keys which can be
displayed below the terminal screen and a logging capability.
@.SH CLASSES
\fBGenTermEm\fP inherits behavior and resources from \fBGenTerm\fP,
\fBCore\fP and \fBComposite\fP classes.
@.PP
The class pointer is \fBgenTermEmWidgetClass\fP
@.PP
The class name is \fBGenTermEm\fP
@.SH "NEW RESOURCES"
The following table list the resources recognized by the
\fBGenTermEm\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 the \fBXtC\fP prefix of the
resource name.
@.sp 1 
@.KS
@.sp 1
@.TS
center;
cB sss
lB lB lB lB
llll.
GenTermEm Resource Set
Name	Class	Type	Default
_
XtNdestructiveTab	XtCDestructiveTab	Boolean	True
XtNescCallback	XtCEscCallback	Callback	Null
XtNflowCallback	XtCFlowCallback	Callback	Null
XtNfunctionLabelWidth	XtCFunctionLabelWidth	Int	8
XtNfunctionSize	XtCFunctionSize	Dimension	39
XtNlogFile	XtCLogFile	Int	-1
XtNlogging	XtCLogging	Boolean	False
XtNname	XtCName	String	term0
XtNnumberFunctionKeys	XtCNumberFunctionKeys	Int	8
XtNnumberMapTables	XtCNumberMapTables	Int	1
XtNnumberStorageArguments	XtCNumberStorageArguments	Int	20
XtNoutputFile	XtCOutputFile	Int	-1
XtNparseFile	XtCParseFile	String	./hpterm.par
XtNpreScroll	XtCPreScroll	Boolean	False
XtNscrollAbortChar	XtCScrollAbortChar	Char	^[
XtNscrollChar	XtCScrollChar	Char	^J
XtNshowFunction	XtCShowFunction	Boolean	False
XtNwakeUpCallback	XtCWakeUpCallback	Callback	NULL
@.TE
@.KE
@.sp 1
@.IP "\fBXtNdestructiveTab\fP"
This resource specifies the behavior of the tab key.  If \fBTrue\fP,
then striking the tab key causes the cursor to move to the next tab
stop on the line and erasing any characters is passed.  If \fBFalse\fP
then the cursor will move to the next tap stop passing over any
characters.
@.IP "\fBXtNescCallback\fP"
This resource specifies the list of callback functions to call when
ever the widget executes the \fIEscapeCallback\fP input translator
function.  This allows the calling application to handle specific
input escape sequences in the input stream.
@.IP "\fBXtNflowCallback\fP"
This resource specifies the list of callback functions to call when
ever the widget executes the \fISetFlow\fP input translator function.
This allows the calling application to respond to flow control
requests.
@.IP "\fBXtNfunctionLabelWidth\fP"
This resources specifies how many characters wide the function key
labels should be when they are displayed.
@.IP "\fBXtNfunctionSize\fP"
This resource specifies the height of the function key widgets when
they are displayed.
@.IP "\fBXtNlogFile\fP"
This resource specifies the file descriptor for the log file.  If
logging is enabled, all input and output characters will be written to
this file.  The file should be opened for writing.
@.IP "\fBXtNlogging\fP"
This resource specifies if logging is currently enabled.  If the
resource is set to \fITrue\fP then all characters either read or
written will be also written to the file specified by the
\fBXtNlogFile\fP resource.
@.IP "\fBXtNname\fP"
This resource contains the name of the terminal the widget is
currently emulating.  Currently, this resource is unused and does not
affect the behavior of the widget.
@.IP "\fBXtNnumberFunctionKeys\fP"
This resource specifies how many programmable function keys there are.
@.IP "\fBXtNnumberMapTables\fP"
This resource specifies how many output mapping tables can exist
simultaneously.
@.IP "\fBXtNnumberStorageArguments\fP"
This resource specifies how many global variables the input translator
functions can access.
@.IP "\fBXtNoutputFile\fP"
This resource specifies the file descriptor from which it will receive
input.  The descriptor should be associated with an IPC channel which
is connected to the output a program which is attached to this
terminal emulator.  Usually this is a pty but, other file types can be
used such as pipe, fifo's or sockets can be used.  The widget performs
only read operations on the descriptor however, the file type
associated with the descriptor should be suitable for use in the
\fIXtAppAddInput\fP function.
@.IP "\fBXtNparseFile\fP"
This resource specifies the complete path name of the file containing
the parse table and key tables.  This resource controls what kind of
terminal the widget is emulating.  If after realization, this
resource is altered, the widget will reset itself and load the new
file and thereby change its emulation.
@.IP "\fBXtNpreScroll\fP"
This resource specifies whether the widget should perform a prescroll
or not.  Because of the separation of the widget into a parser widget
and terminal management widget, a proper smooth scroll can not be
efficiently implemented.  Therefore, a prescroll is implemented.  If
this resource is \fITrue\fP, on each block of text, the widget first
attempts to guess how many lines are required to print the text prior
to parsing it.  It then requests that many lines from the terminal
management widget.
@.IP "\fBXtNscrollAbortChar\fP"
This resource defines a character which will cause the widget to abort
calculating the prescroll region.  Typically this resource corresponds
to the starting character of an escape sequence that would cause the
cursor to move.  This may cause the prescroll count to be incorrect so
the widget will abort and process the text block normally.
@.IP "\fBXtNscrollChar\fP"
This resource defines the character which causes the cursor to move
down one line.  It is used for the prescroll calculation only.
@.IP "\fBXtNshowFunciton\fP"
This resource specifies whether the widget should display the function
keys on the screen or not.
@.IP "\fBXtNwakeUpCallback\fP"
This resource specifies a list of callback functions to call when ever
the widget wakes itself up.  The widget goes to sleep when ever
graphics events are still pending or the \fBGenTerm\fP has locked
itself.  It wakes up when the graphics expose events are complete or
the \fBGenTerm\fP widget unlocks itself.  A callback is generated to
inform the calling application it is now ready to process more
characters.
@.sp 1
@.sp 1
@.SH "CALLBACK INFORMATION"
A pointer to the following structure is passed to each callback:
@.sp .5
@.nf
@.ta .25i 1.1i
\fBtypedef struct\fP
{
	\fBint\fP	\fIreason\fP;
	\fBXEvent\fP	\fI* event\fP;
	\fBchar\fP	\fI* string\fP;
	\fBint\fP	\fILen\fP;
	\fBchar\fP	\fI** escapes\fP;
} \fBGenTermEmCallback\fP;
@.fi
@.sp .5
@.IP "\fIreason\fP"
Indicates why the callback was called.
Possible values are: \fIGTE_INPUT\fP, \fIGTE_ESCAPE\fP,
\fIGTE_WAKEUP\fP, \fIGTE_XOFF\fP and \fIGTE_XON\fP.
@.IP "\fIevent\fP"
Points the the \fBXEvent\fP structure which triggered this event (if
any event did).
@.IP "\fIstring\fP"
If \fBreason\fP equals \fIGTE_INPUT\fP then \fBstring\fP points to the
characters that were entered by the user.
@.IP "\fILen\fP"
If \fBreason\fP equals \fIGTE_INPUT\fP the \fBLen\fP is equal to the
number of characters that \fBstring\fP points to.
@.IP "\fIescapes\fP"
If \fBreason\fP equals \fIGTE_ESCAPE\fP the \fIescapes\fP points to a
array of null terminated strings.  The final string in the list is
NULL.  The number and values of the \fIescapes\fP strings  depends on
the \fBEscapeCallback\fP input translator.
@.SH "TRANSLATIONS"
The \fIGenTermEm\fP widget has the following default translations:
\fB
@.nf
@.ta 1.8i
@.sp 0.5
<KeyPress>:	input()
<Expose>:	expose()
<GraphicsExpose>:	expose() awaitgraphicsexpose()
<NoExpose>:	noexpose() awaitgraphicsexpose()
<Btn1Down>:	StartSelection()
<Btn1Motion>:	ExtendSelection()
<Btn1Up>:	MakeSelection(PRIMARY,CUT_BUFFER0)
<Btn2Up>:	InsertSelection(PRIMARY,CUT_BUFFER0)
@.fi
\fP
@.SH "ACTIONS"
The \fIGenTermEm\fP action routines are:
@.IP "\fBawaitgraphicsexpose()\fP"
Determines if all pending graphics expose events have been processed.
If they have then it wakes the widget up and starts the processing of
characters.  It may invoke the \fBXtNwakeUpCallback\fP.
@.IP "\fBinput()\fP"
Process a key press event.  If the key was a function key then it is
expanded to its currently programmed value and executed.  If the key
is defined in the currently active key table then it is converted to
its appropriate value.  If the key is an \fIoutput\fP key or a
\fIboth\fP key, then the resultant string is passed through the parser
to be printed on the screen.  If it is an \fIinput\fP key or a
\fIboth\fP key then the \fBXtNkbdCallback\fP is invoked with a reason
of \fIGTE_INPUT\fP.  In the callback structure \fBstring\fP will point
to translated key value.
@.IP "\fBInsertSelection(Source)\fP"
Inserts text from the specified source.  \fBSource\fP and be any of
\fIPRIMARY\fP, \fISECONDARY\fP or \fICUT_BUFFERn\fP where n is an
integer from 0 to 7.  You can specify multiple sources in which case
the action takes the text from the first source that contains text.
The action then invokes a \fIXtNkbdCallback\fP with a reason of
\fBGTE_INPUT\fP.
@.IP "\fBinvokeTranslation(table)\fP"
Executes a parse table.  The action takes the name of a parse table
which is defined in the currently loaded parse file and executes any
input translations that are bound to its first translation rule.
@.IP "\fBoutput(string)\fP"
Print the arguments on the screen.  The argument to the action are
processed through the parser and printed on the widget's screen.
@.sp 1
@.SH "THE PARSE FILE"
The parse file contains all the terminal emulation information the
widget requires to emulation a specific terminal.  It contains
translation tables for the key events and the definitions for the
parser for the output stream.
@.LP
The syntax of the parse file is as follows.  Any line starting with a
\fI#\fP character is considered a comment.  In addition, the \fI^\fP
character is special.  When encountered the widget reads in the next
character and clears its seventh bit.  This allows control characters
to be read in.  Any special characters can be escaped by preceding
them with the \fI\\\fP character.  The format for the tables are:
@.sp
@.nf
KeyTable(Name)=
{
<KeyDefinition>
}
}
ParseTable(Name)=
{
<ParseItem>
}
@.fi
@.sp
Where \fIName\fP is a unique character string identifier.  There can
be as many key table and parse tables as desired and they can be
specified in any order.  However, when the widget is first initialized
it will use the key table whose name is defined as \fIDefault\fP.
Similarly, the widget will first load the parse table whose name is
\fIDefault\fP. In
addition, if any parse table is defined with the identifier
\fIStartUp\fP and if the first item in the parse table is a null rule,
then the widget will execute the translator associated with that rule.
This allows the widget to initialize any global variables it needs.
@.LP
\fIKeyDefinition\fPs define the key actions and are listed one per
line.  The syntax is:
@.sp
@.nf
KeySym(Modifier),Type,String
@.fi
@.sp
\fIKeySym\fP is the name of the X11 key symbol the definition is for.
It should correspond to the names given in
\fI/usr/include/X11/keysymdef.h\fP with out the \fIXK_\fP prefix.  The
\fI(Modifier)\fP is optional.  If specified, it list the modifier that
is in effect for this definition.  Valid modifiers are:
\fIShift\fP, \fICaps\fP, \fIControl\fP, \fIMod1\fP, \fIMod\fP,
\fIMod3\fP, \fIMod4\fP, \fIMod5\fP, \fIButton1\fP, \fIButton2\fP,
\fIButton3\fP, \fIButton4\fP and \fIButton5\fP.  \fIType\fP specifies
the type of key this is to become.  If \fIType\fP is equal to \fIO\fP
then the key is an output only key.  When this key is struck, it will
be translated and sent through the widget's parser for processing.  It
will not generate an input event.  If \fIType\fP is equal to \fII\fP,
then the key is an input only key.  When the key is struck, it will be
translated and the result will be sent to keyboard callback routines.
If \fIType\fP is equal to \fIB\fP, then the key is both an input and
output.  \fIString\fP is the translation string that should be
substituted for the key.  It is this value that will be sent to the
parser or the callback routines.  The string continues to the end of
the line.  Non printable characters can be enbedded via the \fI^\fP
escape mechanism mentioned above.
@.LP
A \fIParseItem\fP define the translation rules for the escape codes
the terminal supports.  The items are listed one per line and contain
the grammar for the escape code and the commands the widget should
execute when the rule is matched. The syntax for the parse item is:
@.sp
@.nf
Rule{Translators}
@.fi
@.sp
A \fIRule\fP consists of a series of characters or special matching
functions.  Non printable characters can be entered with the \fI^\fP
escape mechanism.  A special matching function is the name of the a
function which can scan the input stream and match certain sequences.
For example, there is a matching function to match a string of
integers.  The syntax for a matching function is:
@.sp
@.nf
<Name(Args),Num>
@.fi
@.sp
where \fIName\fP is a character string which correspond to the name of
the function.  \fIArgs\fP is a comma separated list of arguments.  Each
argument can be either a number, a string enclosed in double quotes or
a dollar sign (\fI$\fP) followed by a number.  The last specifies a
positional argument.  When the matching function is executed the value
of the argument stored in that position will be substituted for the
argument.  At the end of rule matching, all positional argument values
are reset.  \fINum\fP is a number which specifies the number of the
positional argument into which the matched string will be stored.  The
valid matching functions are:
@.IP \fBDigits(Default,Seperator,Length)\fP
This function will match a list of zero or more integer values.
\fBDefault\fP, an integer value, is the value to return if no digits
are encountered.  \fBSeperator\fP, a character string, defines the
single character that separates each integer in the list.
\fILength\fP, an integer value, is an optional argument.  If it is
given then it defines the number of digits in each integer.  The
matching function returns the first matched integer in the specified
positional argument.  The second matched integer is returned in the
next argument and so on until the end of the list.  At the end of the
list, the default value is stored.
@.IP \fBFloat(IntSize,FracSize)\fP
This function will match a single floating point number.  It will not
match a number in exponential format.  \fBIntSize\fP is an optional
argument and if specified defines the number of digits to match before
the decimal point.  \fBFracSize\fP is an optional argument and, if
specified, defines the number of digits to match after the decimal point.
@.IP \fBInt(Len)\fP
This function will match a single integer value.  \fBLen\fP is an
optional value which, if given, defines the number of digits in the
integer to match.
@.IP \fBSelect(C1,C2,C3...Cn)\fP
This function will match either \fIC1\fP or \fIC2\fP \fIC3\fP etc.
The arguments are character strings whose first character define one
of the characters to possibly match.
@.IP \fBString(Len)\fP
This function will match a string of arbitrary characters of exactly \fBLen\fP
characters long.
@.IP \fBUpto(Stop)\fP
This function will match a string of arbitrary characters upto, and
including the character given as the first character in \fBStop\fP.
@.LP
A \fBTranslators\fP is a semicolon separated list of translation
functions.  Each translation function has the following syntax:
@.sp
@.nf
Name(Arguments),Label
@.fi
@.sp
where \fBName\fP is a character string which defines the name of the
function to execute.  \fBArguments\fP is a common separated list of
arguments.  The arguments have the same form as for the matching
functions.  The \fB,Label\fP construct is optional and if given
defines a label for the function.  The \fBLabel\fP is an integer value
which is used as a branching address.  Valid translation function
names and the functions they perform are:
@.IP \fBCarriageReturn()\fP
Moves the cursor to the leftmost column.
@.IP \fBCheckModifiers(Modifier,Which,Set)\fP
Queries the values of the modifiers that were returned with the last
\fBGetLastButtonEvent\fP translation function.  \fBModifier\fP is the
number of the positional argument into which the modifier was stored.
\fBWhich\fP specifies which modifier to test.  It can have a value of
\fI"Shift"\fP, \fI"Meta"\fP or \fI"Control"\fP.  \fBSet\fP is the
number of the positional argument into which the result will be
stored.  If the modifier is set then a one is stored in this variable.
Otherwise, a zero is stored.
@.IP \fBClearDisplay(Top,Bottom)\fP
Clears the screen starting at row \fBTop\fP and ending at row
\fBBottom\fP.
@.IP \fBClearLine(Type)\fP
Clears the current line.  If \fBType\fP is equal to \fI0\fP then the
entire line is cleared.  If \fBType\fP is equal to \fI1\fP then the
line is cleared from the cursor to the end of the line.  Finally, if
\fBType\fP is equal to \fI2\fP the line is cleared from the start to
the current cursor position.  Any other value causes a warning message
to be generated.
@.IP \fBClearMemory(Which)\fP
Clears the contents of the off screen memory.  If \fBWhich\fP is equal
to \fI0\fP all the memory is cleared and the screen is blanked.  If
\fBWhich\fP is equal to \fI1\fP the memory below the current screen
position if cleared.  If \fBWhich\fP is equal to 2 the memory above
the current screen position is cleared.
@.IP \fBDefinePen(Num,ForeRed,ForeGround,ForeBlue,BackRed,BackGreen,BackBlue)\fP
Defines the foreground and background colours for the specified pen.
\fBNum\fP is the pen number to change.  It must be within the range of
0 to the \fIXtNnumberColor\fP resource.  \fBForeRed\fP,
\fBForeGreen\fP and \fBForeBlue\fP specify the foreground colour
triple.  If the resource \fIXtNDefineColor\fP is set to \fBGTRGB\fP
then they are the red green and blue colours.  If the resource is
currently \fBGTHSL\fP then these values correspond to the hue
saturation and luminance.  The values are floating point number
ranging from zero to one.  Since the widget does not support floating
point arguments, the values are given as character strings (i.e.
\fIDefinePen(1,"0.45","1.0","0.3","0.0","0.0","0.0")\fP).
\fBBackRed\fP, \fBBackGreen\fP and \fBBackBlue\fP specify the
background colour triple and have the save format and meaning as the
foreground colours.
@.IP \fBDeleteCharacters(Num)\fP
Deletes a number of character from the current line starting at the
current cursor position.  \fBNum\fP is the number of characters to be
deleted.  The characters to the right of the deleted ones will be
pushed left \fBNum\fP spaces.
@.IP \fBDeleteLines(Num)\fP
Deletes a number of lines from the screen starting at the current row.
\fBNum\fP is the number of lines to delete.  Any lines below the
delete ones will roll up on the screen and any data saved in the off the
screen memory below the current screen will be scrolled back onto the
screen.
@.IP \fBDownLine(Num,Wrap)\fP
Moves the cursor down \fBNum\fP lines.  \fBWrap\fP is an integer value
which specifies the behavior of the cursor at the bottom of the screen.
If \fBWrap\fP is equal to 0 the screen will scroll up the required
number of lines to keep the cursor on the screen.  If \fBWrap\fP is
equal to 1 then the cursor will wrap around to the top of the screen.
Finally, if \fBWrap\fP is equal to 2 then the cursor will stick at the
bottom of the screen.
@.IP \fBEmit(String1,String2...)\fP
Invokes the keyboard callback with the passed strings arguments as the
data.  One callback will be generated for each argument given.
\fBString\fP\fIn\fP is the character string to pass to the callback.
@.IP \fBEscapeCallback(Arg1,Arg2...)\fP
Invokes the escape callback with the passed strings as the arguments.
Only one escape callback will be generated per call.  \fBArg\fP\fIn\fP
is the character string to callback in the \fIn\fP-1 position of the
escapes array in the callback structure.
@.IP \fBExecuteFunctionKey(Num)\fP
Cause the widget to execute a function key.  \fBNum\fP is the number
of the function key to execute.
@.IP \fBFetch(From,To)\fP
Fetches a value from a global variable.  The widget maintains a set of
global variables that are guaranteed to maintain their value between
rule executions.  These can be used to store state information for the
parser.  The variables are referenced by their number just as the
positional arguments are.  \fBFrom\fP is the number of the global
variable to fetch the value from.  \fBTo\fP is the number of the
positional argument into which the value should be stored.
@.IP \fBGetArg(Pointer,To)\fP
Implements an indirect reference to a positional argument.
\fBPointer\fP is the number of the positional argument to read the
value from.  This value is interpreted as the number of the
positional argument to return the value of.  \fBTo\fP is the number of
the positional argument to return the result in.  If the value stored
in \fBPointer\fP positional argument is not a valid positional
argument number then a zero is returned.
@.IP \fBGetBottomText(Where)\fP
Returns the number of the last nonblank line currently on the screen.
If all lines contain data then the last visible line is returned.
\fBWhere\fP is the number of the positional argument to store the
result in.
@.IP \fBGetFont(Where)\fP
Determines which font is currently being used.  It returns 0 is the
base font is currently being used and 1 if the alternate font is in
use.  \fBWhere\fP is the number of the positional argument to store
the result in.
@.IP \fBGetLine(Row,Column,Where)\fP
Get the contexts of a line, starting at position \fBRow\fP and
\fBColumn\fP.  The character string will be stored in the positional
argument given by \fBWhere\fP.
@.IP \fBGetLastButton(Button,X,Y,Mods)\fP
Returns information on the last button press event that the widget
processed.  \fBButton\fP is the number of the positional argument into
which the number of the button which was pressed is to be stored.  \fBX\fP
and \fBY\fP are the number of the positional arguments into which the
x and y coordinate of the event are to be stored.  \fBMods\fP is the
number of the positional argument into which the button modifiers are
to be stored.  Further information on the modifiers can be obtained
via the \fBCheckModifiers\fP translator function.
@.IP \fBGetPen(Num)\fP
Returns the number of the pen that is currently being used.  \fBNum\fP
is the number of the positional argument to store the pen number in.
@.IP \fBGetPosition(Row,Column)\fP
Returns the current cursor position.  \fBRow\fP is the number of the
positional argument to store the current row in.  \fBColumn\fP is the
number of the positional argument to store the current column in.
@.IP \fBGetResource(Name,Where)\fP
Gets the current value of the specified resource.  \fBName\fP is the
name of the resource setting to query.  The name should correspond to
the name in the resource file.  \fBWhere\fP is the number of the
positional argument to store the result in.  Currently only integer
valued resources can be properly queried through this function.
@.IP \fBGetScreenSize(Row,Column)\fP
Gets the current size of the screen in rows and columns.  \fBRow\fP is
the number of the positional argument to store the number of rows in.
\fBColumn\fP is the number of the positional argument to store the
number of columns in.
@.IP \fBGetStringLen(String,Where)\fP
Determines the number of characters in the given string.  \fBString\fP
is the string to count the characters in.  \fBWhere\fP is the number
of the positional argument into which the result is to be stored.
@.IP \fBGetSubString(String,Start,End,Result)\fP
Extracts the contents of a string and returns the result.
\fBString\fP is the character string to take the substring from.
\fBStart\fP and \fBEnd\fP specify the starting and ending positions of
the string to be extracted.  \fBWhere\fP is the number of the
positional argument where the substring is to be stored.
@.IP \fBGetTop(Where)\fP
Gets the number of the line in the save screen which corresponds to
the line that is currently at the top of the screen.  \fBWhere\fP is
the number of the positional argument into which the result is to be
stored.
@.IP \fBGetTopOfScrollRegion(Num,Where)\fP
Finds the top row of a specific scroll region and returns the result.
\fBNum\fP is the number of the scroll region to find the top of.
\fBWhere\fP is the number of the positional argument where the result
is to be stored.  If the scroll region does not exist then the
function will return 0, the top of the screen.
@.IP \fBIf(Operand1,Condition,Operand2,Label)\fP
Test to is if a condition is true and performs a branch operation if
it is.  \fBOperand1\fP and \fBOperand2\fP are the two values to test.
\fBCondition\fP is the boolean expression to evaluate.
\fBCondition\fP can have the following values: \fI"="\fP, \fI">"\fP,
\fI">="\fP, \fI"<"\fP, \fI"<="\fP or \fI"!="\fP.  \fBLabel\fP is the
label number to branch to if the result of the operation is true.
When the branch is taken, the parser does not execute the next
translation function in the list but instead searches through the
entire list to find a function whose label equals the specified value.
If no branch label is found the parser stops executing this list.  It
is possible to branch back in the list to create loops.
@.IP \fBIgnore()\fP
This is a do nothing function.  It simply returns.
@.IP \fBInsertLines(Num,Where)\fP
Inserts \fBNum\fP blank lines into the visible screen.  If \fBWhere\fP
is equal to 1 then the lines are inserted after the current row.  If
\fBWhere\fP is equal to 0 then the lines are inserted before the
current row.  All lines below the inserted lines are pushed down
\fBNum\fP lines.  Any lines pushed off the screen are stored in the
off screen memory.
@.IP \fBIntToString(Num,Len,Where)\fP
Performs an explicit integer to string conversion.  \fBNum\fP is the
number to convert.  \fBLen\fP is the number of digits the final string
should have.  The final result will be truncated or padded with
leading zeroes to make the string the proper length.  \fBWhere\fP is
the number of the positional argument to store the result in.
@.IP \fBLoadAttribute(Row,Column)\fP
Set the current attributes to be the same as the characters associated
with the character located at position \fBRow\fP and \fBColumn\fP.
The arguments \fBRow\fP and \fBColumn\fP specify the location of the
character to load.  If the given location is invalid then the default
attributes are loaded.
@.IP \fBLoadMapTable(Num)\fP
Set the current output mapping table to be map table number \fBNum\fP.
\fBNum\fP is the number of the map table to load.
@.IP \fBMath(Operand1,Operation,Operand2,Result)\fP
Performs a specific mathematical operation and returns the result.
\fBOperand1\fP and \fBOperand2\fP are the two operands to perform the
operation on.  \fBOperation\fP is the mathematical operation to
perform.  The valid operations are : \fI"+"\fP, \fI"-"\fP, \fI"*"\fP,
\fI"/"\fP, \fI"%"\fP, \fI">"\fP, \fI"<"\fP and \fI"&"\fP.  The first five
operation correspond to their C language equivalents.  The \fI">"\fP
and \fI"<"\fP operations are the normal C language shift right
and left operations.  \fI"&"\fP is a string concatenation operation.
\fBResult\fP is the number of the positional argument into which the
result is to be stored.
@.IP \fBMoveCursor(Row,Column)\fP
Moves the cursor to the position given by \fBRow\fP and \fBColumn\fP.
If this position is invalid or is off the visible screen then the
cursor will be moved to the closest point to the specified point that
is still on the visible screen.
@.IP \fBMoveLeft(Num,WrapType,RollType)\fP
Moves the cursor left \fBNum\fP columns.  \fBWrapType\fP specifies the
behavior of the cursor when it encounters the leftmost column.  If
\fBWrapType\fP is equal to \fI0\fP then the cursor sticks at the
leftmost column.  If \fBWrapType\fP is equal to \fI1\fP then the
cursor will wrap around to the rightmost column of the previous row.
If the cursor is at the upper left corner of the screen and
\fIRollType\fP is equal to \fI0\fP then the cursor moves to the lower
right corner of the screen.  If \fBRollType\fP is equal to \fI1\fP
then the screen will be scrolled down and the cursor moved to the
rightmost column of the previous row.
@.IP \fBMoveRight(Num,WrapType,RollType)\fP
Moves the cursor right \fBNum\fP columns.  \fBWrapType\fP specifies
the behavior of the cursor when it encounters the rightmost column.
If \fBWrapType\fP is equal to \fI0\fP then the cursor sticks at the
rightmost column.  If \fBWrapType\fP is equal to \fI1\fP then the
cursor will wrap around to the leftmost column of the next row.  If
the cursor is at the lower right corner of the screen and
\fIRollType\fP is equal to \fI0\fP then the cursor will move the the
upper left corner of the screen.  If \fBRollType\fP is equal to
\fI1\fP then the screen will be scrolled up and the cursor moved to
the leftmost column of the next row.
@.IP \fBNewLine()\fP
Moves the cursor down one row.  If the cursor was on the bottom row of
the screen, the screen will be scrolled up one line.
@.IP \fBNextTab()\fP
Moves the cursor to the next tab stop on the current row.  If there
are no more tab stops on the row then the cursor will move to the end
of the line.
@.IP \fBOutputString(String1,String2,Stringn...)\fP
Prints the passed strings on the screen.  The passed arguments
\fBString\fP\fIn\fP are the character strings to print out.  Prior to
printing, the strings are passed through the parser.  The current
positional arguments are saved prior to parsing the strings and reset
after.
@.IP \fBPreviousTab()\fP
Moves the cursor to the previous tab stop on the current row.  If
there are no tab stops to the left of the current position the cursor
will be moved to the leftmost column.
@.IP \fBProgramKey(Type,Number,Label,String)\fP
Programs a specific function key.  \fBType\fP determines what kind of
function key this it.  If \fBType\fP is equal to \fI0\fP then when the key
is executed, its string sent to the terminal for execution and
generates a keyboard callback.  If \fBType\fP is equal to \fI1\fP the
function key is executed locally in the terminal only.  If \fBType\fP
is equal to \fI2\fP then the key generates a keyboard callback only.
\fBNum\fP is the number of the function key to program.  \fBLabel\fP
is the character string that will be printed in the function key label
widget at the bottom of the screen.  \fBString\fP is the character to
string to program the key with.
@.IP \fBProgramMapTable(Num,Start,End,StartVal,EndVal)\fP
Sets the values for the specified output mapping table.  The mapping
table defines the font positions for each ascii character.  Initially,
the mapping table contains a unity translation.  That is to say,
position \fIi\fP in the table contains a value of \fIi\fP.
\fBStart\fP and \fBEnd\fP are the starting and ending points of the
range in the table to perform the programming on.  \fBStartVal\fP and
\fBEndVal\fP define the values the starting and end points should
have.  All points in between are assigned a value falling on a
straight line between \fBStartVal\fP and \fBEndVal\fP.  I.E. the
function \fIProgramMapTable(1,0,32,0,128)\fP would assign a value of
\fI0\fP to table position \fI0\fP a value of \fI4\fP to position
\fI1\fP and so on up to position \fI32\fP which would be assigned a
value of \fI128\fP.
@.IP \fBQuit()\fP
Causes the parser to quit executing the list of translator functions
and begin parsing the next character in the input stream.
@.IP \fBReject()\fP
Causes the parser to reject the matched character sequence.  When a
sequence is reject it is printed on the screen as it would if it never
matched a parser sequence.
@.IP \fBSetBlinkMode(Set)\fP
If \fBSet\fP is equal to \fIone\fP, the blink attribute is turned on for the
current attributes.  If \fBSet\fP is equal to \fIzero\fP then the
blink attribute is turned off.
@.IP \fBSetField()\fP
Copies the current attribute setting through out the current field.
It may also create a new field.  A field is a section of text on the
screen which have the same attributes.  When text is written on the
screen it inherits its attributes from the field and not the current
settings.  If the cursor is positioned at the beginning of a defined
field, then the attribute is set through out that field.  If the
cursor position in currently in the middle of a field then the current
field is truncated to the position immediately to the left of the
cursor.  A new field is then defined from the current position to the
end of the previous field.  The current attribute is copied through
out this field.  Initially, each field contains one field extending
the entire length of the line.
@.IP \fBSetFlow(Type)\fP
Invokes a flow callback. If \fBType\fP is equal to \fI1\fP, the reason
for the callback will be \fIGTE_XON\fP.  If \fBType\fP is equal to
\fI0\fP, the reason for the callback will be \fIGTE_XOFF\fP.
@.IP \fBSetFont(Type)\fP
Sets the font for the current attribute.  If \fBType\fP is equal
\fI0\fP the base font will be set.  If \fBType\fP is equal to \fI1\fP
then the alternate font will be used.
@.IP \fBSetHalfBrightMode(Flag)\fP
If \fBFlag\fP is equal to \fI1\fP then the half bright attribute is
set for the current attributes.  If \fBFlag\fP is equal to \fI0\fP
then it is cleared.
@.IP \fBSetInsertMode(Flag)\fP
If \fBFlag\fP is equal to \fI1\fP then the widget is placed in insert
mode.  If \fBFlag\fP is equal to \fI0\fP then insert mode is turned
off.
@.IP \fBSetInverseVideo(Flag)\fP
If \fBFlag\fP is equal to \fI1\fP then the inverse video attribute is
set for the current attributes.  If \fBFlag\fP is equal to \fI0\fP
then it is cleared.
@.IP \fBSetKeyTable(Name)\fP
Loads the specified key table.  \fBName\fP is the name of the key
table to load as it is specified in the parse file.
@.IP \fBSetParseTable(Name)\fP
Sets the current parse table to be the one associated in the parse
file with the name \fBName\fP.  \fBName\fP is a character string which
specifies the name of the parse table to load.  If the name is invalid
then the current parse table remains loaded.  With this function, the
widget can change the type of terminal it is emulating.
@.IP \fBSetPen(Num)\fP
Set the pen number for the current attribute.  \fBNum\fP is the pen
number to set to.
@.IP \fBSetResource(Name,Val)\fP
Set the value of a specific X resource.  \fBName\fP is the name of the
X resource of the widget to set.  It should correspond to the name
that would be used in the resource file.  \fBVal\fP is the value to
set it to.  Currently only integer and boolean valued resources can be
set with this function.
@.IP \fBSetScrollRegion(Start,End,Num)\fP
Defines a scroll region with in the visible screen.  \fBStart\fP and
\fBEnd\fP are the starting and ending rows of the scroll region.
\fBNum\fP is the number to assign to the scroll region.  Each scroll
region should have a unique number.  By convention scroll region
number zero is the entire visible screen.
@.IP \fBSetUnderLineMode(Flag)\fP
If \fBFlag\fP is equal to \fI1\fP then the underline attribute is set
for the current attributes.  If \fBFlag\fP is equal to \fI0\fP then
the underline attribute is cleared.
@.IP \fBSetTab(Col)\fP
Set a tap stop at the specified column on the current row.  \fBCol\fP
is the number of the column to set the tab stop on.
@.IP \fBSetTop(Num)\fP
Set the top line of the visible screen to correspond to line number
\fBNum\fP in the save screen.
@.IP \fBSoundBell()\fP
Cause the terminal to beep.
@.IP \fBStore(Val,Where)\fP
Store the value of argument \fBVal\fP in the global variable whose
position number if equal to \fBWhere\fP.
@.IP \fBToAscii(Num,String)\fP
Returns the ascii equivalent character.  \fBNum\fP is the number to
convert to ascii.  \fBString\fP is the number of the positional
argument to return the character in.
@.IP \fBUpLine(Num,WrapType)\fP
Moves the cursor up \fBNum\fP lines.  \fBWrapType\fP specifies the
behavior of the cursor when it encounters the top of the visible
screen.  If \fBWrapType\fP is equal to \fI0\fP the screen will scroll
down the required number of lines to keep the cursor on the visible
screen.  If \fBWrapType\fP is equal to \fI1\fP the cursor will wrap
around to the bottom of the screen.  If \fBWrapType\fP is equal to \fI2\fP
then the cursor will stick to the top.
@.IP \fBUnSetTab(Col)\fP
Clears a tab stop at a specific column on the current row.  \fBCol\fP
is the number of the column to set the tab on.
@.sp 1
@.SH "EXAMPLE PARSE FILE"
@.sp
Below is a simple sample parser file.  It contains key mappings for
the arrow keys and the home key.  It defines escape sequences for
newlines, carriage returns and tabs, as well as escapes to move the
cursor around and perform cursor positioning.
@.nf
@.sp 1
# A Simple example parser
# A Simple example parser
KeyTable(Default)=
{
Up,I,^[[1A
Down,I,^[[1B
Right,I,^[[1C
Left,I,^[[1D
Home,O,^[H
}
}
ParseTable(Default)=
{
^J{NewLine()}
^M{CarriageReturn()}
^G{SoundBell()}
^I{NextTab()}
^K{DeleteLines(1)}
^[[<Int(),1>A{If($1,"<",0,1);UpLine($1,2);Quit();\\
	Math($1),"*",-1,2),1;DownLine($2,2)}
^[[<Int(),1>B{DownLine($1,2)}
^[[<Int(),1>C{MoveRight($1,0,0)}
^[[<Int(),1>D{MoveLeft($1,0,0)}
^[[<Int(),1>;<Int(),2>E{MoveCursor($1,$2)}
^[H{MoveCursor(0,0)}
}
@.fi
@.sp
@.SH "ENTRY POINTS"
In addition to the normal widget functions, the \fIGenTermEm\fP widget
also contains the functions which can be called from the application
program.
@.ta .2i 1.2i
@.\"
@.IP "\fBint GtEOutput(Term,String,Len)\fP"
@.sp
@.nf
\fB\tWidget\tTerm
\tchar *\tString
\tint\tLen\fP
@.fi
@.sp
This is the main output routine for the widget.  \fBTerm\fP is the
widget instance's record.  \fBString\fP is a pointer to a character
string and \fBLen\fP is the number of characters in the string.  This
function prints the string on the screen.  The string is passed
through the parser prior to printing to interprets any escape
sequences it may contain.  If the screen is currently locked then the
function will enqueue the string for printing at the next available instance.
The function returns \fIGTE_DONE\fP if the request completes
successfully and \fIGTE_WAIT\fP if the widget is currently locked or
waiting for a graphics expose event.  In the latter case, the
application program should not call \fBGtEOutput\fP again until it has
received a wakeup callback.  If the application does not honour this
request then the widget will be forced to allocate large amounts of
memory for its input queue which can have negative effects on program
performance.  If output logging is currently enable, a copy of the
string will be written into the log file.
@.sp
@.SH "RELATED INFORMATION"
\fBCore(3X)\fP, \fBComposite(3X)\fP, \fBGenTerm(3X)\fP
@EOF
set `wc -lwc <GenTerm/GenTermEm.man`
if test $1$2$3 != 825604339494
then
	echo ERROR: wc results of GenTerm/GenTermEm.man are $* should be 825 6043 39494
fi

chmod 644 GenTerm/GenTermEm.man

echo x - GenTerm/LoadParser.c
cat >GenTerm/LoadParser.c <<'@EOF'
/* Parse.c : This file contains the section of the terminal emulator parser */
/*   which loads the parse file. */
/* 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 <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"

#define BUFSIZ 1024
#define EOL -2

struct Buffer
{
 int nchar;
 int pos;
 int started;
 int escape;
 char buffer[BUFSIZ];
 FILE *File;
};

static struct ParseItem *CreatePItem();
static struct ParseItem *GtELoadParseTable();
static struct KeyTranslations *LoadKeyTable();
static int GetNextToken();
static struct Translator *GetTranslatorToken();
static struct SpecialItem *GetSpecialToken();
static struct ArgumentList *BuildArgList();
static void GetFunctionToken();
static char *BufferGets();
static int BufferGetc();

extern struct FuncDefs Translators[];

extern struct FuncDefs Specials[];

GtELoadParseFile(w)

GenTermEmWidget w;

{
 struct Buffer InBuffer;
 char string[1024];
 struct GtEList *temp;
 int i,j;

 InBuffer.nchar = 0;
 InBuffer.pos = 0;
 InBuffer.started = 0;
 if((InBuffer.File = fopen(w->genTermEm.ParseFile,"r")) == NULL)
  XtAppError(XtWidgetToApplicationContext(w),
	     "GenTermEm Widget can't find parse Table!");
 
 w->genTermEm.ParseList = NULL;
 w->genTermEm.KeyList = NULL;

 while(BufferGets(&InBuffer,string,1024) != NULL)
  {
   if(strncmp(string,KEYTOKEN,strlen(KEYTOKEN)) == 0)/*start of a key table?*/
    {
     temp = (struct GtEList *)XtMalloc(sizeof(struct GtEList));
     j = i = strlen(KEYTOKEN) + 1;
     while((string[j++] != ')') && (string[j] != NULL));
     if(string[j] == NULL)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget finds bad parser file!");
     string[j-1] = NULL;
     strcpy(temp->Name,&(string[i]));
     while((i = BufferGetc(&InBuffer) != (int)'{') && (i != EOF));
     if(i == EOF)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget finds bad parser file");
     BufferGets(&InBuffer,string,1024);
     temp->Point.KeyTable = LoadKeyTable(w,&InBuffer);
     temp->Num = w->genTermEm.NumKeys;
     temp->Next = w->genTermEm.KeyList;
     w->genTermEm.KeyList = temp;
    }
   else if(strncmp(string,PARSETOKEN,strlen(PARSETOKEN)) == 0)
    {
     temp = (struct GtEList *) XtMalloc(sizeof(struct GtEList));
     j = i = strlen(PARSETOKEN) + 1;
     while((string[j++] != ')') && (string[j] != NULL));
     if(string[j] == NULL)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget finds bad parser file!");
     string[j-1] = NULL;
     strcpy(temp->Name,&(string[i]));
     while((i = BufferGetc(&InBuffer) != (int)'{') && (i != EOF)); 
     if(i == EOF)
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget finds bad parser file");
     BufferGets(&InBuffer,string,1024);
     temp->Point.ParseTable = GtELoadParseTable(w,&InBuffer);
     BufferGets(&InBuffer,string,1024);
     temp->Next = w->genTermEm.ParseList;
     w->genTermEm.ParseList = temp;
    }
   else
    XtAppError(XtWidgetToApplicationContext(w),
	       "GenTermEm Widget finds bad parser file");
  }
 temp = w->genTermEm.ParseList;
 while(temp != NULL)
  {
   if(strcmp(temp->Name,DEFAULT) == 0)
    {
     w->genTermEm.ParseTable = temp->Point.ParseTable;
     break;
    }
   temp = temp->Next;
  }
 if(temp == NULL)
  XtAppError(XtWidgetToApplicationContext(w),
	     "GenTermEm Widget doesn't find default parse table");

 temp = w->genTermEm.KeyList;
 while(temp != NULL)
  {
   if(strcmp(temp->Name,DEFAULT) == 0)
    {
     w->genTermEm.Keys = temp->Point.KeyTable;
     w->genTermEm.NumKeys = temp->Num;
     break;
    }
   temp = temp->Next;
  }
 if(temp == NULL)
  XtAppError(XtWidgetToApplicationContext(w),
	     "GenTermEm Widget doesn't find default key table"); 

 fclose(InBuffer.File);
   
}

/* BufferGets:  This function returns the rest of the current line */

static char *BufferGets(InBuffer,string,len)

struct Buffer *InBuffer;
char *string;
int len;

{
 int i,j;
 char *temp;

 if(InBuffer->pos >= InBuffer->nchar)
  {
   while((temp = fgets(InBuffer->buffer,BUFSIZ,InBuffer->File)) != NULL)
    if((InBuffer->buffer[0] != '#') &&  (InBuffer->buffer[0] != '\n'))
     break;
   if(temp == NULL)
    return(NULL);
   InBuffer->nchar = strlen(InBuffer->buffer);
   InBuffer->pos = 0;
  }
 j = 0;
 i = InBuffer->pos;
 while(i < InBuffer->nchar)
  {
   switch(InBuffer->buffer[i])
    {
   case '^':
    string[j++] = InBuffer->buffer[i+1] & 077;
     i++;
     break;
  case  '\\':
    if(InBuffer->buffer[i+1] == '\n')
     {
      fgets(InBuffer->buffer,BUFSIZ,InBuffer->File);
      i = InBuffer->pos = 0;
      InBuffer->nchar = strlen(InBuffer->buffer);
     }
    else
     {
      string[j++] = InBuffer->buffer[i+1];
      i++;
     }
    break;
  case ' ':
  case '\t':
    break;
  default:
    string[j++] = InBuffer->buffer[i];
    break;
   }
   i++;
   if(j == len)
    {
     InBuffer->pos = i;
     return(string);
    }
  }
 string[j] = NULL;
 InBuffer->pos = i;
 return(string);
}

static int BufferGetc(InBuffer)

struct Buffer *InBuffer;

{
 int c;
 char *string;

 if(InBuffer->pos >= InBuffer->nchar)
  {
   while((string = fgets(InBuffer->buffer,BUFSIZ,InBuffer->File)) != NULL)
    if((InBuffer->buffer[0] != '#') && (InBuffer->buffer[0] != '\n'))
     break;
   if(string == NULL)
    return(EOF);
   InBuffer->nchar = strlen(InBuffer->buffer);
   InBuffer->pos = 0;
  }

 c = -99;
 InBuffer->escape = False;
 while(c == -99)
  {
   switch(InBuffer->buffer[InBuffer->pos])
    {
   case '^':
     c = InBuffer->buffer[InBuffer->pos+1] & 077;
     InBuffer->pos++;
     break;
   case  '\\':
     if(InBuffer->buffer[InBuffer->pos+1] == '\n')
      {
       fgets(InBuffer->buffer,BUFSIZ,InBuffer->File);
       InBuffer->pos = 0;
       InBuffer->nchar = strlen(InBuffer->buffer);
      }
     else
      {
       c = InBuffer->buffer[InBuffer->pos+1];
       InBuffer->escape = True;
       InBuffer->pos++;
      }
     break;
   case '\n':
     c = EOL;
     break;
   case ' ':
   case '\t':
     break;
   default:
     c = InBuffer->buffer[InBuffer->pos];
     break;
    }
   InBuffer->pos++;
  }
 return((int)c);
}

static struct ParseItem *GtELoadParseTable(w,InBuffer)

GenTermEmWidget w;
struct Buffer *InBuffer;

{
 struct ParseItem *Table;
 struct ParseItem *NewItem;
 struct ParseItem *NextItem;
 int NextToken;
 char c;
 int StartLine;
 struct SpecialItem *special;
 struct Translator *translator;


 Table = CreatePItem();
 NextItem = Table;

 while(((NextToken=GetNextToken(w,InBuffer,&c,&special,&translator,
			       &StartLine)) != EOFTOKEN) &&
       (NextToken != EOTTOKEN))
  switch(NextToken)
   {
  case ENDTOKEN:     /* reset parser to top of table */
    NextItem = Table;
    break;
  case TOKENCHAR:
    if(NextItem->empty == 0)
     {
      NextItem->c = c;
      NextItem->empty = 1;
      NextItem->child = CreatePItem();
      NextItem = NextItem->child;
     }
    else
     {
      while(NextItem->next != NULL)
       {
	if(NextItem->c == c)
	 break;
	/*if((NextItem->translators != NULL) || (NextItem->special != NULL))
	 XtAppError(XtWidgetToApplicationContext(w),
		    "GenTermEmWidget encounters an ambigous grammar!");*/
	NextItem = NextItem->next;
       }
      if(NextItem->c == c)
       {
	if(NextItem->child != NULL)
	 NextItem = NextItem->child;
	else
	 {
	  if(NextItem->translators != NULL)
	   XtAppError(XtWidgetToApplicationContext(w),
		      "GenTermEmWidget encounters an ambigous grammar!");
	  else
	   {  /* hmmm... can this ever happen? */
	    NextItem->child = CreatePItem();
	    NextItem = NextItem->child;
	   }
	 }
       }
      else
       {
	NextItem->next = CreatePItem();
	NextItem->next->c = c;
	NextItem->next->empty = 1;
	NextItem->next->child = CreatePItem();
	NextItem = NextItem->next->child;
       }
     }
    break;
  case SPECIALCHARTOKEN:
    if(NextItem->empty != 0)
     {
/* here we have a potential problem with my parser design.  I don't want to */
/* be in the position of running the grammar through a list of special */
/* matching functions so I have to make sure at any point in the parse table */
/* there is only one possible special matching function to execute.  But, it */
/* possible for there to be many branches in the tree after the special match*/
/* so it is possible to try to insert a special match function where one */
/* already exists, providing it is the same function.  But, the arguments and*/
/* storage position of the function may be different.  This is supported */
/* under my grammar.  For each case, the special matcher must receive the */
/* same arguments and store its results in the same position.  Here I check */
/* the position indicator but I don't check the argument list, I simply use */
/* the first one I find. */
      if((NextItem->special->func == special->func) &&
	 (NextItem->special->position == special->position))
       NextItem = NextItem->child;
      else
       XtAppError(XtWidgetToApplicationContext(w),
		  "GenTermEmWidget encounters an ambigous grammar!");
     }
    else
     {
      NextItem->empty = 1;
      NextItem->special = special;
      NextItem->child = CreatePItem();
      NextItem = NextItem->child;
     }
    break;
  case TRANSLATIONTOKEN:
    if(NextItem->empty != 0)
     XtAppError(XtWidgetToApplicationContext(w),
		"GenTermEmWidget encounters an ambigous grammar!");
    else
     {
      NextItem->empty = 1;
      NextItem->translators = translator;
      NextItem->child = CreatePItem();
      NextItem = NextItem->child;
     }
   }
 return(Table);
}

static struct KeyTranslations *LoadKeyTable(w,InBuffer)

GenTermEmWidget w;
struct Buffer *InBuffer;

{
 struct KeyTranslations Keys[1024];
 struct KeyTranslations *Table;
 char buffer[1024];
 char next;
 int k,j,l;
 int i = 0;

 while(BufferGets(InBuffer,buffer,1024)  != NULL)
  {
   buffer[strlen(buffer)-1] = NULL;  /* get rid of trailing newline */
   if(buffer[0] == '}')
    break;
   k = -1;
   while((buffer[++k] != ',') && (buffer[k] != '(') && (buffer[k] != NULL));
   if(buffer[k] == NULL)
    XtAppError(XtWidgetToApplicationContext(w),
	       "GenTermEm Widget finds bad key translation table");
   next = buffer[k];
   buffer[k] = NULL;
   Keys[i].sym = XStringToKeysym(buffer);
   if(Keys[i].sym == NoSymbol)
    XtAppError(XtWidgetToApplicationContext(w),
	       "GenTermEm Widget finds bad keysym in translation table");
   Keys[i].state = 0;
   if(next == '(')   /* are there any modifiers? */
    {
     while(next != ')')
      {
       j = k+1;
       while((buffer[++k] != ',') && (buffer[k] != ')') && 
	     (buffer[k] != NULL));
       if(buffer[k] == NULL)
	XtAppError(XtWidgetToApplicationContext(w),
		   "GenTermEm Widget find bad modifier in translation table");
       next = buffer[k];
       buffer[k] = NULL;
       for(l = 0; w->genTermEm.Mods[l].Name != NULL; l++)
	{
	 if(strcmp(w->genTermEm.Mods[l].Name,&(buffer[j])) == 0)
	  {
	   Keys[i].state |= w->genTermEm.Mods[l].Mask;
	   break;
	  }
	}
       if(w->genTermEm.Mods[l].Name == NULL)
	XtAppError(XtWidgetToApplicationContext(w),
		   "GenTermEm Widget finds bad keysym in translation table");
      }
     k++;
     if(buffer[k++] != ',')
      XtAppError(XtWidgetToApplicationContext(w),
		 "GenTermEm Widget finds bad keysym in translation table");
    }
   else
    {
     k++;
     Keys[i].state = 0;
    }
   Keys[i].type = buffer[k++];
   if(buffer[k++] != ',')
    XtAppError(XtWidgetToApplicationContext(w),
	       "GenTermEm Widget finds bad keytable syntax");
   Keys[i].string = XtMalloc(strlen(&(buffer[k])+1));
   j = 0;
   while(buffer[k] != NULL)
    {
     Keys[i].string[j++] = buffer[k++];
    }
   Keys[i].len = j;
   i++;
  }
 Table = (struct KeyTranslations *)
  XtMalloc(sizeof(struct KeyTranslations)*i);
 for(j = 0; j < i; j++)
  {
   Table[j].sym = Keys[j].sym;
   Table[j].state = Keys[j].state;
   Table[j].type = Keys[j].type;
   Table[j].string = Keys[j].string;
   Table[j].len = Keys[j].len;
  }
 w->genTermEm.NumKeys = i;

 return(Table);
}
     
static struct ParseItem *CreatePItem()

{
 struct ParseItem *p;

 p = (struct ParseItem *) XtMalloc(sizeof(struct ParseItem));
 p->empty = 0;
 p->c = NULL;
 p->next = NULL;
 p->child = NULL;
 p->special = NULL;
 p->translators = NULL;

 return(p);
}

static int GetNextToken(w,InBuffer,c,special,translator,StartLine)

GenTermEmWidget w;
struct Buffer *InBuffer;
char *c;
struct SpecialItem **special;
struct Translator **translator;
int *StartLine;

{
 int input;
 char nextchar;
 int token = UNKNOWNTOKEN;

 if((input = BufferGetc(InBuffer)) == EOF)
  return(EOFTOKEN);

 nextchar = (char)input;

 while(token == UNKNOWNTOKEN)
  {
   if(InBuffer->escape)
    {
     *c = nextchar;
     token = TOKENCHAR;
     *StartLine = 0;
    }
   else
    {
     switch(input)
      {
     case '<' :
      *special = GetSpecialToken(w,InBuffer);
      *StartLine = 0;
      token = SPECIALCHARTOKEN;
      break;
    case '{' :
     *translator = GetTranslatorToken(w,InBuffer);
      *StartLine = 0;
      token = TRANSLATIONTOKEN;
      break;
    case EOL:
      *StartLine = 1;
      token = ENDTOKEN;
      break;
    case '}':
      token = EOTTOKEN;
      break;
/*    case '\\':
      *c = BufferGetc(InBuffer);
      *StartLine = 0;
      token = TOKENCHAR;
      break;*/
    default:
      *c = nextchar;
      *StartLine = 0;
      token = TOKENCHAR;
      break;
     }
    }
  }
 return(token);
}

static struct Translator *GetTranslatorToken(w,InBuffer)

GenTermEmWidget w;
struct Buffer *InBuffer;

{
 struct Translator *temp;
 char TranslationName[1024];
 int tlen;
 char Args[1024];
 int alen;
 int i = -1;
 int j;
 int c;

 GetFunctionToken(w,InBuffer,TranslationName,&tlen,Args,&alen);

 temp = (struct Translator *) XtMalloc(sizeof(struct Translator));
 temp->next = NULL;
 temp->func = NULL;
 while(Translators[++i].func != NULL)
  if(strcmp(Translators[i].name,TranslationName) == 0)
   {
    temp->func = Translators[i].func;
    break;
   }
 if(temp->func == NULL)
  {
   sprintf(Args,"Error, invalid special function found %s",TranslationName);
   XtAppError(XtWidgetToApplicationContext(w),Args);
  }
 temp->arglist = BuildArgList(Args,alen);
 if((i = BufferGetc(InBuffer)) == ';')
  temp->next = GetTranslatorToken(w,InBuffer);
 else if(i == ',')
  {
   j = 0;
   while(((c = BufferGetc(InBuffer)) != '}') && (c != ';'))
    {
     if(c == EOF)
      XtAppError(XtWidgetToApplicationContext(w),
		 "Unexpected End of File Found");
     Args[j++] = (char) c;
    }
   Args[j] = NULL;
   if(sscanf(Args,"%d",&(temp->label)) != 1)
    XtAppError(XtWidgetToApplicationContext(w),"Bad Label Indicator");
   if(c == ';')
    temp->next = GetTranslatorToken(w,InBuffer);
  }
 else if(i != '}')
  while(((i = BufferGetc(InBuffer)) != '}') && (i != EOF));
 return(temp);
}

static struct SpecialItem *GetSpecialToken(w,InBuffer)

GenTermEmWidget w;
struct Buffer *InBuffer;

{
 struct SpecialItem *temp;
 char SpecialName[1024];
 int slen;
 char Args[1024];
 int alen;
 int i = -1;
 int c;

 GetFunctionToken(w,InBuffer,SpecialName,&slen,Args,&alen);

 temp = (struct SpecialItem *) XtMalloc(sizeof(struct SpecialItem));
 temp->func = NULL;
 while(Specials[++i].func != NULL)
  if(strcmp(Specials[i].name,SpecialName) == 0)
   {
    temp->func = Specials[i].func;
    break;
   }
 if(temp->func == NULL)
  {
   sprintf(Args,"Error, invalid special function found %s",SpecialName);
   XtAppError(XtWidgetToApplicationContext(w),Args);
  }
 temp->arglist = BuildArgList(Args,alen);
 
 c = BufferGetc(InBuffer);
 i = 0;
 if(c == ',')
  {
   while((c = BufferGetc(InBuffer)) != '>')
    {
     if(c == EOF)
      XtAppError(XtWidgetToApplicationContext(w),
		 "Unexpected End of File Found");
     Args[i++] = (char) c;
    }
   Args[i] = NULL;
   if(sscanf(Args,"%d",&(temp->position)) != 1)
    XtAppError(XtWidgetToApplicationContext(w),"Bad Position Indicator");
  }
 else
  temp->position = 0;	 
 return(temp);
}

static void GetFunctionToken(w,InBuffer,FuncName,flen,ArgList,alen)

GenTermEmWidget w;
char *FuncName;
int *flen;
char *ArgList;
int *alen;

{
 int c;

 *flen = 0;
 *alen = 0;

 while((c = BufferGetc(InBuffer)) != '(')
  {
   if(c == EOF)
    XtAppError(XtWidgetToApplicationContext(w),"Premature end of file found");
   FuncName[(*flen)++] = (char) c;
  }
 FuncName[*flen] = NULL;
 while((c = BufferGetc(InBuffer)) != ')')
  {
   if(c == EOF)
    XtAppError(XtWidgetToApplicationContext(w),"Premature end of file found");
   ArgList[(*alen)++] = (char) c;
  }
 ArgList[*alen] = NULL;
}

static struct ArgumentList *BuildArgList(args,alen)

char *args;
int alen;

{
 struct Arguments buffer[20];
 struct ArgumentList *temp;
 int bcount = 0;
 int i = 0;
 int k;

 while(i < alen)
  {
   if(args[i] == '"')     /* start of a string */
    {
     i++;
     buffer[bcount].type = ASTRING;
     buffer[bcount].string = &(args[i]);
     k = i;
     while(args[i] != '"')
      {
       if(args[i] == NULL)
	return(NULL);
       i++;
      }
     buffer[bcount++].n = i-k;
     i++;
    }
   else if(args[i] == '$')   /* positional argument */
    {
     buffer[bcount].type = APOSITION;
     i++;
     if(sscanf(&(args[i]),"%d",&(buffer[bcount++].n)) != 1)
      return(NULL);
     while((i < alen) && (args[i++] != ','));
    }
   else if((isdigit(args[i])) ||(args[i] == '-') || (args[i] == '+'))
    {
     buffer[bcount].type = AINT;
     if(sscanf(&(args[i]),"%d",&(buffer[bcount++].n)) != 1)
      return(NULL);
     while((i < alen) && (args[i++] != ','));
    }
   else if(args[i] == ',')
    i++;
   else
    return(NULL);
  }

 temp = (struct ArgumentList *)XtMalloc(sizeof(struct ArgumentList));
 temp->NumArgs = bcount;

 temp->args = (struct Arguments *)XtMalloc(sizeof(struct Arguments)*bcount);
 for(i = 0; i < bcount; i++)
  {
   temp->args[i].type = buffer[i].type;
   if(buffer[i].type == ASTRING)
    {
     temp->args[i].string = (char *) XtMalloc(sizeof(char) * buffer[i].n+1);
     strncpy(temp->args[i].string,buffer[i].string,buffer[i].n);
    }
   temp->args[i].n = buffer[i].n;
  }
 return(temp);
}
@EOF
set `wc -lwc <GenTerm/LoadParser.c`
if test $1$2$3 != 763200018601
then
	echo ERROR: wc results of GenTerm/LoadParser.c are $* should be 763 2000 18601
fi

chmod 644 GenTerm/LoadParser.c

echo x - GenTerm/Makefile
cat >GenTerm/Makefile <<'@EOF'
INCLUDE=-I/usr/include/X11R4 -I/usr/include/Motif1.1 -I/usr/contrib/X11R4
LIBS=-L/usr/lib/X11R4 -L/usr/lib/Motif1.1 -lXv -lXm -lXt -lXmu -lXext -lX11
OBJS = GenTerm.o GenTermEm.o Parse.o LoadParser.o Pty.o
SRC = GenTerm.c GenTermEm.c Parse.c LoadParser.c Pty.c
CFLAGS=-O $(INCLUDE)

#all : ctest TAGS

lib : libTermWidget.a

libTermWidget.a : $(OBJS)
	ar -cr libTermWidget.a $(OBJS)

test : test.o $(OBJS)
	cc $(CFLAGS) -o test test.o $(OBJS) $(LIBS)

test.o : test.c

ctest : ctest.o $(OBJS)
	cc $(CFLAGS) -o ctest ctest.o $(OBJS) $(LIBS)

ctest.o : ctest.c

Pty.o : Pty.c Pty.h

GenTerm.o : GenTerm.c GenTerm.h GenTermP.h

GenTermEm.o : GenTermEm.c GenTermEm.h GenTermEmP.h GenTerm.h GenTermP.h

LoadParser.o : LoadParser.c GenTermEm.h GenTermEmP.h GenTerm.h GenTermP.h Parser.h

Parse.o : Parse.c GenTermEm.h GenTermEmP.h GenTerm.h GenTermP.h Parser.h

TAGS : $(SRC)
	etags $(SRC)

clean :
	rm -f *.o core test ctest libTermWidget.a *~

install :
	-mkdir $(PARSEDIR)
	chmod 0555 $(PARSEDIR)
	cpset hpterm.par $(PARSEDIR) 0444 bin bin
	cpset xterm.par $(PARSEDIR) 0444 bin bin

installall :
	-mkdir $(PARSEDIR)
	chmod 0555 $(PARSEDIR)
	cpset hpterm.par $(PARSEDIR) 0444 bin bin
	cpset xterm.par $(PARSEDIR) 0444 bin bin
	cpset libTermWidget.a $(LIBDIR) 0444 bin bin
	cpset GenTerm.man $(MANDIR)/man3/GenTerm.3 0444 bin bin
	cpset GenTermEm.man $(MANDIR)/man3/GenTermEm.3 0444 bin bin
	cpset Pty.man $(MANDIR)/man3/Pty.3 0444 bin bin
	cpset Pty.h $(INCDIR) 0444 bin bin
	cpset PtyP.h $(INCDIR) 0444 bin bin
	cpset GenTerm.h $(INCDIR) 0444 bin bin
	cpset GenTermP.h $(INCDIR) 0444 bin bin
	cpset GenTermEm.h $(INCDIR) 0444 bin bin
	cpset GenTermEmP.h $(INCDIR) 0444 bin bin



@EOF
set `wc -lwc <GenTerm/Makefile`
if test $1$2$3 != 632141677
then
	echo ERROR: wc results of GenTerm/Makefile are $* should be 63 214 1677
fi

chmod 644 GenTerm/Makefile

echo x - GenTerm/Parser.h
cat >GenTerm/Parser.h <<'@EOF'
/* 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. */
#define PARSEFILE "./hpterm.par"
#define UNKNOWNTOKEN    -1
#define EOFTOKEN         0
#define ENDTOKEN         1
#define TOKENCHAR        2
#define SPECIALCHARTOKEN 3
#define TRANSLATIONTOKEN 4
#define EOTTOKEN         5

#define ASTRING   1
#define AINT      2
#define APOSITION 3

#define TRANSOKAY   0
#define TRANSERROR  -1
#define TRANSREJECT -2

#define PARSETOKEN "ParseTable"
#define KEYTOKEN   "KeyTable"
#define DEFAULT    "Default"
@EOF
set `wc -lwc <GenTerm/Parser.h`
if test $1$2$3 != 30130890
then
	echo ERROR: wc results of GenTerm/Parser.h are $* should be 30 130 890
fi

chmod 644 GenTerm/Parser.h

echo x - GenTerm/Pty.h
cat >GenTerm/Pty.h <<'@EOF'
/* 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. */
#ifndef _READPtyh
#define _READPtyh

#include "GenTermEm.h"

extern WidgetClass ptyWidgetClass;

typedef struct _PtyClassRec *PtyWidgetClass;
typedef struct _PtyRec *PtyWidget;

#define XtNmasterPtyName       "masterPtyName"
#define XtNslavePtyName        "slavePtyName"
#define XtNmasterPtyDescriptor "masterPtyDescriptor"
#define XtNslavePtyDescriptor  "slavePtyDescriptor"
#define XtNmasterPtyOpenMode   "masterPtyOpenMode"
#define XtNslavePtyOpenMode    "slavePtyOpenMode"
#define XtNttyMode             "ttyMode"
#define XtNptyCallback         "ptyCallback"

#define XtCMasterPtyName       "MasterPtyName"
#define XtCSlavePtyName        "SlavePtyName"
#define XtCMasterPtyDescriptor "MasterPtyDescriptor"
#define XtCSlavePtyDescriptor  "SlavePtyDescriptor"
#define XtCMasterPtyOpenMode   "MasterPtyOpenMode"
#define XtCSlavePtyOpenMode    "SlavePtyMode"
#define XtCTtyMode             "TtyMode"
#define XtCPtyCallback         "PtyCalback"

#define PTY_OPEN       1
#define PTY_IOCTL      2
#define PTY_SLAVEOPEN  3
#define PTY_SLAVECLOSE 4

typedef struct ptyCallback
{
 int reason;
 int MasterPtyDescriptor;
 int SlavePtyDescriptor;
 struct termios *Termios;
} PtyCallback;


#endif _READPtyh
@EOF
set `wc -lwc <GenTerm/Pty.h`
if test $1$2$3 != 531731645
then
	echo ERROR: wc results of GenTerm/Pty.h are $* should be 53 173 1645
fi

chmod 644 GenTerm/Pty.h

echo x - GenTerm/PtyP.h
cat >GenTerm/PtyP.h <<'@EOF'
/* PtyP.h -- Private definitions for the Pty 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. */

#ifndef _ReadPtyP
#define _ReadPtyP

#include <X11/X.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>

#include "Pty.h"
#include "GenTermEmP.h"
#include "GenTermP.h"

#define TTYIMODE 1
#define TTYOMODE 2
#define TTYCMODE 3
#define TTYLMODE 4
#define TTYCCHAR 5
#define TTYSPEED 6
#define TTYSIZE 7

#define TTYNOW 1
#define TTYLATER 2

#define TTYROW 1
#define TTYCOLUMN 2

struct TtyMode
{
 char *Name;
 int Invertable;
 int Type;
 int When;
 tcflag_t Mask;
};

typedef struct 
{
 int dummy;
} PtyClassPart;

/* our full class declaration */

typedef struct _PtyClassRec
{
 CoreClassPart core_class;
 CompositeClassPart composite_class;
 GenTermClassPart genTerm_class;
 GenTermEmClassPart genTermEm_class;
 PtyClassPart pty_class;
} PtyClassRec;

/* new fields for our widget record */

typedef struct
{
/* public resources */

 char *TtyModes;             /* the termio settings */
 XtCallbackList PtyCallbacks;

/* public read-only resources */

 int MasterPtyOpenModes;     /* the arguments to give the open() call */
 int SlavePtyOpenModes;
 char *MasterPtyName;        /* the filename of the master Pty */
 char *SlavePtyName;         /* filename of the slave side of the Pty */
 int MasterDescriptor;       /* master side file descriptor */
 int SlaveDescriptor;        /* slave side file descriptor */

/* private data */

 XtInputId OutputId;
 XtInputId ExceptId;
 char StartChar;
 Boolean StartAny;
 Boolean FlowEnabled;
 Boolean WriteEnabled;
 char *Storage;
 int StoreSize;
 int NumStore;
} PtyPart;

/* our full instance record */

typedef struct _PtyRec
{
 CorePart core;
 CompositePart composite;
 GenTermPart genTerm;
 GenTermEmPart genTermEm;
 PtyPart pty;
} PtyRec;

#endif _ReadPtyP
@EOF
set `wc -lwc <GenTerm/PtyP.h`
if test $1$2$3 != 1053092211
then
	echo ERROR: wc results of GenTerm/PtyP.h are $* should be 105 309 2211
fi

chmod 644 GenTerm/PtyP.h

echo x - GenTerm/Xmu.h
cat >GenTerm/Xmu.h <<'@EOF'
/*
 * $XConsortium: Xmu.h,v 1.26 89/07/16 14:12:37 jim Exp $
 *
 * Copyright 1988 by the Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided 
 * that the above copyright notice appear in all copies and that both that 
 * copyright notice and this permission notice appear in supporting 
 * documentation, and that the name of M.I.T. not be used in advertising
 * or publicity pertaining to distribution of the software without specific, 
 * written prior permission. M.I.T. makes no representations about the 
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * The X Window System is a Trademark of MIT.
 *
 * The interfaces described by this header file are for miscellaneous utilities
 * and are not part of the Xlib standard.
 */

#ifndef _XMU_H_
#define _XMU_H_

/*
 * This include file is obsolete and is provided only for compatibility with
 * MIT Release 3 clients.  Callers should use the appropriate include file.  
 *
 * DO NOT ADD ANY NEW INCLUDES OR DEFINITIONS TO THIS FILE!
 */
#include <X11/Intrinsic.h>
#include <X11/Xmu/Atoms.h>		/* _XA_... */
#include <X11/Xmu/CharSet.h>		/* CopyISOLatin1Lowered */
#include <X11/Xmu/Converters.h>		/* CvtStringTo... */
#include <X11/Xmu/Drawing.h>		/* DrawRoundedRect, DrawLogo */
#include <X11/Xmu/Error.h>		/* PrintDefaultError */
#include <X11/Xmu/StdSel.h>		/* ConvertStandardSelection */

#endif /* _XMU_H_ */

@EOF
set `wc -lwc <GenTerm/Xmu.h`
if test $1$2$3 != 402371576
then
	echo ERROR: wc results of GenTerm/Xmu.h are $* should be 40 237 1576
fi

chmod 444 GenTerm/Xmu.h

echo x - xcontrol/Makefile
cat >xcontrol/Makefile <<'@EOF'
INCLUDE=-I/usr/include/X11R4 -I/usr/include/Motif1.1 -I/usr/contrib/X11R4 -I../GenTerm
LIBS=-L/usr/lib/X11R4 -L/usr/lib/Motif1.1 -L../GenTerm -lTermWidget -lXv -lXm -lXt -lXmu -lXext -lX11
OBJS = XControl.o ParseString.o Command.o
SRC = XControl.c ParseString.c Command.c
CFLAGS=-O $(INCLUDE)

all :  XControl TAGS

XControl : $(OBJS)
	cc $(CFLAGS) -o XControl $(OBJS)  $(LIBS)

XControl.o : XControl.c XControl.h

ParseString.o : ParseString.c XControl.h

Command.o : Command.c XControl.h

TAGS : $(SRC)
	etags $(SRC)

install :
	sed -e s%PARSEDIR%$(PARSEDIR)% <XControl.ad >XControl.temp
	cpset XControl.temp /usr/lib/X11/app-defaults/XControl 0444 bin bin
	rm XControl.temp
	sed -e s%PARSEDIR%$(PARSEDIR)% <XVi.ad >XVi.temp
	cpset XVi.temp /usr/lib/X11/app-defaults/XVi 0444 bin bin
	cpset XControl $(BINDIR) 0555 bin bin
	ln -s $(BINDIR)/XControl $(BINDIR)/XVi
	cpset XControl.man $(MANDIR)/man1/XControl.1 0444 bin bin

clean :
	rm -f *.o *.temp a.out core *~ XControl
@EOF
set `wc -lwc <xcontrol/Makefile`
if test $1$2$3 != 32108974
then
	echo ERROR: wc results of xcontrol/Makefile are $* should be 32 108 974
fi

chmod 644 xcontrol/Makefile

exit 0
From: tonyc@a4430ux.esr.hp.com ( Tony Cox (SR) )
Date: Mon, 25 Jan 1993 13:58:15 GMT
Subject: Re: SLIP?
Organization: Hewlett-Packard Rockville