[comp.sources.x] v05i037: macro-string enhancement for Xterm, Part01/01

argv@island.uu.net (Dan Heller) (12/06/89)

Submitted-by: uunet!zax!sci!jimmc (Jim McBeath)
Posting-number: Volume 5, Issue 37
Archive-name: macstr/part01



#! /bin/sh
##  This is a shell archive.  Remove anything before this line, then unpack
##  it by saving it into a file and typing "sh file".  To overwrite existing
##  files, type "sh file -c".  You can also feed this as standard input via
##  unshar, or by typing "sh <file".  If this archive is complete, you will
##  see the following message at the end:
#		"End of shell archive."
# Contents:  README.macrostr xterm.man.diff Imakefile.diff
#   Makefile.diff ptyx.h.diff charproc.c.diff macrostr.c
# Wrapped by jimmc@zax on Mon Nov 13 17:14:21 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README.macrostr -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README.macrostr\"
else
echo shar: Extracting \"README.macrostr\" \(553 characters\)
sed "s/^X//" >README.macrostr <<'END_OF_README.macrostr'
XThe macro string package is intended to allow xterm to generate the character
Xsequences for button presses on just about any terminal you can think of.
XIt is a general enough mechanism that you may find other uses for it as well.
XInstallation requires the addition of one major new file (macrostr.c) and some
Xone-line changes to a few other files.  See the updated man pages for details
Xon how the macro string capability is used.  Copyright has been donated to
XMIT using their standard copyright notice.
X
XJim McBeath	13.Nov.89
Xsci!jimmc@decwrl.dec.com
END_OF_README.macrostr
if test 553 -ne `wc -c <README.macrostr`; then
    echo shar: \"README.macrostr\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f xterm.man.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xterm.man.diff\"
