v05i037: macro-string enhancement for Xterm, Part01/01
Dan Heller
argv at island.uu.net
Wed Dec 6 06:06:04 AEST 1989
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 at 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 at 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 at 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
More information about the Comp.sources.x
mailing list