else
echo shar: Extracting \"xterm.man.diff\" \(14424 characters\)
sed "s/^X//" >xterm.man.diff <<'END_OF_xterm.man.diff'
X1c1
X< .TH XTERM 1 "25 October 1988" "X Version 11"
X---
X> .TH XTERM 1 " 7 November 1989" "X Version 11"
X222c222
X< cause the window to be repositioned automatically in the normal postion at the
X---
X> cause the window to be repositioned automatically in the normal position at the
X264c264
X< This option indicates that a visual bell is prefered over an audible one.
X---
X> This option indicates that a visual bell is preferred over an audible one.
X286c286
X< This option specifies the prefered size and position of the Tektronix window.
X---
X> This option specifies the preferred size and position of the Tektronix window.
X290c290
X< This option specifies the prefered position of the icon window.
X---
X> This option specifies the preferred position of the icon window.
X316c316
X< instead of the user's shell.  \fBThis option has been superceeded by the new
X---
X> instead of the user's shell.  \fBThis option has been superceded by the new
X358c358
X< This option specifies the prefered size and position of the VT102 window;
X---
X> This option specifies the preferred size and position of the VT102 window;
X376c376
X< Specifies the prefered size and position of the application when iconified.
X---
X> Specifies the preferred size and position of the application when iconified.
X457c457
X< Specifies the prefered size and position of the VT102 window.
X---
X> Specifies the preferred size and position of the VT102 window.
X460c460
X< Specifies the prefered size and position of the Tektronix window.
X---
X> Specifies the preferred size and position of the Tektronix window.
X713c713
X< To distinquish a pointer button from a key, the high bit of the character is
X---
X> To distinguish a pointer button from a key, the high bit of the character is
X785c785
X< X environments differ in their security conciousness.  The servers provided
X---
X> X environments differ in their security consciousness.  The servers provided
X911a912,919
X> .B macro-string(\fImacro-string\fB)
X> Rebinds the key or key sequence to the macro-string value.
X> When this action is executed, the macro string is processed, which normally
X> inserts a string into the input stream.
X> This capability is useful for emulating the wide variety of character sequences
X> that are produced by a button press on various terminals.
X> For more details, see the section "MACRO STRINGS" below.
X> .TP 15
X994a1003,1368
X> .SH "MACRO STRINGS"
X> .PP
X> Xterm includes a fairly general macro-string processing capability intended
X> to allow emulation of the button-press sequences of just about any terminal
X> type.
X> The macro-string processor is a simple stack machine which interprets a
X> macro string.
X> The macro string can contain commands which access state information
X> (such as the X and Y location of the mouse), manipulate the stack (such
X> as doing arithmetic operations), and insert text into the terminal
X> input buffer (which is the desired end result of the macro string).
X> There are rudimentary programming commands (conditional execution,
X> subroutine calls), built-in primitives and macro strings, and user-definable
X> macro strings.
X> .PP
X> A macro string is interpreted one token at a time.
X> Operations are expressed in RPN, i.e. operands first (which are placed onto
X> the stack) followed by operation (which operates on the stack).
X> White space in a macro string is ignored.
X> If there is an error in processing a macro string, the Bell() function
X> is called.
X> .PP
X> There are two data types: integer and string.
X> Boolean operations result in an integer where FALSE is represented by
X> 0 and TRUE is represented by 1.
X> When interpreting an integer as a Boolean, 0 is considered
X> FALSE and anything else is considered TRUE.
X> When interpreting a string as a Boolean, NULL or the empty string is
X> considered FALSE and anything else is considered TRUE.
X> .PP
X> In the descriptions below, the term TOS represents the value of the
X> top item on the stack, TOS-1 is the next-to-top, etc.
X> .PP
X> The macro-string commands are as follows:
X> .TP 15
X> .B "\'string\'"
X> Single-quoted string.
X> Pushes the quoted string onto the stack.
X> The string can contain any character except NULL and single quote.
X> There is no backslash notation and no provision for including a single
X> quote within a single-quoted string.
X> You can use a double-quoted string if you need to include a single
X> quote in your string.
X> Note also that the various parsers used to load this string (i.e. the
X> C compiler if it is a built-in macro string, or the resource manager if
X> it is from a resource or default file) can handle backslash notation, so
X> you can include control characters in a quoted string.
X> .TP 15
X> .ft 3
X> "string"
X> .}N
X> Double-quoted string.
X> Pushes the quoted string onto the stack.
X> This behaves in exactly the same way as a single-quoted string, except that
X> when using a double-quoted string you can include single quotes in the
X> string but not double quotes.
X> .TP 15
X> .B "printf formatting"
X> You can convert TOS to a string using standard printf formatting commands.
X> For example, if TOS is the integer 123, then the command "%04d" would
X> replace TOS with the string "0123", and the command "%X" would replace
X> TOS with the string "7B".
X> The formatting string is only a single "%" sequence, and only converts
X> the top item on the stack to a string.
X> .TP 15
X> .B "+"
X> Add or catenate.
X> If TOS and TOS-1 are both integers,
X> replaces TOS and TOS-1 with (TOS-1 + TOS).
X> If TOS and TOS-1 are both strings, replaces TOS and TOS-1 with
X> the catenation of TOS-1 and TOS.
X> .TP 15
X> .B "-"
X> Subtract.
X> Replaces TOS and TOS-1 with (TOS-1 - TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "*"
X> Multiply.
X> Replaces TOS and TOS-1 with (TOS-1 * TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "/"
X> Integer divide.
X> Replaces TOS and TOS-1 with (TOS-1 / TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "<<"
X> Left shift.
X> Replaces TOS and TOS-1 with (TOS-1 << TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B ">>"
X> Right shift.
X> Replaces TOS and TOS-1 with (TOS-1 >> TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "|"
X> Bitwise OR.
X> Replaces TOS and TOS-1 with (TOS-1 | TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "||"
X> Logical OR.
X> Replaces TOS and TOS-1 with (TOS-1 || TOS).
X> TOS and TOS-1 are independently considered as Booleans.
X> .TP 15
X> .B "&"
X> Bitwise AND.
X> Replaces TOS and TOS-1 with (TOS-1 & TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "&&"
X> Logical AND.
X> Replaces TOS and TOS-1 with (TOS-1 && TOS).
X> TOS and TOS-1 are independently considered as Booleans.
X> .TP 15
X> .B "^"
X> Bitwise XOR.
X> Replaces TOS and TOS-1 with (TOS-1 ^ TOS).
X> TOS and TOS-1 must both be integers.
X> .TP 15
X> .B "^^"
X> Logical XOR.
X> Replaces TOS and TOS-1 with (TOS-1 ^^ TOS).
X> TOS and TOS-1 are independently considered as Booleans.
X> .TP 15
X> .B "!"
X> Logical NOT.
X> Replaces TOS by the logical inverse of TOS when considered as a Boolean.
X> .TP 15
X> .B "~"
X> Bitwise invert.
X> Replaces TOS by the bitwise inversion of TOS.
X> TOS must be an integer.
X> .TP 15
X> .B number
X> Numbers can be entered in decimal, octal or hexadecimal radix.
X> A simple string of digits, not starting with a 0, pushes a decimal
X> value onto the stack.
X> If the first digit in the string is 0 and the remainder of digits are
X> between 0 and 7, the number is input as an octal number and pushed onto
X> the stack.
X> If the first digit in the string is 0 and it is immediately followed
X> by x or X, the number is input as a hexadecimal number and pushed onto
X> the stack.
X> .TP 15
X> .B b
X> Pushes the button field from a button event onto the stack.
X> .TP 15
X> .B c
X> Pushes the cursor column from a key or button event onto the stack.
X> The leftmost column is column 0.
X> .TP 15
X> .B C
X> Pushes the column width of the screen onto the stack.
X> .TP 15
X> .B h
X> Pushes the pixel height of a character onto the stack.
X> .TP 15
X> .B H
X> Pushes the pixel height of the screen onto the stack.
X> .TP 15
X> .B i
X> Places TOS (must be a string) into the terminal input buffer
X> and pops it off the stack.
X> .TP 15
X> .B k
X> Pushes the keycode field from a key event onto the stack.
X> .TP 15
X> .B l
X> Puts the results of XLookupString on a key event onto the stack.
X> If XLookupString returns an error or no string, an empty string is
X> pushed onto the stack.
X> .TP 15
X> .B M
X> Pop TOS (which must be a string) and interpret the macro of that name.
X> The macro may be either a primitive or built-in (both compiled into xterm)
X> or a user-defined macro.
X> User defined macros override built-in macros, but not primitives.
X> The list of primitives and built-in macros is given below.
X> .TP 15
X> .B r
X> Pushes the cursor row from a key or button event onto the stack.
X> The topmost row is 0.
X> .TP 15
X> .B R
X> Pushes the row height of the screen onto the stack.
X> .TP 15
X> .B s
X> Pushes the state field from a key or button event onto the stack.
X> .TP 15
X> .B w
X> Pushes the pixel width of a character onto the stack.
X> .TP 15
X> .B W
X> Pushes the pixel width of the screen onto the stack.
X> .TP 15
X> .B x
X> Pushes the x pixel value from a key or button event onto the stack.
X> .TP 15
X> .B X
X> Pushes to x_root pixel value from a key or button event onto the stack.
X> .TP 15
X> .B y
X> Pushes the y pixel value from a key or button event onto the stack.
X> .TP 15
X> .B Y
X> Pushes the y_root pixel value from a key or button event onto the stack.
X> .TP 15
X> .B Z
X> Conditionally returns from (terminates) a macro.
X> Pops TOS and interprets it as a Bool; if TRUE, returns from the macro,
X> else does nothing.
X> .PP
X> Primitive functions are compiled into Xterm and can not be overridden.
X> The primitives are:
X> .TP 15
X> .B error
X> Generates an error; calls Bell() and aborts all macro string processing.
X> This is typically used with an "if" statement to abort a macro if
X> an error condition occurs.
X> .TP 15
X> .B exch
X> Exchanges TOS with TOS-1.
X> .TP 15
X> .B if
X> Examines TOS-1 as a Boolean; if TRUE, executes the macro named at TOS,
X> else does nothing.
X> In either case, the two values are popped off the stack before the
X> test is performed.
X> .TP 15
X> .B ifElse
X> Examines TOS-2 as a Boolean; if TRUE, executes the macro named at TOS-1,
X> else executes the macro named at TOS.
X> In either case, the three values are popped off the stack before the
X> test is performed.
X> .TP 15
X> .B limit
X> Limits TOS-2 to be between TOS-1 and TOS.
X> If TOS-2 is less than TOS-1, replaces it with TOS-1.
X> If TOS-2 is greater than TOS, replaces it with TOS.
X> All three items must be integers.
X> Pops two items off the stack, leaving only the limited number.
X> .TP 15
X> .B ord
X> Converts a one-character string at TOS to an integer with the
X> equivalent integer value (essentially a "scanf %c").
X> .TP 15
X> .B pop
X> Pops one item off the stack and discards it.
X> .TP 15
X> .B push
X> Pushes the top item onto the stack again, duplicating it.
X> .TP 15
X> .B tekScale
X> Pushes the tekScale field of the screen onto the stack.
X> Useful for emulating the Tektronix mode buttons.
X> .TP 15
X> .B toBool
X> Converts TOS to a Boolean (integer 0 or 1).
X> 
X> .PP
X> There are a number of built-in macros, which are simply macro strings
X> which are compiled into xterm.
X> These built-ins can be overridden by a user defined macro.
X> The built-ins are listed below, with the definitions of some given
X> as examples.
X> .TP 15
X> .B SeikoButton
X> Generates the character sequence for button presses on a Seiko terminal.
X> There are a number of associated built-ins that are a part of this package:
X> SeikoGetX, SeikoGetY, SeikoSub1, SeikoEnd.
X> To set up your xterm so that it generates Seiko character sequences for
X> the buttons when the shift key is held down, you could add the following
X> lines to your resource file:
X> .sp
X> .Ds
X>  *VT100.translations: #override \\n\\
X> 	Shift <BtnDown> : macro-string("'SeikoButton'M") \\n\\
X> 	Shift <BtnUp> : ignore()
X> .De
X> .TP 15
X> .B X10Button
X> Generates the character sequence that the X10 xterm generated for button
X> pushes.
X> This macro is implemented with this string:
X> .sp
X> .Ds
X>  '\\033[M'i31b+%ci33c+%ci33r+%ci
X> .De
X> .TP 15
X> .B VT200ButtonPress
X> Generates the character sequence for a VT200 button press.
X> This macro is implemented with this string:
X> .sp
X> .Ds
X>  '\\033['iM31'VT200KeyState'M+b+%ci33c+%ci33r+%ci
X> .De
X> .TP 15
X> .B VT200KeyState
X> Called by the VT200ButtonPress macro.
X> This macro is implemented with this string:
X> .sp
X> .Ds
X>  s5&s8&2>>+
X> .De
X> .TP 15
X> .B TekButton
X> Generates the character sequence for a Tektronix button press.
X> Associated macros are TekGetBchar, TekGetlbchar, TekUcase, and TekSub1.
X> .TP 15
X> .B TestConst
X> Generates a character string with a number of screen-dependent values,
X> implemented with this string:
X> .sp
X> .Ds
X>  'h='ih%di' w='iw%di' H='iH%di' W='iW%di' R='iR%di' C='iC%di'\\n'i
X> .De
X> .TP 15
X> .B TestButton
X> Generates a character string with a number of position-dependent values,
X> suitable for binding to a button,
X> implemented with this string:
X> .sp
X> .Ds
X>  'x='ix%di' y='iy%di' X='iX%di' Y='iY%di\\
X>  ' r='ir%di' c='ic%di' b='ib%di' s='is%xi'\\n'i
X> .De
X> .TP 15
X> .B TestKey
X> Generates a character string with a number of position-dependent values,
X> suitable for binding to a key,
X> implemented with this string:
X> .sp
X> .Ds
X>  'x='ix%di' y='iy%di' X='iX%di' Y='iY%di\\
X>  ' r='ir%di' c='ic%di' k='ik%di' s='is%xi' l=\\"'ili'\\"\\n'i
X> .De
X> .PP
X> You could add the following bindings to execute the test macros to
X> see how the values look:
X> .sp
X> .Ds
X>  *VT100.translations: #override \\n\\
X> 	<Key>F5 : macro-string("'TestConst'M") \\n\\
X> 	<Key>F6 : macro-string("'TestKey'M")
X> .De
X> .PP
X> User defined macros can be specified in your resource or Xdefaults file.
X> Macros are searched for as subresources of the xterm widget, where the
X> subobject name is "macroString" and the subresource name is the macro name.
X> For example, to define a macro named foo that prints out the string
X> "button" and the button number, you could put this line in your resource file:
X> .sp
X> .Ds
X>  *VT100.macroString.foo: 'button 'i b%di
X> .De
X> .PP
X> You could then bind this macro to a key with a line like:
X> .sp
X> .Ds
X>  *VT100.translations: #override \\n\\
X> 	<Key>F7 : macro-string("'foo'M")
X> .De
X> 
X1125c1499
X< Consortium), Dave Serisky (HP)
X---
X> Consortium), Dave Serisky (HP), Jim McBeath (Silicon Compilers)
END_OF_xterm.man.diff
if test 14424 -ne `wc -c <xterm.man.diff`; then
    echo shar: \"xterm.man.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Imakefile.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Imakefile.diff\"
else
echo shar: Extracting \"Imakefile.diff\" \(1173 characters\)
sed "s/^X//" >Imakefile.diff <<'END_OF_Imakefile.diff'
X*** Imakefile.orig	Thu May 18 19:57:44 1989
X--- Imakefile	Fri Oct 27 13:44:02 1989
X***************
X*** 27,36 ****
X  /* add -DWTMP and -DLASTLOG if you want them */
X          DEFINES = -DMODEMENU -DUTMP -DBcopy=bcopy GettyProgram
X            SRCS1 = button.c charproc.c cursor.c data.c input.c \
X! 		  main.c menu.c misc.c screen.c scrollbar.c tabs.c \
X  		  TekPrsTbl.c Tekproc.c util.c VTPrsTbl.c
X            OBJS1 = main.o input.o charproc.o cursor.o util.o tabs.o \
X! 		  screen.o scrollbar.o button.o Tekproc.o misc.o \
X  		  VTPrsTbl.o TekPrsTbl.o data.o menu.o
X            SRCS2 = resize.c
X            OBJS2 = resize.o
X--- 27,36 ----
X  /* add -DWTMP and -DLASTLOG if you want them */
X          DEFINES = -DMODEMENU -DUTMP -DBcopy=bcopy GettyProgram
X            SRCS1 = button.c charproc.c cursor.c data.c input.c \
X! 		  macrostr.c main.c menu.c misc.c screen.c scrollbar.c tabs.c \
X  		  TekPrsTbl.c Tekproc.c util.c VTPrsTbl.c
X            OBJS1 = main.o input.o charproc.o cursor.o util.o tabs.o \
X! 		  screen.o scrollbar.o button.o Tekproc.o misc.o macrostr.o \
X  		  VTPrsTbl.o TekPrsTbl.o data.o menu.o
X            SRCS2 = resize.c
X            OBJS2 = resize.o
END_OF_Imakefile.diff
if test 1173 -ne `wc -c <Imakefile.diff`; then
    echo shar: \"Imakefile.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile.diff\"
else
echo shar: Extracting \"Makefile.diff\" \(1055 characters\)
sed "s/^X//" >Makefile.diff <<'END_OF_Makefile.diff'
X*** Makefile.orig	Fri Oct 27 12:58:09 1989
X--- Makefile	Fri Oct 27 15:39:17 1989
X***************
X*** 167,176 ****
X  
X          DEFINES = -DMODEMENU -DUTMP -DBcopy=bcopy
X            SRCS1 = button.c charproc.c cursor.c data.c input.c \
X! 		  main.c menu.c misc.c screen.c scrollbar.c tabs.c \
X  		  TekPrsTbl.c Tekproc.c util.c VTPrsTbl.c
X            OBJS1 = main.o input.o charproc.o cursor.o util.o tabs.o \
X! 		  screen.o scrollbar.o button.o Tekproc.o misc.o \
X  		  VTPrsTbl.o TekPrsTbl.o data.o menu.o
X            SRCS2 = resize.c
X            OBJS2 = resize.o
X--- 167,176 ----
X  
X          DEFINES = -DMODEMENU -DUTMP -DBcopy=bcopy
X            SRCS1 = button.c charproc.c cursor.c data.c input.c \
X! 		  macrostr.c main.c menu.c misc.c screen.c scrollbar.c tabs.c \
X  		  TekPrsTbl.c Tekproc.c util.c VTPrsTbl.c
X            OBJS1 = main.o input.o charproc.o cursor.o util.o tabs.o \
X! 		  screen.o scrollbar.o button.o Tekproc.o misc.o macrostr.o \
X  		  VTPrsTbl.o TekPrsTbl.o data.o menu.o
X            SRCS2 = resize.c
X            OBJS2 = resize.o
END_OF_Makefile.diff
if test 1055 -ne `wc -c <Makefile.diff`; then
    echo shar: \"Makefile.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ptyx.h.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ptyx.h.diff\"
else
echo shar: Extracting \"ptyx.h.diff\" \(701 characters\)
sed "s/^X//" >ptyx.h.diff <<'END_OF_ptyx.h.diff'
X*** ptyx.h.orig	Thu May 18 19:56:42 1989
X--- ptyx.h	Tue Nov  7 09:23:09 1989
X***************
X*** 191,196 ****
X--- 191,202 ----
X  	int height;
X  } BitmapBits;
X  
X+ typedef struct _userMacro {
X+ 	struct _userMacro *next;
X+ 	String name;
X+ 	String value;
X+ } UserMacro;
X+ 
X  #define	SAVELINES		64      /* default # lines to save      */
X  
X  typedef struct {
X***************
X*** 344,349 ****
X--- 350,356 ----
X  	Atom*		selection_atoms; /* which selections we own */
X  	Cardinal	sel_atoms_size;	/*  how many atoms allocated */
X  	Cardinal	selection_count; /* how many atoms in use */
X+ 	UserMacro	*userMacros;	/* list of user macro-strings */
X  } TScreen;
X  
X  /* meaning of bits in screen.select flag */
END_OF_ptyx.h.diff
if test 701 -ne `wc -c <ptyx.h.diff`; then
    echo shar: \"ptyx.h.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f charproc.c.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"charproc.c.diff\"
else
echo shar: Extracting \"charproc.c.diff\" \(741 characters\)
sed "s/^X//" >charproc.c.diff <<'END_OF_charproc.c.diff'
X*** charproc.c.orig	Thu May 18 19:58:00 1989
X--- charproc.c	Fri Oct 27 13:45:47 1989
X***************
X*** 164,169 ****
X--- 164,170 ----
X  extern void HandleLeaveWindow();
X  extern void HandleFocusChange();
X         void HandleKeymapChange();
X+ extern void HandleMacroString();
X  extern void HandleModeMenu();
X  extern void HandleInsertSelection();
X  extern void HandleSelectStart();
X***************
X*** 210,215 ****
X--- 211,217 ----
X      { "insert",		  HandleKeyPressed },
X      { "insert-selection", HandleInsertSelection },
X      { "keymap", 	  HandleKeymapChange },
X+     { "macro-string",	  HandleMacroString },
X      { "mode-menu",	  HandleModeMenu },
X      { "secure",		  HandleSecure },
X      { "select-start",	  HandleSelectStart },
END_OF_charproc.c.diff
if test 741 -ne `wc -c <charproc.c.diff`; then
    echo shar: \"charproc.c.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f macrostr.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"macrostr.c\"
else
echo shar: Extracting \"macrostr.c\" \(24964 characters\)
sed "s/^X//" >macrostr.c <<'END_OF_macrostr.c'
X/* macrostr.c - handle macro string capability
X *
X * 26.Oct.89  Jim McBeath	Initial definition
X */
X
X/*
X * Copyright 1989 Massachusetts Institute of Technology
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of M.I.T. not be used in advertising or
X * publicity pertaining to distribution of the software without specific,
X * written prior permission.  M.I.T. makes no representations about the
X * suitability of this software for any purpose.  It is provided "as is"
X * without express or implied warranty.
X *
X * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
X * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
X * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
X * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
X * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X *
X * Author:  Jim McBeath, Silicon Compiler Systems
X *          sci!jimmc@decwrl.dec.com
X */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <ctype.h>
X#include "ptyx.h"
X
X#define TOS (stackCount-1)
X#define PUSHINT(n) if (!StackPushInt(n)) return FALSE
X
X/* inverse of CursorX and CursorY macros (except no topline used in Row) */
X#define CursorRow(screen,Y) (((Y) - screen->border)/FontHeight(screen))
X#define CursorCol(screen,X) (((X) - screen->scrollbar - screen->border) \
X	/ FontWidth(screen))
X
Xextern char *malloc(), *realloc();
X
Xenum MacStackType { MacStackNull, MacStackInt, MacStackString };
X
Xtypedef struct _macstackentry {
X	enum MacStackType type;
X	union {
X		char *s;
X		int n;
X	} d;
X} MacStackEntry;
X
X/* The static variables in this module have a lifetime which is limited
X * to a single call to HandleMacroString.
X */
X
Xstatic Widget stackWidget;
Xstatic TScreen *stackScreen;
Xstatic XEvent *stackEvent;
X
X/* The value stack used by all of the macro processing functions */
Xstatic int stackAlloc;
Xstatic int stackCount;
Xstatic MacStackEntry *stack;
X
X/* A string buffer used by various parsing functions */
Xstatic int stackQAlloc;
Xstatic int stackQCount;
Xstatic char *Qstr;
X
X/* forward references for PrimTab */
Xextern int PrimToBool();
Xextern int PrimNot();
Xextern int PrimIfTrue();
Xextern int PrimIfElse();
Xextern int PrimPop();
Xextern int PrimPush();
Xextern int PrimExch();
Xextern int PrimLimit();
Xextern int PrimOrd();
Xextern int PrimReturn();
Xextern int PrimError();
Xextern int PrimTekScale();
X
X/* Table of named primitive functions */
Xstatic struct {
X	char *name;	/* name of the primitive function */
X	int (*func)();	/* returns TRUE if all OK, FALSE if problem */
X} PrimTab[] = {
X	{"error",	PrimError},
X	{"exch",	PrimExch},
X	{"if",		PrimIfTrue},
X	{"ifElse",	PrimIfElse},
X	{"limit",	PrimLimit},
X	{"ord",		PrimOrd},
X	{"pop",		PrimPop},
X	{"push",	PrimPush},
X	{"tekScale",	PrimTekScale},
X	{"toBool",	PrimToBool},
X};
X
X/* Table of built-in macro strings */
Xstatic struct {
X	char *name;	/* name of the built-in macro string */
X	char *str;	/* contents of the macro string */
X} BuiltinTab[] = {
X	{"SeikoButton",
X"'\033J'i'SeikoGetX'M'SeikoSub1'M'SeikoGetY'M'SeikoSub1'M'SeikoEnd'M"},
X	{"SeikoGetX",	"x48*w/1890-"},
X	{"SeikoGetY",	"1537y64*h/-"},
X	{"SeikoSub1",
X"'push'M'push'M10>>037&0140|%ci5>>037&0100|%ci037&040|%ci"},
X	{"SeikoEnd",	"' 'i31b3&+%ci'! !\r'i"},
X	{"X10Button",	"'\033[M'i31b+%ci33c+%ci33r+%ci"},
X	{"VT200KeyState",	"s5&s8&2>>+"},
X	{"VT200ButtonPress", "'\033['iM31'VT200KeyState'M+b+%ci33c+%ci33r+%ci"},
X	{"VT200ButtonOther", "'\033['iM32'VT200KeyState'M+3+%ci33c+%ci33r+%ci"},
X	{"TekButton",	"'TekGetBchar'M%ci\
Xx'tekScale'M/0 4096 1- 'limit'M'TekSu1'M \
X3072 34+ y'tekScale'/- 0 3072 1- 'limit'M'TekSub1'M"},
X	{"TekGetBchar",	"'TekGetlbchar'M s 1 & 'TekUcase' 'if'M 0x80 |"},
X	{"TekGetlbchar", "\
X'r' 'ord'M b 1 == Z 'pop'M \
X'm' 'ord'M b 2 == Z 'pop'M \
X'l' 'ord'M b 3 == Z 'error'M"},
X	{"TekUcase",	"32 -"},
X	{"TekSub1",	"'push'M 7>>037&040|%ci 2>>037&040|%ci"},
X	{"TestConst",
X"'h='ih%di' w='iw%di' H='iH%di' W='iW%di' R='iR%di' C='iC%di'\n'i"},
X	{"TestButton",
X"'x='ix%di' y='iy%di' X='iX%di' Y='iY%di\
X' r='ir%di' c='ic%di' b='ib%di' s='is%xi'\n'i"},
X	{"TestKey",
X"'x='ix%di' y='iy%di' X='iX%di' Y='iY%di\
X' r='ir%di' c='ic%di' k='ik%di' s='is%xi' l=\"'ili'\"\n'i"},
X};
X
X
Xstatic int
Xishexalpha(c)
Xchar c;
X{
X	return (c>='a'&&c<='f' || c>='A'&&c<='F');
X}
X
X/* Value stack manipulation functions */
X
Xstatic void
XStackClear()	/* clear the stack */
X{
X	int i;
X
X	for (i=0; i<stackCount; i++) {		/* free all strings */
X		if (stack[i].type == MacStackString) {
X			if (stack[i].d.s)
X				free(stack[i].d.s);
X		}
X	}
X	stackCount = 0;
X}
X
Xstatic void
XStackPop(n)
Xint n;		/* pop N items off the top of the stack */
X{
X	while (n>0 && stackCount>0) {
X		if (stack[TOS].type == MacStackString) {
X			if (stack[TOS].d.s)
X				free(stack[TOS].d.s);
X		}
X		n--;
X		stackCount--;
X	}
X}
X
Xstatic Bool	/* TRUE if successful, FALSE it not (no more memory) */
XStackPush(e)
XMacStackEntry *e;
X{
X	int nbytes;
X
X	if (stackCount>=stackAlloc) {
X		/* need more room */
X		if (stackAlloc)
X			stackAlloc *= 2;
X		else
X			stackAlloc = 15;
X		nbytes = stackAlloc * sizeof(stack[0]);
X		if (stack)
X			stack = (MacStackEntry *)realloc((char *)stack,nbytes);
X		else
X			stack = (MacStackEntry *)malloc(nbytes);
X		if (!stack)
X			return FALSE;
X	}
X	stack[stackCount] = *e;	/* copy in structure */
X		/* note that we do not do any string copies here */
X	stackCount++;
X	return TRUE;
X}
X
Xstatic Bool	/* TRUE if successful, FALSE it not (no more memory) */
XStackPushString(s)
Xchar *s;	/* the string becomes the property of the stack */
X{
X	MacStackEntry e;
X	Bool t;
X
X	e.type = MacStackString;
X	e.d.s = s;
X	t = StackPush(&e);
X	if (!t) {
X		free(s);	/* it's our string - don't leak the memory */
X	}
X	return t;
X}
X
Xstatic Bool	/* TRUE if successful, FALSE it not (no more memory) */
XStackPushStringCopy(s)
Xchar *s;	/* makes a copy of the string to put onto the stack */
X{
X	char *newstr;
X
X	newstr = malloc(strlen(s)+1);
X	if (!newstr)
X		return FALSE;
X	strcpy(newstr,s);
X	return (StackPushString(newstr));
X}
X
Xstatic Bool	/* TRUE if successful, FALSE it not (no more memory) */
XStackPushInt(n)
Xint n;
X{
X	MacStackEntry e;
X	Bool t;
X
X	e.type = MacStackInt;
X	e.d.n = n;
X	t = StackPush(&e);
X	return t;
X}
X
X
X/* String buffer manipulation functions */
X
Xstatic void
XStackQclear()
X{
X	stackQCount = 0;
X}
X
Xstatic Bool	/* TRUE is successful, FALSE if not (no more memory) */
XStackQchar(c)
Xchar c;
X{
X	int nbytes;
X
X	if (stackQCount>=stackQAlloc) {
X		/* need more room */
X		if (stackQAlloc)
X			stackQAlloc *= 2;
X		else
X			stackQAlloc = 120;
X		nbytes = stackQAlloc;
X		if (Qstr)
X			Qstr = realloc(Qstr,nbytes);
X		else
X			Qstr = malloc(nbytes);
X		if (!Qstr)
X			return FALSE;
X	}
X	Qstr[stackQCount++] = c;
X	return TRUE;
X}
X
X/* handles quoted strings; parses string and pushes it onto the stack */
X/* Note that we do NOT do any backslash processing */
Xstatic char *	/* returns pointer to the closing quote char or NULL on error */
XStackQstr(p,stopchar)
Xchar *p;	/* pointer to first data char */
Xchar stopchar;	/* the character to stop on */
X{
X	StackQclear();
X	while (*p && *p!=stopchar) {
X		if (!StackQchar(*p))
X			return NULL;	/* no more memory */
X		p++;
X	}
X	if (!*p)
X		return NULL;	/* no terminating quote */
X	if (!StackQchar(0))
X		return NULL;
X	if (!StackPushStringCopy(Qstr))
X		return NULL;
X	return p;
X}
X
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XStackToBool(n)	/* converts stack item n to a bool (int 0/1) */
Xint n;
X{
X	int f;
X
X	switch (stack[n].type) {
X	case MacStackInt:
X		stack[n].d.n = !!stack[n].d.n;
X		break;
X	case MacStackString:
X		if (stack[n].d.s && stack[n].d.s[0]) {
X			f = 1;
X		} else {
X			f = 0;
X		}
X		if (stack[n].d.s)
X			free(stack[n].d.s);
X		stack[n].type = MacStackInt;
X		stack[n].d.n = f;
X		break;
X	default:
X		return FALSE;
X	}
X	return TRUE;
X}
X
X/* Primitives */
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimToBool()	/* converts TOS to a bool (int 0/1) */
X{
X	if (stackCount<1)
X		return FALSE;
X	return (StackToBool(TOS));
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimNot()	/* converts TOS to Bool and then invert it */
X{
X	int f;
X
X	if (stackCount<1)
X		return FALSE;
X	switch (stack[TOS].type) {
X	case MacStackInt:
X		stack[TOS].d.n = !stack[TOS].d.n;
X		break;
X	case MacStackString:
X		if (stack[TOS].d.s && stack[TOS].d.s[0]) {
X			f = 0;
X		} else {
X			f = 1;
X		}
X		StackPop(1);
X		PUSHINT(f);
X		break;
X	default:
X		return FALSE;
X	}
X	return TRUE;
X}
X
X/* The IfTrue primitive requires a macro name at TOS and a value at TOS-1.
X * Both values are first removed from the stack.
X * If the value is TRUE, then the macro is executed, otherwise nothing
X * else happens.
X */
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimIfTrue()
X{
X	char *macroname;
X	int b,t;
X
X	if (stackCount<2)
X		return FALSE;
X	if (stack[TOS].type!=MacStackString)
X		return FALSE;
X	macroname = stack[TOS].d.s;
X	stack[TOS].d.s = 0;
X	StackPop(1);
X	if (!PrimToBool())
X		return FALSE;	/* error testing truth */
X	b = stack[TOS].d.n;
X	StackPop(1);
X	if (b)
X		t = StackDoNamedMacro(macroname);
X	else
X		t = TRUE;
X	free(macroname);
X	return t;
X}
X
X/* The IfElse primitive requires a macro name at TOS,
X * a macro name at TOS-1, and a condition value at TOS-2.
X * All three items are first removed from the stack.
X * If the condition is TRUE, then the macro is which was at TOS-1 is executed,
X * otherwise the macro which was at TOS is executed.
X * Thus, you first push the condition value, then the name of the TRUE macro,
X * then the name of the FALSE macro, then "ifElse", then M.
X */
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimIfElse()
X{
X	char *truemacro, *falsemacro;
X	int b,t;
X
X	if (stackCount<3)
X		return FALSE;
X	if (stack[TOS].type!=MacStackString ||
X	    stack[TOS-1].type!=MacStackString)
X		return FALSE;
X	falsemacro = stack[TOS].d.s;
X	stack[TOS].d.s = 0;
X	truemacro = stack[TOS-1].d.s;
X	stack[TOS-1].d.s = 0;
X	StackPop(2);
X	if (!PrimToBool())
X		return FALSE;	/* error testing truth */
X	b = stack[TOS].d.n;
X	StackPop(1);
X	if (b)
X		t = StackDoNamedMacro(truemacro);
X	else
X		t = StackDoNamedMacro(falsemacro);
X	free(truemacro);
X	free(falsemacro);
X	return t;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimPop()	/* throws away the top item on the stack */
X{
X	if (stackCount<1)
X		return FALSE;
X	StackPop(1);
X	return TRUE;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimPush()	/* duplicates the top item on the stack by pushing a copy */
X{
X	if (stackCount<1)
X		return FALSE;
X	switch (stack[TOS].type) {
X	case MacStackInt:
X		PUSHINT(stack[TOS].d.n);
X		break;
X	case MacStackString:
X		if (!StackPushStringCopy(stack[TOS].d.s))
X			return FALSE;
X		break;
X	default:
X		return FALSE;
X	}
X	return TRUE;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimExch()	/* exchanges the top two items on the stack */
X{
X	MacStackEntry e;
X
X	if (stackCount<2)
X		return FALSE;
X	e = stack[TOS];		/* structure copy */
X	stack[TOS] = stack[TOS-1];
X	stack[TOS-1] = e;
X	return TRUE;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimLimit()	/* limits TOS-2 to be between TOS-1 and TOS */
X{
X	int high,low;
X
X	if (stackCount<3)
X		return FALSE;
X	if (stack[TOS].type != MacStackInt ||
X	    stack[TOS-1].type != MacStackInt ||
X	    stack[TOS-2].type != MacStackInt)
X		return FALSE;
X	high = stack[TOS].d.n;
X	low = stack[TOS-1].d.n;
X	StackPop(2);
X	if (stack[TOS].d.n>high)
X		stack[TOS].d.n = high;
X	else if (stack[TOS].d.n<low)
X		stack[TOS].d.n = low;
X	return TRUE;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimOrd()	/* converts a char (string of len 1) to an int */
X{
X	int ord;
X
X	if (stackCount<1)
X		return FALSE;
X	if (stack[TOS].type != MacStackString ||
X	    strlen(stack[TOS].d.s)!=1)
X		return FALSE;
X	ord = stack[TOS].d.s[0];
X	StackPop(1);
X	PUSHINT(ord);
X	return TRUE;
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimError()	/* generates an error (aborts) */
X{
X	return FALSE;	/* simple enough */
X}
X
Xstatic Bool	/* returns TRUE if all OK, FALSE if any problems */
XPrimTekScale()	/* generates an error (aborts) */
X{
X	PUSHINT(TekScale(stackScreen));
X	return TRUE;
X}
X
X
X/* Macro processing functions */
X
Xtypedef struct {
X	char *value;
X} UmInfo, *UmInfoPtr;
Xstatic XtResource umresource[] = {
X	{ "", "", XtRString, sizeof(String),
X		XtOffset(UmInfoPtr,value),XtRString,NULL},
X};
X
Xstatic String		/* returns macro string or NULL if not found */
XStackFindUserMacro(name)
XString name;
X{
X	UserMacro *umlist;
X	UmInfo uminfo;
X
X	umlist = stackScreen->userMacros;
X	for (; umlist; umlist=umlist->next) {
X		if (strcmp(umlist->name,name)==0)
X			return(umlist->value);
X	}
X	/* not a macro that is already loaded, see if we can load it */
X	umresource[0].resource_name = name;
X	umresource[0].resource_class = name;
X	XtGetSubresources(stackWidget,(caddr_t)&uminfo,
X		"macroString","MacroString",
X		umresource,(Cardinal)1,(ArgList)NULL,(Cardinal)0);
X	if (!uminfo.value)
X		return NULL;	/* can't find the macro */
X	umlist = (UserMacro *)malloc(sizeof(UserMacro));
X	if (!umlist)
X		return NULL;	/* can't get memory */
X	umlist->name = malloc(strlen(name)+1);
X	if (!umlist->name) {
X		free((char *)umlist);
X		return NULL;
X	}
X	umlist->value = malloc(strlen(uminfo.value)+1);
X	if (!umlist->value) {
X		free(umlist->name);
X		free((char *)umlist);
X		return NULL;
X	}
X	strcpy(umlist->name,name);
X	strcpy(umlist->value,uminfo.value);
X	umlist->next = stackScreen->userMacros;
X	stackScreen->userMacros = umlist;
X	return(umlist->value);
X}
X
X/* handles the "%" formatting; parses format string and operates on stack */
Xstatic char *	/* returns pointer to the last char of the fmt string or NULL */
XStackFstr(p)
Xchar *p;	/* pointer to first char of formatting string */
X{
X	static char *fmtchars="-+#*.0123456789";
X	char *buf;
X
X	if (stackCount<1)
X		return NULL;
X	StackQclear();
X	if (!StackQchar('%'))
X		return NULL;
X	while (*p && (index(fmtchars,*p))) {
X		if (!StackQchar(*p))
X			return NULL;
X		p++;
X	}
X	if (!StackQchar(*p))	/* add the final formatting char */
X		return NULL;
X	if (!StackQchar(0))	/* null terminate the format string */
X		return NULL;
X	switch (*p) {
X	case 0:
X		return NULL;
X	case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'c':
X		if (stack[TOS].type!=MacStackInt)
X			return NULL;
X		buf = malloc(100);
X		if (!buf)
X			return NULL;
X		sprintf(buf,Qstr,stack[TOS].d.n);
X		break;
X	case 's':
X		if (stack[TOS].type!=MacStackString)
X			return NULL;
X		buf = malloc(strlen(stack[TOS].d.s)+100);
X		if (!buf)
X			return NULL;
X		sprintf(buf,Qstr,stack[TOS].d.s);
X		break;
X	default:
X		return NULL;
X	}
X	StackPop(1);	/* get rid of converted value */
X	if (!StackPushStringCopy(buf)) {
X		free(buf);
X		return NULL;
X	}
X	free(buf);
X	return p;
X}
X
X/* handles primitives */
XBool		/* returns TRUE if OK, FALSE is any errors */
XStackDoPrimitive(name)
Xchar *name;
X{
X	int i;
X
X	for (i=0; i<XtNumber(PrimTab); i++) {
X		if (strcmp(PrimTab[i].name,name)==0) {
X			return (*PrimTab[i].func)();
X		}
X	}
X	return FALSE;
X}
X
X/* handles built-in macro strings */
XBool		/* returns TRUE if OK, FALSE is any errors */
XStackDoBuiltin(name)
Xchar *name;
X{
X	int i;
X
X	for (i=0; i<XtNumber(BuiltinTab); i++) {
X		if (strcmp(BuiltinTab[i].name,name)==0) {
X			return ProcessMacroString(BuiltinTab[i].str);
X		}
X	}
X	return FALSE;
X}
X
X/* handles user defined macro strings */
XBool		/* returns TRUE if OK, FALSE is any errors */
XStackDoUserMacro(name)
Xchar *name;
X{
X	String macrostr;
X
X	macrostr = StackFindUserMacro(name);
X	if (!macrostr)
X		return FALSE;	/* no such macro */
X	return ProcessMacroString(macrostr);
X}
X
X/* handles macro as named at TOS */
XBool		/* returns TRUE if OK, FALSE if any errors */
XStackDoMacro()
X{
X	char *macroname;
X	int t;
X
X	if (stackCount<1 || stack[TOS].type!=MacStackString)
X		return FALSE;	/* no macro name */
X	macroname = stack[TOS].d.s;
X	stack[TOS].d.s = 0;
X	StackPop(1);	/* remove the macro name from the stack */
X	t = StackDoNamedMacro(macroname);
X	free(macroname);
X	return t;
X}
X
X/* handles macros (primitives, built-in macros, or user macros) */
XBool		/* returns TRUE if OK, FALSE if any errors */
XStackDoNamedMacro(macroname)
XString macroname;
X{
X	/* User macros can override builtin macro strings, but not primitives */
X	if (StackDoPrimitive(macroname) ||
X	    StackDoUserMacro(macroname) ||
X	    StackDoBuiltin(macroname)) {
X		return TRUE;
X	}
X	return FALSE;	/* no such macro */
X}
X
Xstatic int    /* returns TRUE if all OK, FALSE if problem (syntax, no memory) */
XProcessMacroString(macrostring)
Xchar *macrostring;
X{
X	char *p;
X	char *newstr;
X	int newnum;
X	int l;
X	int n;
X	Bool b;
X	int radix, hc;
X	KeySym ks;
X	char buf[100];
X
X	for (p=macrostring;*p;p++) {	/* process commands */
X		switch (*p) {
X		case ' ':	/* ignore spaces */
X			break;
X		case '"':	/* quoted string */
X		case '\'':
X			p = StackQstr(p+1,*p);
X			if (!p)
X				return FALSE;		/* error */
X			break;
X		case '%':	/* formatted print onto TOS */
X			p = StackFstr(p+1);
X			if (!p)
X				return FALSE;		/* error */
X			break;
X		case '+':	/* add two numbers or cat two strings */
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackString &&
X			    stack[TOS-1].type == MacStackString) {
X				l = strlen(stack[TOS].d.s) +
X				    strlen(stack[TOS-1].d.s) + 1;
X				newstr = malloc(l);
X				if (!newstr)
X					return FALSE;
X				strcpy(newstr,stack[TOS-1].d.s);
X				strcat(newstr,stack[TOS].d.s);
X				StackPop(1);
X				free(stack[TOS].d.s);
X				stack[TOS].d.s = newstr;
X			}
X			else if (stack[TOS].type == MacStackInt ||
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n + stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '-':	/* subtract two numbers */
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt ||
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n - stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '*':	/* multiply two numbers */
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt ||
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n * stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '/':	/* divide two numbers */
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt ||
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n / stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '<':	/* left shift (<<) */
X			if ((*(++p))!='<')
X				return FALSE;
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt &&
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n << stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '>':	/* right shift (>>) */
X			if ((*(++p))!='>')
X				return FALSE;
X			if (stackCount<2)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt &&
X				 stack[TOS-1].type == MacStackInt) {
X				newnum = stack[TOS-1].d.n >> stack[TOS].d.n;
X				StackPop(1);
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '|':	/* logical or bitwise OR */
X			if (stackCount<2)
X				return FALSE;
X			if (p[1]=='|') {	/* logical */
X				p++;
X				if (!(StackToBool(TOS) && StackToBool(TOS-1)))
X					return FALSE;
X				newnum = stack[TOS-1].d.n || stack[TOS].d.n;
X			} else {		/* bitwise */
X				if (stack[TOS].type != MacStackInt ||
X				    stack[TOS-1].type != MacStackInt)
X					return FALSE;
X				newnum = stack[TOS-1].d.n | stack[TOS].d.n;
X			}
X			StackPop(1);
X			stack[TOS].d.n = newnum;
X			break;
X		case '&':	/* logical or bitwise AND */
X			if (stackCount<2)
X				return FALSE;
X			if (p[1]=='&') {	/* logical */
X				p++;
X				if (!(StackToBool(TOS) && StackToBool(TOS-1)))
X					return FALSE;
X				newnum = stack[TOS-1].d.n && stack[TOS].d.n;
X			} else {		/* bitwise */
X				if (stack[TOS].type != MacStackInt ||
X				    stack[TOS-1].type != MacStackInt)
X					return FALSE;
X				newnum = stack[TOS-1].d.n & stack[TOS].d.n;
X			}
X			StackPop(1);
X			stack[TOS].d.n = newnum;
X			break;
X		case '^':	/* logical or bitwise XOR */
X			if (stackCount<2)
X				return FALSE;
X			if (p[1]=='^') {	/* logical */
X				p++;
X				if (!(StackToBool(TOS) && StackToBool(TOS-1)))
X					return FALSE;
X				newnum = stack[TOS-1].d.n ^ stack[TOS].d.n;
X			} else {		/* bitwise */
X				if (stack[TOS].type != MacStackInt ||
X				    stack[TOS-1].type != MacStackInt)
X					return FALSE;
X				newnum = stack[TOS-1].d.n ^ stack[TOS].d.n;
X			}
X			StackPop(1);
X			stack[TOS].d.n = newnum;
X			break;
X		case '!':	/* logical not */
X			if (!PrimNot())
X				return FALSE;
X			break;
X		case '~':	/* bitwise invert */
X			if (stackCount<1)
X				return FALSE;
X			if (stack[TOS].type == MacStackInt) {
X				newnum = ~stack[TOS-1].d.n;
X				stack[TOS].d.n = newnum;
X			}
X			else
X				return FALSE;
X			break;
X		case '0': case '1': case '2': case '3': case '4':
X		case '5': case '6': case '7': case '8': case '9':
X			newnum = 0;
X			if ((*p)=='0') {
X				if (p[1]=='x' || p[1]=='X') {
X					radix = 16;
X					p+=2;
X				}
X				else
X					radix = 8;
X			}
X			else
X				radix = 10;
X			while (isdigit(*p) || (radix==16&&ishexalpha(*p))) {
X				newnum *= radix;
X				if (radix==16&&ishexalpha(*p)) {
X					hc = *p;
X					if (islower(hc))
X						hc = toupper(hc);
X					newnum += hc - 'A' + 10;
X				}
X				else
X					newnum += *p - '0';
X				p++;
X			}
X			--p;	/* have to leave it pointing to last char */
X			PUSHINT(newnum);
X			break;
X		case 'b':	/* put button field from event onto stack */
X			PUSHINT(stackEvent->xbutton.button);
X			break;
X		case 'c':	/* put cursor col onto stack (0 is leftmost) */
X			PUSHINT(CursorCol(stackScreen,stackEvent->xbutton.x));
X			break;
X		case 'C':	/* put number of cols on screen onto stack */
X			PUSHINT(stackScreen->max_col+1);
X			break;
X		case 'h':	/* put pixel height of a char on stack */
X			PUSHINT(FontHeight(stackScreen));
X			break;
X		case 'H':	/* put pixel height of screen on stack */
X			PUSHINT(stackScreen->fullVwin.height);
X			break;
X		case 'i':	/* send TOS as input */
X			if (stackCount<1)
X				return FALSE;
X			if (stack[TOS].type == MacStackString)
X				StringInput(stackScreen,stack[TOS].d.s);
X			else
X				return FALSE;
X			StackPop(1);
X			break;
X		case 'k':	/* put keycode field from event onto stack */
X			PUSHINT(stackEvent->xkey.keycode);
X			break;
X		case 'l':	/* put results of XLookupString on stack */
X			n = XLookupString(stackEvent,buf,sizeof(buf)-1,&ks,0);
X			if (n>0) {
X				newstr = malloc(n+1);
X				if (!newstr)
X					return FALSE;
X				strcpy(newstr,buf);
X				if (!StackPushString(newstr))
X					return FALSE;
X			} else {	/* no translation, use null string */
X				if (!StackPushStringCopy(""))
X					return FALSE;
X			}
X			break;
X		case 'M':	/* execute macro */
X			if (!StackDoMacro())
X				return FALSE;
X			break;
X		case 'r':	/* put cursor row onto stack (0 is topmost) */
X			PUSHINT(CursorRow(stackScreen,stackEvent->xbutton.y));
X			break;
X		case 'R':	/* put number of rows on screen onto stack */
X			PUSHINT(stackScreen->max_row+1);
X			break;
X		case 's':	/* put state field from event onto stack */
X			PUSHINT(stackEvent->xbutton.state);
X			break;
X		case 'w':	/* put pixel width of a char on stack */
X			PUSHINT(FontWidth(stackScreen));
X			break;
X		case 'W':	/* put pixel width of screen on stack */
X			PUSHINT(stackScreen->fullVwin.width);
X			break;
X		case 'x':	/* put x pixel value of cursor on stack */
X			PUSHINT(stackEvent->xbutton.x - stackScreen->border - 
X						stackScreen->scrollbar);
X			break;
X		case 'y':	/* put y pixel value of cursor on stack */
X			PUSHINT(stackEvent->xbutton.y - stackScreen->border);
X			break;
X		case 'X':	/* put x_root pixel value of cursor on stack */
X			PUSHINT(stackEvent->xbutton.x_root);
X			break;
X		case 'Y':	/* put y_root pixel value of cursor on stack */
X			PUSHINT(stackEvent->xbutton.y_root);
X			break;
X		case 'Z':	/* conditional return/end of macro */
X			if (stackCount<1)
X				return FALSE;	/* error */
X			if (!PrimToBool())
X				return FALSE;	/* error testing truth */
X			b = stack[TOS].d.n;
X			StackPop(1);
X			if (b)
X				return TRUE;	/* if true, end of this macro */
X			/* else do nothing */
X			break;
X		default:
X			return FALSE;
X		}
X	}
X	return TRUE;	/* finished without errors */
X}
X
X/* This is the action function called from the translation table */
Xvoid
XHandleMacroString(w,event,params,param_count)
XWidget w;
XXEvent *event;
XString *params;
Xint *param_count;
X{
X
X	if (*param_count != 1)
X		return;
X	StackClear();		/* clear the stack machine */
X	stackScreen = &((XtermWidget)w)->screen;
X	stackWidget = w;
X	stackEvent = event;
X	if (!ProcessMacroString(params[0])) {
X		Bell();		/* some sort of error */
X	}
X}
X
X/* end */
END_OF_macrostr.c
if test 24964 -ne `wc -c <macrostr.c`; then
    echo shar: \"macrostr.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0