home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / packages / teco.el < prev    next >
Encoding:
Text File  |  1991-06-19  |  53.0 KB  |  1,903 lines

  1. ; Path: dg-rtp!rock.concert.net!mcnc!stanford.edu!agate!usenet.ins.cwru.edu!magnus.acs.ohio-state.edu!zaphod.mps.ohio-state.edu!think.com!snorkelwacker.mit.edu!bloom-picayune.mit.edu!math.mit.edu!drw
  2. ; From: drw@nevanlinna.mit.edu (Dale R. Worley)
  3. ; Newsgroups: alt.lang.teco,gnu.emacs.sources,comp.editors
  4. ; Subject: Teco for Gnu Emacs!
  5. ; Date: 19 Jun 91 22:51:03 GMT
  6. ; Organization: MIT Dept. of Tetrapilotomy, Cambridge, MA, USA
  7. ; Having gotten tired of not having Teco, I coded up this version for
  8. ; Gnu Emacs.  There are probably a zillion bugs.  Happy hacking!
  9. ; Dale
  10. ;;; Teco interpreter for Gnu Emacs, version 1.
  11.  
  12. (require 'backquote)
  13. (provide 'teco)
  14.  
  15. ;; This code has been tested some, but no doubt contains a zillion bugs.
  16. ;; You have been warned.
  17.  
  18. ;; Written by Dale R. Worley based on a C implementation by Matt Fichtenbaum.
  19. ;; Please send comments, bug fixes, enhancements, etc. to drw@math.mit.edu.
  20.  
  21. ;; Emacs Lisp version copyright (C) 1991 by Dale R. Worley.
  22. ;; Do what you will with it.
  23.  
  24. ;; Since much of this code is translated from the C version by 
  25. ;; Matt Fichtenbaum, I include his copyright notice:
  26. ;; TECO for Ultrix.   Copyright 1986 Matt Fichtenbaum.
  27. ;; This program and its components belong to GenRad Inc, Concord MA 01742.
  28. ;; They may be copied if this copyright notice is included.
  29.  
  30. ;; To invoke directly, do:
  31. ;; (global-set-key ?\C-z 'teco:command)
  32. ;; (autoload teco:command "teco"
  33. ;;   "Read and execute a Teco command string."
  34. ;;   t nil)
  35.  
  36. ;; Differences from other Tecos:
  37. ;; Character positions in the buffer are numbered in the Emacs way:  The first
  38. ;; character is numbered 1 (or (point-min) if narrowing is in effect).  The
  39. ;; B command returns that number.
  40. ;; Ends of lines are represented by a single character (newline), so C and R
  41. ;; skip over them, rather than 2C and 2R.
  42. ;; All file I/O is left to the underlying Emacs.  Thus, almost all Ex commands
  43. ;; are omitted.
  44.  
  45. ;; Command set:
  46. ;;    NUL    Not a command.
  47. ;;    ^A    Output message to terminal (argument ends with ^A)
  48. ;;    ^C    Exit macro
  49. ;;    ^C^C    Stop execution
  50. ;;    ^D    Set radix to decimal
  51. ;;    ^EA    (match char) Match alphabetics
  52. ;;    ^EC    (match char) Match symbol constituents
  53. ;;    ^ED    (match char) Match numerics
  54. ;;    ^EGq    (match char) Match any char in q-reg
  55. ;;    ^EL    (match char) Match line terminators
  56. ;;    ^EQq    (string char) Use contents of q-reg
  57. ;;    ^ER    (match char) Match alphanumerics
  58. ;;    ^ES    (match char) Match non-null space/tab
  59. ;;    ^EV    (match char) Match lower case alphabetic
  60. ;;    ^EW    (match char) Match upper case alphabetic
  61. ;;    ^EX    (match char) Match any char
  62. ;;    ^G^G    (type-in) Kill command string
  63. ;;    ^G<sp>    (type-in) Retype current command line
  64. ;;    ^G*    (type-in) Retype current command input
  65. ;;    TAB    Insert tab and text
  66. ;;    LF    Line terminator; Ignored in commands
  67. ;;    VT    Ignored in commands
  68. ;;    FF    Ignored in commands
  69. ;;    CR    Ignored in commands
  70. ;;    ^Nx    (match char) Match all but x
  71. ;;    ^O    Set radix to octal
  72. ;;    ^P    Find matching parenthesis
  73. ;;    ^Q    Convert line argument into character argument
  74. ;;    ^Qx    (string char) Use x literally
  75. ;;    n^R    Set radix to n
  76. ;;    :^R    Enter recursive edit
  77. ;;    ^S    -(length of last referenced string)
  78. ;;    ^S    (match char) match separator char
  79. ;;    ^T    Ascii value of next character typed
  80. ;;    n^T    Output Ascii character with value n
  81. ;;    ^U    (type-in) Kill command line
  82. ;;    ^Uq    Put text argument into q-reg
  83. ;;    n^Uq    Put Ascii character 'n' into q-reg
  84. ;;    :^Uq    Append text argument to q-reg
  85. ;;    n:^Uq    Append character 'n' to q-reg
  86. ;;    ^X    Set/get search mode flag
  87. ;;    ^X    (match char) Match any character
  88. ;;    ^Y    Equivalent to '.+^S,.'
  89. ;;    ^Z    Not a Teco command
  90. ;;    ESC    String terminator; absorbs arguments
  91. ;;    ESC ESC    (type-in) End command
  92. ;;    ^\    Not a Teco command
  93. ;;    ^]    Not a Teco command
  94. ;;    ^^x    Ascii value of the character x
  95. ;;    ^_    One's complement (logical NOT)
  96. ;;    !    Define label (argument ends with !)
  97. ;;    "    Start conditional
  98. ;;    n"<    Test for less than zero
  99. ;;    n">    Test for greater than zero
  100. ;;    n"=    Test for equal to zero
  101. ;;    n"A    Test for alphabetic
  102. ;;    n"C    Test for symbol constituent
  103. ;;    n"D    Test for numeric
  104. ;;    n"E    Test for equal to zero
  105. ;;    n"F    Test for false
  106. ;;    n"G    Test for greater than zero
  107. ;;    n"L    Test for less than zero
  108. ;;    n"N    Test for not equal to zero
  109. ;;    n"R    Test for alphanumeric
  110. ;;    n"S    Test for successful
  111. ;;    n"T    Test for true
  112. ;;    n"U    Test for unsuccessful
  113. ;;    n"V    Test for lower case
  114. ;;    n"W    Test for upper case
  115. ;;    #    Logical OR
  116. ;;    $    Not a Teco command
  117. ;;    n%q    Add n to q-reg and return result
  118. ;;    &    Logical AND
  119. ;;    '    End conditional
  120. ;;    (    Expression grouping
  121. ;;    )    Expression grouping
  122. ;;    *    Multiplication
  123. ;;    +    Addition
  124. ;;    ,    Argument separator
  125. ;;    -    Subtraction or negation
  126. ;;    .    Current pointer position
  127. ;;    /    Division
  128. ;;    0-9    Digit
  129. ;;    n<    Iterate n times
  130. ;;    =    Type in decimal
  131. ;;    :=    Type in decimal, no newline
  132. ;;    =    Type in octal
  133. ;;    :=    Type in octal, no newline
  134. ;;    =    Type in hexadecimal
  135. ;;    :=    Type in hexadecimal, no newline
  136. ;;    ::    Make next search a compare
  137. ;;    >    End iteration
  138. ;;    n:A    Get Ascii code of character at relative position n
  139. ;;    B    Character position of beginning of buffer
  140. ;;    nC    Advance n characters
  141. ;;    nD    Delete n characters
  142. ;;    n,mD    Delete characters between n and m
  143. ;;    Gq    Get string from q-reg into buffer
  144. ;;    :Gq    Type out q-reg
  145. ;;    H    Equivalent to 'B,Z'
  146. ;;    I    Insert text argument
  147. ;;    nJ    Move pointer to character n
  148. ;;    nK    Kill n lines
  149. ;;    n,mK    Kill characters between n and m
  150. ;;    nL    Advance n lines
  151. ;;    Mq    Execute string in q-reg
  152. ;;    O    Goto label
  153. ;;    nO    Go to n-th label in list (0-origin)
  154. ;;    Qq    Number in q-reg
  155. ;;    nQq    Ascii value of n-th character in q-reg
  156. ;;    :Qq    Size of text in q-reg
  157. ;;    nR    Back up n characters
  158. ;;    nS    Search
  159. ;;    nT    Type n lines
  160. ;;    n,mT    Type chars from n to m
  161. ;;    nUq    Put number n into q-reg
  162. ;;    nV    Type n lines around pointer
  163. ;;    nXq    Put n lines into q-reg
  164. ;;    n,mXq    Put characters from n to m into q-reg
  165. ;;    n:Xq    Append n lines to q-reg q
  166. ;;    n,m:Xq    Append characters from n to m into q-reg
  167. ;;    Z     Pointer position at end of buffer
  168. ;;    [q    Put q-reg on stack
  169. ;;    \    Value of digit string in buffer
  170. ;;    n\    Convert n to digits and insert in buffer
  171. ;;    ]q    Pop q-reg from stack
  172. ;;    :]q    Test whether stack is empty and return value
  173. ;;    `    Not a Teco command
  174. ;;    a-z    Treated the same as A-Z
  175. ;;    {    Not a Teco command
  176. ;;    |    Conditional 'else'
  177. ;;    }    Not a Teco comand
  178. ;;    ~    Not a Teco command
  179. ;;    DEL    Delete last character typed in
  180.  
  181.  
  182. ;; set a range of elements of an array to a value
  183. (defun teco:set-elements (array start end value)
  184.   (let ((i start))
  185.     (while (<= i end)
  186.       (aset array i value)
  187.       (setq i (1+ i)))))
  188.  
  189. ;; set a range of elements of an array to their indexes plus an offset
  190. (defun teco:set-elements-index (array start end offset)
  191.   (let ((i start))
  192.     (while (<= i end)
  193.       (aset array i (+ i offset))
  194.       (setq i (1+ i)))))
  195.  
  196. (defvar teco:command-string ""
  197.   "The current command string being executed.")
  198.  
  199. (defvar teco:command-pointer nil
  200.   "Pointer into teco:command-string showing next character to be executed.")
  201.  
  202. (defvar teco:ctrl-r 10
  203.   "Current number radix.")
  204.  
  205. (defvar teco:digit-switch nil
  206.   "Set if we have just executed a digit.")
  207.  
  208. (defvar teco:exp-exp nil
  209.   "Expression value preceeding operator.")
  210.  
  211. (defvar teco:exp-val1 nil
  212.   "Current argument value.")
  213.  
  214. (defvar teco:exp-val2 nil
  215.   "Argument before comma.")
  216.  
  217. (defvar teco:exp-flag1 nil
  218.   "t if argument is present.")
  219.  
  220. (defvar teco:exp-flag2 nil
  221.   "t if argument before comma is present.")
  222.  
  223. (defvar teco:exp-op nil
  224.   "Pending arithmetic operation on argument.")
  225.  
  226. (defvar teco:exp-stack nil
  227.   "Stack for parenthesized expressions.")
  228.  
  229. (defvar teco:macro-stack nil
  230.   "Stack for macro invocations.")
  231.  
  232. (defvar teco:mapch-l nil
  233.   "Translation table to lower-case letters.")
  234.  
  235.     (setq teco:mapch-l (make-vector 256 0))
  236.     (teco:set-elements-index teco:mapch-l 0 255 0)
  237.     (teco:set-elements-index teco:mapch-l ?A ?Z (- ?a ?A))
  238.  
  239. (defvar teco:trace nil
  240.   "t if tracing is on.")
  241.  
  242. (defvar teco:at-flag nil
  243.   "t if an @ flag is pending.")
  244.  
  245. (defvar teco:colon-flag nil
  246.   "1 if a : flag is pending, 2 if a :: flag is pending.")
  247.  
  248. (defvar teco:qspec-valid nil
  249.   "Flags describing whether a character is a vaid q-register name.
  250. 3 means yes, 2 means yes but only for file and search operations.")
  251.  
  252.     (setq teco:qspec-valid (make-vector 256 0))
  253.     (teco:set-elements teco:qspec-valid ?a ?z 3)
  254.     (teco:set-elements teco:qspec-valid ?0 ?9 3)
  255.     (aset teco:qspec-valid ?_ 2)
  256.     (aset teco:qspec-valid ?* 2)
  257.     (aset teco:qspec-valid ?% 2)
  258.     (aset teco:qspec-valid ?# 2)
  259.  
  260. (defvar teco:exec-flags 0
  261.   "Flags for iteration in process, ei macro, etc.")
  262.  
  263. (defvar teco:iteration-stack nil
  264.   "Iteration list.")
  265.  
  266. (defvar teco:cond-stack nil
  267.   "Conditional stack.")
  268.  
  269. (defvar teco:qreg-text (make-vector 256 "")
  270.   "The text contents of the q-registers.")
  271.  
  272. (defvar teco:qreg-number (make-vector 256 0)
  273.   "The number contents of the q-registers.")
  274.  
  275. (defvar teco:qreg-stack nil
  276.   "The stack of saved q-registers.")
  277.  
  278. (defconst teco:prompt "*"
  279.   "*Prompt to be used when inputting Teco command.")
  280.  
  281. (defconst teco:exec-1 (make-vector 256 nil)
  282.   "Names of routines handling type 1 characters (characters that are
  283. part of expression processing).")
  284.  
  285. (defconst teco:exec-2 (make-vector 256 nil)
  286.   "Names of routines handling type 2 characters (characters that are
  287. not part of expression processing).")
  288.  
  289. (defvar teco:last-search-string ""
  290.   "Last string searched for.")
  291.  
  292. (defvar teco:last-search-regexp ""
  293.   "Regexp version of teco:last-search-string.")
  294.  
  295. (defmacro teco:define-type-1 (char &rest body)
  296.   "Define the code to process a type 1 character.
  297. Transforms
  298.     (teco:define-type-1 ?x
  299.       code ...)
  300. into
  301.         (defun teco:type-1-x ()
  302.       code ...)
  303. and does
  304.     (aset teco:exec-1 ?x 'teco:type-1-x)"
  305.   (let ((s (intern (concat "teco:type-1-" (char-to-string char)))))
  306.     (` (progn
  307.      (defun (, s) ()
  308.        (,@ body))
  309.      (aset teco:exec-1 (, char) '(, s))))))
  310.  
  311. (defmacro teco:define-type-2 (char &rest body)
  312.   "Define the code to process a type 2 character.
  313. Transforms
  314.     (teco:define-type-2 ?x
  315.       code ...)
  316. into
  317.         (defun teco:type-2-x ()
  318.       code ...)
  319. and does
  320.     (aset teco:exec-2 ?x 'teco:type-2-x)"
  321.   (let ((s (intern (concat "teco:type-2-" (char-to-string char)))))
  322.     (` (progn
  323.      (defun (, s) ()
  324.        (,@ body))
  325.      (aset teco:exec-2 (, char) '(, s))))))
  326.  
  327. (defconst teco:char-types (make-vector 256 0)
  328.   "Define the characteristics of characters, as tested by \":
  329.     1    alphabetic
  330.     2    alphabetic, $, or .
  331.     4    digit
  332.     8    alphabetic or digit
  333.     16    lower-case alphabetic
  334.     32    upper-case alphabetic")
  335.  
  336.     (teco:set-elements teco:char-types ?0 ?9 (+ 4 8))
  337.     (teco:set-elements teco:char-types ?A ?Z (+ 1 2 8 32))
  338.     (teco:set-elements teco:char-types ?a ?z (+ 1 2 8 16))
  339.     (aset teco:char-types ?$ 2)
  340.     (aset teco:char-types ?. 2)
  341.  
  342. (defconst teco:error-texts '(("BNI" . "> not in iteration")
  343.                  ("CPQ" . "Can't pop Q register")
  344.                  ("COF" . "Can't open output file ")
  345.                  ("FNF" . "File not found ")
  346.                  ("IEC" . "Invalid E character")
  347.                  ("IFC" . "Invalid F character")
  348.                  ("IIA" . "Invalid insert arg")
  349.                  ("ILL" . "Invalid command")
  350.                  ("ILN" . "Invalid number")
  351.                  ("IPA" . "Invalid P arg")
  352.                  ("IQC" . "Invalid \" character")
  353.                  ("IQN" . "Invalid Q-reg name")
  354.                  ("IRA" . "Invalid radix arg")
  355.                  ("ISA" . "Invalid search arg")
  356.                  ("ISS" . "Invalid search string")
  357.                  ("IUC" . "Invalid ^ character")
  358.                  ("LNF" . "Label not found")
  359.                  ("MEM" . "Insufficient memory available")
  360.                  ("MRP" . "Missing )")
  361.                  ("NAB" . "No arg before ^_")
  362.                  ("NAC" . "No arg before ,")
  363.                  ("NAE" . "No arg before =")
  364.                  ("NAP" . "No arg before )")
  365.                  ("NAQ" . "No arg before \"")
  366.                  ("NAS" . "No arg before ;")
  367.                  ("NAU" . "No arg before U")
  368.                  ("NFI" . "No file for input")
  369.                  ("NFO" . "No file for output")
  370.                  ("NYA" . "Numeric arg with Y")
  371.                  ("OFO" . "Output file already open")
  372.                  ("PDO" . "Pushdown list overflow")
  373.                  ("POP" . "Pointer off page")
  374.                  ("SNI" . "; not in iteration")
  375.                  ("SRH" . "Search failure ")
  376.                  ("STL" . "String too long")
  377.                  ("UTC" . "Unterminated command")
  378.                  ("UTM" . "Unterminated macro")
  379.                  ("XAB" . "Execution interrupted")
  380.                  ("YCA" . "Y command suppressed")
  381.                  ("IWA" . "Invalid W arg")
  382.                  ("NFR" . "Numeric arg with FR")
  383.                  ("INT" . "Internal error")
  384.                  ("EFI" . "EOF read from std input")
  385.                  ("IAA" . "Invalid A arg")
  386.                  ))
  387.  
  388. (defconst teco:spec-chars 
  389.   [
  390.    0          1          0          0    ; ^@ ^A ^B ^C
  391.    0          64         0          0    ; ^D ^E ^F ^G
  392.    0          2          128        128    ; ^H ^I ^J ^K
  393.    128        0          64         0    ; ^L ^M ^N ^O
  394.    0          64         64         64    ; ^P ^Q ^R ^S
  395.    0          34         0          0    ; ^T ^U ^V ^W
  396.    64         0          0          0    ; ^X ^Y ^Z ^\[
  397.    0          0          1          0    ; ^\ ^\] ^^ ^_
  398.    0          1          16         0    ;    !  \"  # 
  399.    0          0          0          16    ; $  %  &  ' 
  400.    0          0          0          0    ; \(  \)  *  + 
  401.    0          0          0          0    ; ,  -  .  / 
  402.    0          0          0          0    ; 0  1  2  3 
  403.    0          0          0          0    ; 4  5  6  7 
  404.    0          0          0          0    ; 8  9  :  ; 
  405.    16         0          16         0    ; <  =  >  ? 
  406.    1          0          12         0    ; @  A  B  C 
  407.    0          1          1          32    ; D  E  F  G 
  408.    0          6          0          0    ; H  I  J  K 
  409.    0          32         10         2    ; L  M  N  O 
  410.    0          32         4          10    ; P  Q  R  S 
  411.    0          32         0          4    ; T  U  V  W 
  412.    32         0          0          32    ; X  Y  Z  \[ 
  413.    0          32         1          6    ; \  \]  ^  _ 
  414.    0          0          12         0    ; `  a  b  c 
  415.    0          1          1          32    ; d  e  f  g 
  416.    0          6          0          0    ; h  i  j  k 
  417.    0          32         10         2    ; l  m  n  o 
  418.    0          32         4          10    ; p  q  r  s 
  419.    0          32         0          4    ; t  u  v  w 
  420.    32         0          0          0    ; x  y  z  { 
  421.    16         0          0          0    ; |  }  ~  DEL
  422.    ]
  423.   "The special properties of characters:
  424.     1    skipto() special character
  425.     2    command with std text argument
  426.     4    E<char> takes a text argument
  427.     8    F<char> takes a text argument
  428.     16    char causes skipto() to exit
  429.     32    command with q-register argument
  430.     64    special char in search string
  431.     128    character is a line separator")
  432.  
  433.  
  434. (defun teco:execute-command (string)
  435.   "Execute teco command string."
  436.   ;; Initialize everything
  437.   (let ((teco:command-string string)
  438.     (teco:command-pointer 0)
  439.     (teco:digit-switch nil)
  440.     (teco:exp-exp nil)
  441.     (teco:exp-val1 nil)
  442.     (teco:exp-val2 nil)
  443.     (teco:exp-flag1 nil)
  444.     (teco:exp-flag2 nil)
  445.     (teco:exp-op 'start)
  446.     (teco:trace nil)
  447.     (teco:at-flag nil)
  448.     (teco:colon-flag nil)
  449.     (teco:exec-flags 0)
  450.     (teco:iteration-stack nil)
  451.     (teco:cond-stack nil)
  452.     (teco:exp-stack nil)
  453.     (teco:macro-stack nil)
  454.     (teco:qreg-stack nil))
  455.     ;; initialize output
  456.     (teco:out-init)
  457.     ;; execute commands
  458.     (catch 'teco:exit
  459.       (while t
  460.     ;; get next command character
  461.     (let ((cmdc (teco:get-command0 teco:trace)))
  462.       ;; if it's ^, interpret the next character as a control character
  463.       (if (eq cmdc ?^)
  464.           (setq cmdc (logand (teco:get-command teco:trace) 31)))
  465.       (if (and (<= ?0 cmdc) (<= cmdc ?9))
  466.           ;; process a number
  467.           (progn
  468.         (setq cmdc (- cmdc ?0))
  469.         ;; check for invalid digit
  470.         (if (>= cmdc teco:ctrl-r)
  471.             (teco:error "ILN"))
  472.         (if teco:digit-switch
  473.             ;; later digits
  474.             (setq teco:exp-val1 (+ (* teco:exp-val1 teco:ctrl-r) cmdc))
  475.           ;; first digit
  476.           (setq teco:exp-val1 cmdc)
  477.           (setq teco:digit-switch t))
  478.         ;; indicate a value was read in
  479.         (setq teco:exp-flag1 t))
  480.         ;; not a digit
  481.         (setq teco:digit-switch nil)
  482.         ;; cannonicalize the case
  483.         (setq cmdc (aref teco:mapch-l cmdc))
  484.         ;; dispatch on the character, if it is a type 1 character
  485.         (let ((r (aref teco:exec-1 cmdc)))
  486.           (if r
  487.           (funcall r)
  488.         ;; if a value has been entered, process any pending operation
  489.         (if teco:exp-flag1
  490.             (cond ((eq teco:exp-op 'start)
  491.                nil)
  492.               ((eq teco:exp-op 'add)
  493.                (setq teco:exp-val1 (+ teco:exp-exp teco:exp-val1))
  494.                (setq teco:exp-op 'start))
  495.               ((eq teco:exp-op 'sub)
  496.                (setq teco:exp-val1 (- teco:exp-exp teco:exp-val1))
  497.                (setq teco:exp-op 'start))
  498.               ((eq teco:exp-op 'mult)
  499.                (setq teco:exp-val1 (* teco:exp-exp teco:exp-val1))
  500.                (setq teco:exp-op 'start))
  501.               ((eq teco:exp-op 'div)
  502.                (setq teco:exp-val1
  503.                  (if (/= teco:exp-val1 0)
  504.                      (/ teco:exp-exp teco:exp-val1)
  505.                    0))
  506.                (setq teco:exp-op 'start))
  507.               ((eq teco:exp-op 'and)
  508.                (setq teco:exp-val1
  509.                  (logand teco:exp-exp teco:exp-val1))
  510.                (setq teco:exp-op 'start))
  511.               ((eq teco:exp-op 'or)
  512.                (setq teco:exp-val1
  513.                  (logior teco:exp-exp teco:exp-val1))
  514.                (setq teco:exp-op 'start))))
  515.         ;; dispatch on a type 2 character
  516.         (let ((r (aref teco:exec-2 cmdc)))
  517.           (if r
  518.               (funcall r)
  519.             (teco:error "ILL")))))))))))
  520.  
  521. ;; Type 1 commands
  522.  
  523. (teco:define-type-1
  524.  ?\m                    ; CR
  525.  nil)
  526.  
  527. (teco:define-type-1
  528.  ?\n                    ; LF
  529.  nil)
  530.  
  531. (teco:define-type-1
  532.  ?\^k                    ; VT
  533.  nil)
  534.  
  535. (teco:define-type-1
  536.  ?\^l                    ; FF
  537.  nil)
  538.  
  539. (teco:define-type-1
  540.  32                    ; SPC
  541.  nil)
  542.  
  543. (teco:define-type-1
  544.  ?\e                    ; ESC
  545.  (if (teco:peek-command ?\e)
  546.      ;; ESC ESC terminates macro or command
  547.      (teco:pop-macro-stack)
  548.    ;; otherwise, consume argument
  549.    (setq teco:exp-flag1 nil)
  550.    (setq teco:exp-op 'start)))
  551.  
  552. (teco:define-type-1
  553.  ?!                    ; !
  554.  (while (/= (teco:get-command teco:trace) ?!)
  555.    nil))
  556.  
  557. (teco:define-type-1
  558.  ?@                    ; @
  559.  ;; set at-flag
  560.  (setq teco:at-flag t))
  561.  
  562. (teco:define-type-1
  563.  ?:                    ; :
  564.  ;; is it '::'?
  565.  (if (teco:peek-command ?:)
  566.      (progn
  567.        ;; skip second colon
  568.        (teco:get-command teco:trace)
  569.        ;; set flag to show two colons
  570.        (setq teco:colon-flag 2))
  571.    ;; set flag to show one colon
  572.    (setq teco:colon-flag 1)))
  573.  
  574. (teco:define-type-1
  575.  ??                    ; ?
  576.  ;; toggle trace
  577.  (setq teco:trace (not teco:trace)))
  578.  
  579. (teco:define-type-1
  580.  ?.                    ; .
  581.  ;; value is point
  582.  (setq teco:exp-val1 (point)
  583.        teco:exp-flag1 t))
  584.  
  585. (teco:define-type-1
  586.  ?z                    ; z
  587.  ;; value is point-max
  588.  (setq teco:exp-val1 (point-max)
  589.        teco:exp-flag1 t))
  590.  
  591. (teco:define-type-1
  592.  ?b                    ; b
  593.  ;; value is point-min
  594.  (setq teco:exp-val1 (point-min)
  595.        teco:exp-flag1 t))
  596.  
  597. (teco:define-type-1
  598.  ?h                    ; h
  599.  ;; value is b,z
  600.  (setq teco:exp-val1 (point-max)
  601.        teco:exp-val2 (point-min)
  602.        teco:exp-flag1 t
  603.        teco:exp-flag2 t
  604.        teco:exp-op 'start))
  605.  
  606. (teco:define-type-1
  607.  ?\^s                    ; ^s
  608.  ;; value is - length of last insert, etc.
  609.  (setq teco:exp-val1 teco:ctrl-s
  610.        teco:exp-flag1 t))
  611.  
  612. (teco:define-type-1
  613.  ?\^y                    ; ^y
  614.  ;; value is .+^S,.
  615.  (setq teco:exp-val1 (+ (point) teco:ctrl-s)
  616.        teco:exp-val2 (point)
  617.        teco:exp-flag1 t
  618.        teco:exp-flag2 t
  619.        teco:exp-op 'start))
  620.  
  621. (teco:define-type-1
  622.  ?\(                    ; \(
  623.  ;; push expression stack
  624.  (teco:push-exp-stack)
  625.  (setq teco:exp-flag1 nil
  626.        teco:exp-flag2 nil
  627.        teco:exp-op 'start))
  628.  
  629. (teco:define-type-1
  630.  ?\^p                    ; ^p
  631.  (teco:do-ctrl-p))
  632.  
  633. (teco:define-type-1
  634.  ?\C-^                    ; ^^
  635.  ;; get next command character
  636.  (setq teco:exp-val1 (teco:get-command teco:trace)
  637.        teco:exp-flag1 t))
  638.  
  639.  
  640. ;; Type 2 commands
  641. (teco:define-type-2
  642.  ?+                    ; +
  643.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  644.        teco:exp-flag1 nil
  645.        teco:exp-op 'add))
  646.  
  647. (teco:define-type-2
  648.  ?-                    ; -
  649.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  650.        teco:exp-flag1 nil
  651.        teco:exp-op 'sub))
  652.  
  653. (teco:define-type-2
  654.  ?*                    ; *
  655.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  656.        teco:exp-flag1 nil
  657.        teco:exp-op 'mult))
  658.  
  659. (teco:define-type-2
  660.  ?/                    ; /
  661.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  662.        teco:exp-flag1 nil
  663.        teco:exp-op 'div))
  664.  
  665. (teco:define-type-2
  666.  ?&                    ; &
  667.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  668.        teco:exp-flag1 nil
  669.        teco:exp-op 'and))
  670.  
  671. (teco:define-type-2
  672.  ?#                    ; #
  673.  (setq teco:exp-exp (if teco:exp-flag1 teco:exp-val1 0)
  674.        teco:exp-flag1 nil
  675.        teco:exp-op 'or))
  676.  
  677. (teco:define-type-2
  678.  ?\)                    ; \)
  679.  (if (or (not teco:exp-flag1) (not teco:exp-stack))
  680.      (teco:error "NAP"))
  681.  (let ((v teco:exp-val1))
  682.    (teco:pop-exp-stack)
  683.    (setq teco:exp-val1 v
  684.      teco:exp-flag1 t)))
  685.  
  686. (teco:define-type-2
  687.  ?,                    ; ,
  688.  (if (not teco:exp-flag1)
  689.      (teco:error "NAC"))
  690.  (setq teco:exp-val2 teco:exp-val1
  691.        teco:exp-flag2 t
  692.        teco:exp-flag1 nil))
  693.  
  694. (teco:define-type-2
  695.  ?\^_                    ; ^_
  696.  (if (not teco:exp-flag1)
  697.      (teco:error "NAB")
  698.    (setq teco:exp-val1 (lognot teco:exp-val1))))
  699.  
  700. (teco:define-type-2
  701.  ?\^d                    ; ^d
  702.  (setq teco:ctrl-r 10
  703.        teco:exp-flag1 nil
  704.        teco:exp-op 'start))
  705.  
  706. (teco:define-type-2
  707.  ?\^o                    ; ^o
  708.  (setq teco:ctrl-r 8
  709.        teco:exp-flag1 nil
  710.        teco:exp-op 'start))
  711.  
  712. (teco:define-type-2
  713.  ?\^r                    ; ^r
  714.  (if teco:colon-flag
  715.      (progn
  716.        (recursive-edit)
  717.        (setq teco:colon-flag nil))
  718.    (if teco:exp-flag1
  719.        ;; set radix
  720.        (progn
  721.      (if (and (/= teco:exp-val1 8)
  722.           (/= teco:exp-val1 10)
  723.           (/= teco:exp-val1 16))
  724.          (teco:error "IRA"))
  725.      (setq teco:ctrl-r teco:exp-val1
  726.            teco:exp-flag1 nil
  727.            teco:exp-op 'start))
  728.      ;; get radix
  729.      (setq teco:exp-val1 teco:ctrl-r
  730.        teco:exp-flag1 t))))
  731.  
  732. (teco:define-type-2
  733.  ?\^c                    ; ^c
  734.  (if (teco:peek-command ?\^c)
  735.      ;; ^C^C stops execution
  736.      (throw 'teco:exit nil)
  737.    (if teco:macro-stack
  738.        ;; ^C inside macro exits macro
  739.        (teco:pop-macro-stack)
  740.      ;; ^C in command stops execution
  741.      (throw 'teco:exit nil))))
  742.  
  743. (teco:define-type-2
  744.  ?\^x                    ; ^x
  745.  ;; set/get search mode flag
  746.  (teco:set-var 'teco:ctrl-x))
  747.  
  748. (teco:define-type-2
  749.  ?m                    ; m
  750.  (let ((macro-name (teco:get-qspec nil
  751.                    (teco:get-command teco:trace))))
  752.    (teco:push-macro-stack)
  753.    (setq teco:command-string (aref teco:qreg-text macro-name)
  754.      teco:command-pointer 0)))
  755.  
  756. (teco:define-type-2
  757.  ?<                    ; <
  758.  ;; begin iteration
  759.  (if (and teco:exp-flag1 (<= teco:exp-val1 0))
  760.      ;; if this is not to be executed, just skip the
  761.      ;; intervening stuff
  762.      (teco:find-enditer)
  763.    ;; push iteration stack
  764.    (teco:push-iter-stack teco:command-pointer
  765.              teco:exp-flag1 teco:exp-val1)
  766.    ;; consume the argument
  767.    (setq teco:exp-flag1 nil)))
  768.  
  769. (teco:define-type-2
  770.  ?>                    ; >
  771.  ;; end iteration
  772.  (if (not teco:iteration-stack)
  773.      (teco:error "BNI"))
  774.  ;; decrement count and pop conditionally
  775.  (teco:pop-iter-stack nil)
  776.  ;; consume arguments
  777.  (setq teco:exp-flag1 nil
  778.        teco:exp-flag2 nil
  779.        teco:exp-op 'start))
  780.  
  781. (teco:define-type-2
  782.  59                    ; ;
  783.  ;; semicolon iteration exit
  784.  (if (not teco:iteration-stack)
  785.      (teco:error "SNI"))
  786.  ;; if exit
  787.  (if (if (>= (if teco:exp-flag1
  788.          teco:exp-val1
  789.            teco:search-result) 0)
  790.      (not teco:colon-flag)
  791.        teco:colon-flag)
  792.      (progn
  793.        (teco:find-enditer)
  794.        (teco:pop-iter-stack t)))
  795.  ;; consume argument and colon
  796.  (setq teco:exp-flag1 nil
  797.        teco:colon-flag nil
  798.        teco:exp-op 'start))
  799.  
  800. (teco:define-type-2
  801.  ?\"                    ; \"
  802.  ;; must be an argument
  803.  (if (not teco:exp-flag1)
  804.      (teco:error "NAQ"))
  805.  ;; consume argument
  806.  (setq teco:exp-flag1 nil
  807.        teco:exp-op 'start)
  808.  (let* (;; get the test specification
  809.     (c (aref teco:mapch-l (teco:get-command teco:trace)))
  810.     ;; determine whether the test is true
  811.     (test (cond ((eq c ?a)
  812.              (/= (logand (aref teco:char-types teco:exp-val1)
  813.                  1) 0))
  814.             ((eq c ?c)
  815.              (/= (logand (aref teco:char-types teco:exp-val1)
  816.                  2) 0))
  817.             ((eq c ?d)
  818.              (/= (logand (aref teco:char-types teco:exp-val1)
  819.                  4) 0))
  820.             ((or (eq c ?e) (eq c ?f) (eq c ?u) (eq c ?=))
  821.              (= teco:exp-val1 0))
  822.             ((or (eq c ?g) (eq c ?>))
  823.              (> teco:exp-val1 0))
  824.             ((or (eq c ?l) (eq c ?s) (eq c ?t) (eq c ?<))
  825.              (< teco:exp-val1 0))
  826.             ((eq c ?n)
  827.              (/= teco:exp-val1 0))
  828.             ((eq c ?r)
  829.              (/= (logand (aref teco:char-types teco:exp-val1)
  830.                  8) 0))
  831.             ((eq c ?v)
  832.              (/= (logand (aref teco:char-types teco:exp-val1)
  833.                  16) 0))
  834.             ((eq c ?w)
  835.              (/= (logand (aref teco:char-types teco:exp-val1)
  836.                  32) 0))
  837.             (t
  838.              (teco:error "IQC")))))
  839.    (if (not test)
  840.        ;; if the conditional isn't satisfied, read
  841.        ;; to matching | or '
  842.        (let ((ll 1)
  843.          c)
  844.      (while (> ll 0)
  845.        (while (progn (setq c (teco:skipto))
  846.              (and (/= c ?\")
  847.                   (/= c ?|)
  848.                   (/= c ?\')))
  849.          (if (= c ?\")
  850.          (setq ll (1+ ll))
  851.            (if (= c ?\')
  852.            (setq ll (1- ll))
  853.          (if (= ll 1)
  854.              (break))))))))))
  855.  
  856. (teco:define-type-2
  857.  ?'                    ; '
  858.  ;; ignore it if executing
  859.  t)
  860.  
  861. (teco:define-type-2
  862.  ?|                    ; |
  863.  (let ((ll 1)
  864.        c)
  865.    (while (> ll 0)
  866.      (while (progn (setq c (teco:skipto))
  867.            (and (/= c ?\")
  868.             (/= c ?\')))
  869.        nil)
  870.      (if (= c ?\")
  871.      (setq ll (1+ ll))
  872.        (setq ll (1- ll))))))
  873.  
  874. (teco:define-type-2
  875.  ?u                    ; u
  876.  (if (not teco:exp-flag1)
  877.      (teco:error "NAU"))
  878.  (aset teco:qreg-number
  879.        (teco:get-qspec 0 (teco:get-command teco:trace))
  880.        teco:exp-val1)
  881.  (setq teco:exp-flag1 teco:exp-flag2    ; command's value is second arg
  882.        teco:exp-val1 teco:exp-val2
  883.        teco:exp-flag2 nil
  884.        teco:exp-op 'start))
  885.  
  886. (teco:define-type-2
  887.  ?q                    ; q
  888.  ;; Qn is numeric val, :Qn is # of chars, mQn is mth char
  889.  (let ((mm (teco:get-qspec (or teco:colon-flag teco:exp-flag1)
  890.                (teco:get-command teco:trace))))
  891.    (if (not teco:exp-flag1)
  892.        (setq teco:exp-val1 (if teco:colon-flag
  893.                    ;; :Qn
  894.                    (length (aref teco:qreg-text mm))
  895.                  ;; Qn
  896.                  (aref teco:qreg-number mm))
  897.          teco:exp-flag1 t)
  898.      ;; mQn
  899.      (let ((v (aref teco:qreg-text mm)))
  900.        (setq teco:exp-val1 (condition-case nil
  901.                    (aref v teco:exp-val1)
  902.                  (error -1))
  903.          teco:exp-op 'start)))
  904.    (setq teco:colon-flag nil)))
  905.  
  906. (teco:define-type-2
  907.  ?%                    ; %
  908.  (let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
  909.     (v (+ (aref teco:qreg-number mm) (teco:get-value 1))))
  910.    (aset teco:qreg-number mm v)
  911.    (setq teco:exp-val1 v
  912.      teco:exp-flag1 t)))
  913.  
  914. (teco:define-type-2
  915.  ?c                    ; c
  916.  (let ((p (+ (point) (teco:get-value 1))))
  917.    (if (or (< p (point-min)) (> p (point-max)))
  918.        (teco:error "POP")
  919.      (goto-char p)
  920.      (setq teco:exp-flag2 nil))))
  921.  
  922. (teco:define-type-2
  923.  ?r                    ; r
  924.  (let ((p (- (point) (teco:get-value 1))))
  925.    (if (or (< p (point-min)) (> p (point-max)))
  926.        (teco:error "POP")
  927.      (goto-char p)
  928.      (setq teco:exp-flag2 nil))))
  929.  
  930. (teco:define-type-2
  931.  ?j                    ; j
  932.  (let ((p (teco:get-value (point-min))))
  933.    (if (or (< p (point-min)) (> p (point-max)))
  934.        (teco:error "POP")
  935.      (goto-char p)
  936.      (setq teco:exp-flag2 nil))))
  937.  
  938. (teco:define-type-2
  939.  ?l                    ; l
  940.  ;; move forward by lines
  941.  (forward-char (teco:lines (teco:get-value 1))))
  942.  
  943. (teco:define-type-2
  944.  ?\C-q                    ; ^q
  945.  ;; number of characters until the nth line feed
  946.  (setq teco:exp-val1 (teco:lines (teco:get-value 1))
  947.        teco:exp-flag1 t))
  948.  
  949. (teco:define-type-2
  950.  ?=                    ; =
  951.  ;; print numeric value
  952.  (if (not teco:exp-flag1)
  953.      (teco:error "NAE"))
  954.  (teco:output (format
  955.            (if (teco:peek-command ?=)
  956.            ;; at least one more =
  957.            (progn
  958.              ;; read past it
  959.              (teco:get-command teco:trace)
  960.              (if (teco:peek-command ?=)
  961.              ;; another?
  962.              (progn
  963.                ;; read it too
  964.                (teco:get-command teco:trace)
  965.                ;; print in hex
  966.                "%x")
  967.                ;; print in octal
  968.                "%o"))
  969.          ;; print in decimal
  970.          "%d")
  971.            teco:exp-val1))
  972.  ;; add newline if no colon
  973.  (if (not teco:colon-flag)
  974.      (teco:output ?\n))
  975.  ;; absorb argument, etc.
  976.  (setq teco:exp-flag1 nil
  977.        teco:exp-flag2 nil
  978.        teco:colon-flag nil
  979.        teco:exp-op 'start))
  980.  
  981. (teco:define-type-2
  982.  ?\t                    ; TAB
  983.  (if exp-flag1
  984.      (teco:error "IIA"))
  985.  (let ((text (teco:get-text-arg)))
  986.    (insert ?\t text)
  987.    (setq teco:ctrl-s (1+ (length text))))
  988.  ;; clear arguments
  989.  (setq teco:colon-flag nil
  990.        teco:exp-flag1 nil
  991.        teco:exp-flag2 nil))
  992.  
  993. (teco:define-type-2
  994.  ?i                    ; i
  995.  (let ((text (teco:get-text-arg)))
  996.    (if teco:exp-flag1
  997.        ;; if a nI$ command
  998.        (progn
  999.      ;; text argument must be null
  1000.      (or (string-equal text "") (teco:error "IIA"))
  1001.      ;; insert the character
  1002.      (insert teco:exp-val1)
  1003.      (setq teco:ctrl-s 1)
  1004.      ;; consume argument
  1005.      (setq teco:exp-op 'start))
  1006.      ;; otherwise, insert the text
  1007.      (insert text)
  1008.      (setq teco:ctrl-s (length text)))
  1009.    ;; clear arguments
  1010.    (setq teco:colon-flag nil
  1011.      teco:exp-flag1 nil
  1012.      teco:exp-flag2 nil)))
  1013.  
  1014. (teco:define-type-2
  1015.  ?t                    ; t
  1016.  (let ((args (teco:line-args nil)))
  1017.    (teco:output (buffer-substring (car args) (cdr args)))))
  1018.  
  1019. (teco:define-type-2
  1020.  ?v                    ; v
  1021.  (let ((ll (teco:get-value 1)))
  1022.    (teco:output (buffer-substring (+ (point) (teco:lines (- 1 ll)))
  1023.                   (+ (point) (teco:lines ll))))))
  1024.  
  1025. (teco:define-type-2
  1026.  ?\C-a                    ; ^a
  1027.  (teco:output (teco:get-text-arg nil ?\C-a))
  1028.  (setq teco:at-flag nil
  1029.        teco:colon-flag nil
  1030.        teco:exp-flag1 nil
  1031.        teco:exp-flag2 nil
  1032.        teco:exp-op 'start))
  1033.  
  1034. (teco:define-type-2
  1035.  ?d                    ; d
  1036.  (if (not teco:exp-flag2)
  1037.      ;; if only one argument
  1038.      (delete-char (teco:get-value 1))
  1039.    ;; if two arguments, treat as n,mK
  1040.    (let ((ll (teco:line-args 1)))
  1041.      (delete-region (car ll) (cdr ll)))))
  1042.  
  1043. (teco:define-type-2
  1044.  ?k                    ; k
  1045.  (let ((ll (teco:line-args 1)))
  1046.    (delete-region (car ll) (cdr ll))))
  1047.  
  1048. (teco:define-type-2
  1049.  ?\C-u                    ; ^u
  1050.  (let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
  1051.     (text-arg (teco:get-text-arg))
  1052.     (text (if (not teco:exp-flag1)
  1053.           text-arg
  1054.         (if (string-equal text-arg "")
  1055.             (char-to-string teco:exp-val1)
  1056.           (teco:error "IIA")))))
  1057.    ;; if :, append to the register
  1058.    (aset teco:qreg-text mm (if teco:colon-flag
  1059.                    (concat (aref teco:qreg-text mm) text)
  1060.                  text))
  1061.    ;; clear various flags
  1062.    (setq teco:exp-flag1 nil
  1063.      teco:at-flag nil
  1064.      teco:colon-flag nil
  1065.      teco:exp-flag1 nil)))
  1066.  
  1067. (teco:define-type-2
  1068.  ?x                    ; x
  1069.  (let* ((mm (teco:get-qspec nil (teco:get-command teco:trace)))
  1070.     (args (teco:line-args 0))
  1071.     (text (buffer-substring (car args) (cdr args))))
  1072.    ;; if :, append to the register
  1073.    (aset teco:qreg-text mm (if teco:colon-flag
  1074.                    (concat (aref teco:qreg-text mm) text)
  1075.                  text))
  1076.    ;; clear various flags
  1077.    (setq teco:exp-flag1 nil
  1078.      teco:at-flag nil
  1079.      teco:colon-flag nil
  1080.      teco:exp-flag1 nil)))
  1081.  
  1082. (teco:define-type-2
  1083.  ?g                    ; g
  1084.  (let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
  1085.    (if teco:colon-flag
  1086.        (teco:output (aref teco:qreg-text mm))
  1087.      (insert (aref teco:qreg-text mm)))
  1088.    (setq teco:colon-flag nil)))
  1089.  
  1090. (teco:define-type-2
  1091.  ?\[                    ; \[
  1092.  (let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
  1093.    (setq teco:qreg-stack
  1094.      (cons (cons (aref teco:qreg-text mm)
  1095.              (aref teco:qreg-number mm))
  1096.            teco:qreg-stack))))
  1097.  
  1098. (teco:define-type-2
  1099.  ?\]                    ; \]
  1100.  (let ((mm (teco:get-qspec t (teco:get-command teco:trace))))
  1101.    (if teco:colon-flag
  1102.        (setq teco:exp-flag1 t
  1103.          teco:exp-val1 (if teco:qreg-stack -1 0))
  1104.      (if teco:qreg-stack
  1105.      (let ((pop (car teco:qreg-stack)))
  1106.        (aset teco:qreg-text mm (car pop))
  1107.        (aset teco:qreg-number mm (cdr pop))
  1108.        (setq teco:qreg-stack (cdr teco:qreg-stack)))
  1109.        (teco:error "CPQ")))
  1110.    (setq teco:colon-flag nil)))
  1111.  
  1112. (teco:define-type-2
  1113.  ?\\                    ; \
  1114.  (if (not teco:exp-flag1)
  1115.      ;; no argument; read number
  1116.      (let ((p (point))
  1117.        (sign +1)
  1118.        (n 0)
  1119.        c)
  1120.        (setq c (char-after p))
  1121.        (if c
  1122.        (if (= c ?+)
  1123.            (setq p (1+ p))
  1124.          (if (= c ?-)
  1125.          (setq p (1+ p)
  1126.                sign -1))))
  1127.        (cond
  1128.     ((= teco:ctrl-r 8) 
  1129.      (while (progn
  1130.           (setq c (char-after p))
  1131.           (and c (>= c ?0) (<= c ?7)))
  1132.        (setq p (1+ p)
  1133.          n (+ c -48 (* n 8)))))
  1134.     ((= teco:ctrl-r 10) 
  1135.      (while (progn
  1136.           (setq c (char-after p))
  1137.           (and c (>= c ?0) (<= c ?9)))
  1138.        (setq p (1+ p)
  1139.          n (+ c -48 (* n 10)))))
  1140.     (t
  1141.      (while (progn
  1142.           (setq c (char-after p))
  1143.           (and c
  1144.                (or
  1145.             (and (>= c ?0) (<= c ?9))
  1146.             (and (>= c ?a) (<= c ?f))
  1147.             (and (>= c ?A) (<= c ?F)))))
  1148.        (setq p (1+ p)
  1149.          n (+ c (if (> c ?F)
  1150.                 ;; convert 'a' to 10
  1151.                 -87 
  1152.               (if (> c ?9)
  1153.                   ;; convert 'A' to 10
  1154.                   -55
  1155.                 ;; convert '0' to 0
  1156.                 -48))
  1157.               (* n 16))))))
  1158.        (setq teco:exp-val1 (* n sign)
  1159.          teco:exp-flag1 t
  1160.          teco:ctrl-s (- (point) p)))
  1161.    ;; argument: insert it as a digit string
  1162.    (insert (format (cond 
  1163.             ((= teco:ctrl-r 8) "%o")
  1164.             ((= teco:ctrl-r 10) "%d")
  1165.             (t "%x"))
  1166.            teco:exp-val1))
  1167.    (setq teco:exp-flag1 nil
  1168.      teco:exp-op 'start)))
  1169.  
  1170. (teco:define-type-2
  1171.  ?\C-t                    ; ^t
  1172.  (if teco:exp-flag1
  1173.      ;; type a character
  1174.      (progn
  1175.        (teco:output teco:exp-val1)
  1176.        (setq teco:exp-flag1 nil))
  1177.    ;; input a character
  1178.    (let* ((echo-keystrokes 0)
  1179.       (c (read-char)))
  1180.      (teco:output c)
  1181.      (setq teco:exp-val1 c
  1182.        teco:exp-flag1 t))))
  1183.  
  1184. (teco:define-type-2
  1185.  ?s                    ; s
  1186.  (let ((arg (teco:get-text-arg))
  1187.        (count (if teco:exp-flag1 teco:expr-val1 1))
  1188.        regexp)
  1189.    (if (not (string-equal arg ""))
  1190.        (setq regexp (teco:parse-search-string arg)
  1191.          teco:last-search-string arg
  1192.          teco:last-search-regexp regexp)
  1193.      (setq regexp (teco:last-search-regexp)
  1194.        arg teco:last-search-string))
  1195.    (let ((p (point))
  1196.      (result (cond
  1197.           ((> count 0)
  1198.            (re-search-forward regexp nil t count))
  1199.           ((< count 0)
  1200.            (re-search-backward regexp nil t count))
  1201.           (t
  1202.            ;; 0s always is successful
  1203.            t))))
  1204.      ;; if ::s, restore point
  1205.      (if (eq teco:colon-flag 2)
  1206.      (goto-char p))
  1207.      ;; if no real or implied colon, error if not found
  1208.      (if (and (not result)
  1209.           (not teco:colon-flag)
  1210.           (/= (teco:peekcmdc) 34))
  1211.      (teco:error "SRH"))
  1212.      ;; set return results
  1213.      (setq teco:exp-flag2 nil
  1214.        teco:colon-flag nil
  1215.        teco:at-flag nil
  1216.        teco:exp-op 'start)
  1217.      (if teco:colon-flag
  1218.      (setq teco:exp-flag1 t
  1219.            teco:exp-val1 (if result -1 0))
  1220.        (setq teco:exp-flag1 nil)))))
  1221.  
  1222. (defun teco:parse-search-string (s)
  1223.   (let ((i 0)
  1224.     (l (length s))
  1225.     (r "")
  1226.     c)
  1227.     (while (< i l)
  1228.       (setq r (concat r (teco:parse-search-string-1))))
  1229.     r))
  1230.  
  1231. (defun teco:parse-search-string-1 ()
  1232.   (if (>= i l)
  1233.       (teco:error "ISS"))
  1234.   (setq c (aref s i))
  1235.   (setq i (1+ i))
  1236.   (cond
  1237.    ((eq c ?\C-e)            ; ^E - special match characters
  1238.     (teco:parse-search-string-e))
  1239.    ((eq c ?\C-n)            ; ^Nx - match all but x
  1240.     (teco:parse-search-string-n))
  1241.    ((eq c ?\C-q)            ; ^Qx - use x literally
  1242.     (teco:parse-search-string-q))
  1243.    ((eq c ?\C-s)            ; ^S - match separator chars
  1244.     "[^A-Za-z0-9]")
  1245.    ((eq c ?\C-x)            ; ^X - match any character
  1246.     "[\000-\377]")
  1247.    (t                    ; ordinary character
  1248.     (teco:parse-search-string-char c))))
  1249.  
  1250. (defun teco:parse-search-string-char (c)
  1251.   (regexp-quote (char-to-string c)))
  1252.  
  1253. (defun teco:parse-search-string-q ()
  1254.   (if (>= i l)
  1255.       (teco:error "ISS"))
  1256.   (setq c (aref s i))
  1257.   (setq i (1+ i))
  1258.   (teco:parse-search-string-char c))
  1259.  
  1260. (defun teco:parse-search-string-e ()
  1261.   (if (>= i l)
  1262.       (teco:error "ISS"))
  1263.   (setq c (aref s i))
  1264.   (setq i (1+ i))
  1265.   (cond
  1266.    ((or (eq c ?a) (eq c ?A))        ; ^EA - match alphabetics
  1267.     "[A-Za-z]")
  1268.    ((or (eq c ?c) (eq c ?C))        ; ^EC - match symbol constituents
  1269.     "[A-Za-z.$]")
  1270.    ((or (eq c ?d) (eq c ?D))        ; ^ED - match numerics
  1271.     "[0-9]")
  1272.    ((eq c ?g)                ; ^EGq - match any char in q-reg
  1273.     (teco:parse-search-string-e-g))
  1274.    ((or (eq c ?l) (eq c ?L))        ; ^EL - match line terminators
  1275.     "[\012\013\014]")
  1276.    ((eq c ?q)                ; ^EQq - use contents of q-reg
  1277.     (teco:parse-search-string-e-q))
  1278.    ((eq c ?r)                ; ^ER - match alphanumerics
  1279.     "[A-Za-z0-9]")
  1280.    ((eq c ?s)                ; ^ES - match non-null space/tab seq
  1281.     "[ \t]+")
  1282.    ((eq c ?v)                ; ^EV - match lower case alphabetic
  1283.     "[a-z]")
  1284.    ((eq c ?w)                ; ^EW - match upper case alphabetic
  1285.     "[A-Z]")
  1286.    ((eq c ?x)                ; ^EX - match any character
  1287.     "[\000-\377]")
  1288.    (t
  1289.     (teco:error "ISS"))))
  1290.  
  1291. (defun teco:parse-search-string-e-q ()
  1292.   (if (>= i l)
  1293.       (teco:error "ISS"))
  1294.   (setq c (aref s i))
  1295.   (setq i (1+ i))
  1296.   (regexp-quote (aref reco:q-reg-text c)))
  1297.  
  1298. (defun teco:parse-search-string-e-g ()
  1299.   (if (>= i l)
  1300.       (teco:error "ISS"))
  1301.   (setq c (aref s i))
  1302.   (setq i (1+ i))
  1303.   (let* ((q (aref teco:qreg-text c))
  1304.      (len (length q))
  1305.      (null (= len 0))
  1306.      (one-char (= len 1))
  1307.      (dash-present (string-match "-" q))
  1308.      (caret-present (string-match "\\^" q))
  1309.      (outbracket-present (string-match "]" q))
  1310.      p)
  1311.     (cond
  1312.      (null
  1313.       "[^\000-\377]")
  1314.      (one-char
  1315.       (teco:parse-search-string-char c))
  1316.      (t
  1317.       (while (setq p (string-match "^]\\^"))
  1318.     (setq q (concat (substring q 1 p) (substring q (1+ p)))))
  1319.       (concat
  1320.        "["
  1321.        (if outbracket-present "]" "")
  1322.        (if dash-present "---" "")
  1323.        q
  1324.        (if caret-present "^" ""))))))
  1325.  
  1326. (defun teco:parse-search-string-n ()
  1327.   (let ((p (teco:parse-search-string-1)))
  1328.     (cond
  1329.      ((= (aref p 0) ?\[)
  1330.       (if (= (aref p 1) ?^)
  1331.       ;; complement character set
  1332.       (if (= (length p) 4)
  1333.           ;; complement of one character
  1334.           (teco:parse-search-string-char (aref p 2))
  1335.         ;; complement of more than one character
  1336.         (concat "[" (substring p 2)))
  1337.     ;; character set - invert it
  1338.       (concat "[^" (substring p 1))))
  1339.      ((= (aref p 0) ?\\)
  1340.       ;; single quoted character
  1341.       (concat "[^" (substring p 1) "]"))
  1342.      (t
  1343.       ;; single character
  1344.       (if (string-equal p "-")
  1345.       "[^---]"
  1346.     (concat "[^" p "]"))))))
  1347.  
  1348. (teco:define-type-2
  1349.  ?o                    ; o
  1350.  (let ((label (teco:get-text-arg))
  1351.        (index (and teco:exp-flag1 teco:exp-val1)))
  1352.    (setq teco:exp-flag1 nil)
  1353.    ;; handle computed goto by extracting the proper label
  1354.    (if index
  1355.        (if (< index 0)
  1356.        ;; argument < 0 is a noop
  1357.        (setq label "")
  1358.      ;; otherwise, find the n-th label (0-origin)
  1359.      (setq label (concat label ","))
  1360.      (let ((p 0))
  1361.        (while (and (> index 0)
  1362.                (setq p (string-match "," label p))
  1363.                (setq p (1+ p)))
  1364.          (setq index (1- index)))
  1365.        (setq q (string-match "," label p))
  1366.        (setq label (substring label p q)))))
  1367.    ;; if the label is non-null, find the correct label
  1368.    ;; start from beginning of iteration or macro, and look for tag
  1369.    (setq teco:command-pointer
  1370.      (if teco:iteration-stack
  1371.          ;; if in iteration, start at beginning of iteration
  1372.          (aref (car teco:iteration-stack) 0)
  1373.        ;; if not in iteration, start at beginning of command or macro
  1374.        0))
  1375.    ;; search for tag
  1376.    (catch 'label
  1377.      (let ((level 0)
  1378.        c p l)
  1379.        ;; look for interesting things, including !
  1380.        (while t
  1381.      (setq c (teco:skipto t))
  1382.      (cond
  1383.       ((= c ?<)            ; start of iteration
  1384.        (setq level (1+ level)))
  1385.       ((= c ?>)            ; end of iteration
  1386.        (if (= level 0)
  1387.            (teco:pop-iter-stack t)
  1388.          (setq level (1- level))))
  1389.       ((= c ?!)            ; start of tag
  1390.        (setq p (string-match "!" teco:command-string teco:command-pointer))
  1391.        (if (and p
  1392.             (string-equal label (substring teco:command-string
  1393.                            teco:command-pointer
  1394.                            p)))
  1395.            (progn
  1396.          (setq teco:command-pointer (1+ p))
  1397.          (throw 'label nil))))))))))
  1398.  
  1399. (teco:define-type-2
  1400.  ?a                    ; :a
  1401.  ;; 'a' must be used as ':a'
  1402.  (if (and teco:exp-flag1 teco:colon-flag)
  1403.      (let ((char (+ (point) teco:exp-val1)))
  1404.        (setq teco:exp-val1
  1405.          (if (and (>= char (point-min))
  1406.               (< char (point-max)))
  1407.          (char-after char)
  1408.            -1)
  1409.          teco:colon-flag nil))
  1410.    (teco:error "ILL")))
  1411.  
  1412.  
  1413. ;; Routines to get next character from command buffer
  1414. ;; getcmdc0, when reading beyond command string, pops
  1415. ;; macro stack and continues.
  1416. ;; getcmdc, in similar circumstances, reports an error.
  1417. ;; If pushcmdc() has returned any chars, read them first
  1418. ;; routines type characters as read, if argument != 0.
  1419.  
  1420. (defun teco:get-command0 (trace)
  1421.   ;; get the next character
  1422.   (let (char)
  1423.     (while (not (condition-case nil
  1424.             (setq char (aref teco:command-string teco:command-pointer))
  1425.           ;; if we've exhausted the string, pop the macro stack
  1426.           ;; if we exhaust the macro stack, exit
  1427.           (error (teco:pop-macro-stack)
  1428.              nil))))
  1429.     ;; bump the command pointer
  1430.     (setq teco:command-pointer (1+ teco:command-pointer))
  1431.     ;; trace, if requested
  1432.     (and trace (teco:trace-type char))
  1433.     ;; return the character
  1434.     char))
  1435.  
  1436. ;;     while (cptr.dot >= cptr.z)        /* if at end of this level, pop macro stack
  1437. ;;         {
  1438. ;;         if (--msp < &mstack[0])        /* pop stack; if top level
  1439. ;;             {
  1440. ;;             msp = &mstack[0];        /* restore stack pointer
  1441. ;;             cmdc = ESC;                /* return an ESC (ignored)
  1442. ;;             exitflag = 1;            /* set to terminate execution
  1443. ;;             return(cmdc);            /* exit "while" and return
  1444. ;;             }
  1445. ;;         }
  1446. ;;     cmdc = cptr.p->ch[cptr.c++];        /* get char
  1447. ;;     ++cptr.dot;                            /* increment character count
  1448. ;;     if (trace) type_char(cmdc);            /* trace
  1449. ;;     if (cptr.c > CELLSIZE-1)            /* and chain if need be
  1450. ;;         {
  1451. ;;         cptr.p = cptr.p->f;
  1452. ;;         cptr.c = 0;
  1453. ;;         }
  1454. ;;     return(cmdc);
  1455. ;;     }
  1456.  
  1457.  
  1458. (defun teco:get-command (trace)
  1459.   ;; get the next character
  1460.   (let ((char (condition-case nil
  1461.           (aref teco:command-string teco:command-pointer)
  1462.         ;; if we've exhausted the string, give error
  1463.         (error
  1464.          (teco:error (if teco:macro-stack "UTM" "UTC"))))))
  1465.     ;; bump the command pointer
  1466.     (setq teco:command-pointer (1+ teco:command-pointer))
  1467.     ;; trace, if requested
  1468.     (and trace (teco:trace-type char))
  1469.     ;; return the character
  1470.     char))
  1471.  
  1472. ;; char getcmdc(trace)
  1473. ;;     {
  1474. ;;     if (cptr.dot++ >= cptr.z) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  1475. ;;     else
  1476. ;;         {
  1477. ;;         cmdc = cptr.p->ch[cptr.c++];    /* get char
  1478. ;;         if (trace) type_char(cmdc);        /* trace
  1479. ;;         if (cptr.c > CELLSIZE-1)        /* and chain if need be
  1480. ;;             {
  1481. ;;             cptr.p = cptr.p->f;
  1482. ;;             cptr.c = 0;
  1483. ;;             }
  1484. ;;         }
  1485. ;;     return(cmdc);
  1486. ;;     }
  1487.  
  1488.  
  1489. ;; peek at next char in command string, return 1 if it is equal
  1490. ;; (case independent) to argument
  1491.  
  1492. (defun teco:peek-command (arg)
  1493.   (condition-case nil
  1494.       (eq (aref teco:mapch-l (aref teco:command-string teco:command-pointer))
  1495.       (aref teco:mapch-l arg))
  1496.     (error nil)))
  1497.  
  1498. ;; int peekcmdc(arg)
  1499. ;;     char arg;
  1500. ;;     {
  1501. ;;     return(((cptr.dot < cptr.z) && (mapch_l[cptr.p->ch[cptr.c]] == mapch_l[arg])) ? 1 : 0);
  1502. ;;     }
  1503.  
  1504. (defun teco:get-text-arg (&optional term-char default-term-char)
  1505.   ;; figure out what the terminating character is
  1506.   (setq teco:term-char (or term-char
  1507.                (if teco:at-flag
  1508.                    (teco:get-command teco:trace)
  1509.                  (or default-term-char
  1510.                  ?\e)))
  1511.     teco:at_flag nil)
  1512.   (let ((s "")
  1513.     c)
  1514.     (while (progn
  1515.          (setq c (teco:get-command teco:trace))
  1516.          (/= c teco:term-char))
  1517.       (setq s (concat s (char-to-string c))))
  1518.     s))
  1519.  
  1520.  
  1521. ;; Routines to manipulate the stacks
  1522.  
  1523. ;; Pop the macro stack.  Throw to 'teco:exit' if the stack is empty.
  1524. (defun teco:pop-macro-stack ()
  1525.   (if teco:macro-stack
  1526.       (let ((frame (car teco:macro-stack)))
  1527.     (setq teco:macro-stack (cdr teco:macro-stack)
  1528.           teco:command-string (aref frame 0)
  1529.           teco:command-pointer (aref frame 1)
  1530.           teco:exec-flags (aref frame 2)
  1531.           teco:iteration-stack (aref frame 3)
  1532.           teco:cond-stack (aref frame 4)))
  1533.     (throw 'teco:exit nil)))
  1534.  
  1535. ;; Push the macro stack.
  1536. (defun teco:push-macro-stack ()
  1537.   (setq teco:macro-stack
  1538.     (cons (vector teco:command-string
  1539.               teco:command-pointer
  1540.               teco:exec-flags
  1541.               teco:iteration-stack
  1542.               teco:cond-stack)
  1543.           teco:macro-stack)))
  1544.  
  1545. ;; Pop the expression stack.
  1546. (defun teco:pop-exp-stack ()
  1547.   (let ((frame (car teco:exp-stack)))
  1548.     (setq teco:exp-stack (cdr teco:exp-stack)
  1549.       teco:exp-val1 (aref frame 0)
  1550.       teco:exp-flag1 (aref frame 1)
  1551.       teco:exp-val2 (aref frame 2)
  1552.       teco:exp-flag2 (aref frame 3)
  1553.       teco:exp-exp (aref frame 4)
  1554.       teco:exp-op (aref frame 5))))
  1555.  
  1556. ;; Push the expression stack.
  1557. (defun teco:push-exp-stack ()
  1558.   (setq teco:exp-stack
  1559.     (cons (vector teco:exp-val1
  1560.               teco:exp-flag1
  1561.               teco:exp-val2
  1562.               teco:exp-flag2
  1563.               teco:exp-exp
  1564.               teco:exp-op)
  1565.           teco:exp-stack)))
  1566.  
  1567. ;; Pop the iteration stack
  1568. ;; if arg t, exit unconditionally
  1569. ;; else check exit conditions and exit or reiterate
  1570. (defun teco:pop-iter-stack (arg)
  1571.   (let ((frame (car teco:iteration-stack)))
  1572.     (if (or arg
  1573.         (not (aref frame 1))
  1574.         ;; test against 1, since one iteration has already been done
  1575.         (<= (aref frame 2) 1))
  1576.     ;; exit iteration
  1577.     (setq teco:iteration-stack (cdr teco:iteration-stack))
  1578.       ;; continue with iteration
  1579.       ;; decrement count
  1580.       (aset frame 2 (1- (aref frame 2)))
  1581.       ;; reset command pointer
  1582.       (setq teco:command-pointer (aref frame 0)))))
  1583.  
  1584. ;; Push the iteration stack
  1585. (defun teco:push-iter-stack (pointer flag count)
  1586.   (setq teco:iteration-stack
  1587.     (cons (vector pointer
  1588.               flag
  1589.               count)
  1590.           teco:iteration-stack)))          
  1591.  
  1592. (defun teco:find-enditer ()
  1593.   (let ((icnt 1)
  1594.     c)
  1595.     (while (> icnt 0)
  1596.       (while (progn (setq c (teco:skipto))
  1597.             (and (/= c ?<)
  1598.              (/= c ?>)))
  1599.     (if (= c ?<)
  1600.         (setq icnt (1+ icnt))
  1601.       (setq icnt (1- icnt)))))))
  1602.  
  1603.  
  1604. ;; I/O routines
  1605.  
  1606. (defvar teco:output-buffer (get-buffer-create "*Teco Output*")
  1607.   "The buffer into which Teco output is written.")
  1608.  
  1609. (defun teco:out-init ()
  1610.   ;; Recreate the teco output buffer, if necessary
  1611.   (setq teco:output-buffer (get-buffer-create "*Teco Output*"))
  1612.   (save-excursion
  1613.     (set-buffer teco:output-buffer)
  1614.     ;; get a fresh line in output buffer
  1615.     (goto-char (point-max))
  1616.     (insert ?\n)
  1617.     ;; remember where to start displaying
  1618.     (setq teco:output-start (point))
  1619.     ;; clear minibuffer, in case we have to display in it
  1620.     (save-window-excursion
  1621.       (select-window (minibuffer-window))
  1622.       (erase-buffer))
  1623.     ;; if output is visible, position it correctly
  1624.     (let ((w (get-buffer-window teco:output-buffer)))
  1625.       (if w
  1626.       (progn
  1627.         (set-window-start w teco:output-start)
  1628.         (set-window-point w teco:output-start))))))
  1629.  
  1630. (defun teco:output (s)
  1631.   (let ((w (get-buffer-window teco:output-buffer))
  1632.     (b (current-buffer))
  1633.     (sw (selected-window)))
  1634.     ;; Put the text in the output buffer
  1635.     (set-buffer teco:output-buffer)
  1636.     (goto-char (point-max))
  1637.     (insert s)
  1638.     (let ((p (point)))
  1639.       (set-buffer b)
  1640.       (if w
  1641.       ;; if output is visible, move the window point to the end
  1642.       (set-window-point w p)
  1643.     ;; Otherwise, we have to figure out how to display the text
  1644.     ;; Has a newline followed by another character been added to the
  1645.     ;; output buffer?  If so, we have to make the output buffer visible.
  1646.     (if (save-excursion
  1647.           (set-buffer teco:output-buffer)
  1648.           (backward-char 1)
  1649.           (search-backward "\n" teco:output-start t))
  1650.         ;; a newline has been seen, clear the minibuffer and make the
  1651.         ;; output buffer visible
  1652.         (progn
  1653.           (save-window-excursion
  1654.         (select-window (minibuffer-window))
  1655.         (erase-buffer))
  1656.           (let ((pop-up-windows t))
  1657.         (pop-to-buffer teco:output-buffer)
  1658.         (goto-char p)
  1659.         (set-window-start w teco:output-start)
  1660.         (set-window-point w p)
  1661.         (select-window sw)))
  1662.       ;; a newline has not been seen, add output to minibuffer
  1663.       (save-window-excursion
  1664.         (select-window (minibuffer-window))
  1665.         (goto-char (point-max))
  1666.         (insert s)))))))
  1667.  
  1668. ;; Output a character of tracing information
  1669. (defun teco:trace-type (c)
  1670.   (teco:output (if (= c ?\e)
  1671.         ?$
  1672.           c)))
  1673.  
  1674. ;; Report an error
  1675. (defun teco:error (code)
  1676.   (let ((text (cdr (assoc code teco:error-texts))))
  1677.     (teco:output (concat (if (save-excursion (set-buffer teco:output-buffer)
  1678.                          (/= (point) teco:output-start))
  1679.                  "\n"
  1680.                "")
  1681.              "? " code " " text))
  1682.     (beep)
  1683.     (if debug-on-error (debug nil code text))
  1684.     (throw 'teco:exit nil)))
  1685.  
  1686.  
  1687. ;; Utility routines
  1688.  
  1689. ;; copy characters from command string to buffer
  1690. (defun teco:moveuntil (string pointer terminate trace)
  1691.   (let ((count 0))
  1692.     (condition-case nil
  1693.     (while (/= (aref string pointer) terminate)
  1694.       (and teco:trace (teco:trace-type (aref string pointer)))
  1695.       (insert (aref string pointer))
  1696.       (setq pointer (1+ pointer))
  1697.       (setq count (1+ count)))
  1698.       (error (teco:error (if teco:macro-stack "UTM" "UTC"))))
  1699.     count))
  1700.  
  1701. ;; Convert character to q-register name
  1702. ;; If file-or-search is t, allow _, *, %, #
  1703. (defun teco:get-qspec (file-or-search char)
  1704.   ;; lower-case char
  1705.   (setq char (aref teco:mapch-l char))
  1706.   ;; test that it's valid
  1707.   (if (= (logand (aref teco:qspec-valid char) (if file-or-search 2 1)) 0)
  1708.       (teco:error "IQN"))
  1709.   char)
  1710.  
  1711. ;; Set or get value of a variable
  1712. (defun teco:set-var (var)
  1713.   (if teco:exp-flag1
  1714.       (progn
  1715.     (if teco:exp-flag2
  1716.         ;; if two arguments, they they are <clear bits>, <set bits>
  1717.         (set var (logior (logand (symbol-value var) (lognot teco:exp-val2))
  1718.                  teco:exp-val1))
  1719.       ;; if one argument, it is the new value
  1720.       (set var teco:exp-val1))
  1721.     ;; consume argument(s)
  1722.     (setq teco:exp-flag2 nil
  1723.           teco:exp-flag1 nil))
  1724.     ;; if no arguments, fetch the value
  1725.     (setq teco:exp-val1 (symbol-value var)
  1726.       teco:exp-flag1 t)))
  1727.  
  1728. ;; Get numeric argument
  1729. (defun teco:get-value (default)
  1730.   (prog1
  1731.       (if teco:exp-flag1
  1732.       teco:exp-val1
  1733.     (if (eq teco:exp-op 'sub)
  1734.         (- default)
  1735.       default))
  1736.     ;; consume argument
  1737.     (setq teco:exp-flag1 nil
  1738.       teco:exp-op 'start)))
  1739.  
  1740. ;; Get argument measuring in lines
  1741. (defun teco:lines (r)
  1742.   (- (save-excursion
  1743.        (if (> r 0)
  1744.        (if (search-forward "\n" nil t r)
  1745.            (point)
  1746.          (point-max))
  1747.      (if (search-backward "\n" nil t (- 1 r))
  1748.          (1+ (point))
  1749.        (point-min))))
  1750.      (point)))
  1751.  
  1752. ;; routine to handle args for K, T, X, etc.
  1753. ;; if two args, 'char x' to 'char y'
  1754. ;; if just one arg, then n lines (default 1)
  1755. (defun teco:line-args (arg)
  1756.   (if teco:exp-flag2
  1757.       (cons teco:exp-val1 teco:exp-val2)
  1758.     (cons (point) (+ (point) (teco:lines (if teco:exp-flag1
  1759.                          teco:exp-val1
  1760.                        1))))))
  1761.  
  1762. ;; routine to skip to next ", ', |, <, or >
  1763. ;; skips over these chars embedded in text strings
  1764. ;; stops in ! if argument is t
  1765. ;; returns character found
  1766. (defun teco:skipto (&optional arg)
  1767.   (catch 'teco:skip
  1768.     (let (;; "at" prefix
  1769.       (atsw nil)
  1770.       ;; temp attributes
  1771.       ta
  1772.       ;; terminator
  1773.       term
  1774.       skipc)
  1775.       (while t                ; forever
  1776.     (while (progn
  1777.          (setq skipc (teco:get-command nil)
  1778.                ta (aref teco:spec-chars skipc))
  1779.          ;; if char is ^, treat next char as control
  1780.          (if (eq skipc ?^)
  1781.              (setq skipc (logand 31 (teco:get-command nil))
  1782.                ta (aref teco:spec-chars skipc)))
  1783.          (= (logand ta 51) 0))    ; read until something interesting
  1784.                     ; found
  1785.       nil)
  1786.     (if (/= (logand ta 32) 0)
  1787.         (teco:get-command nil))    ; if command takes a Q spec,
  1788.                     ; skip the spec
  1789.     (if (/= (logand ta 16) 0)    ; sought char found: quit 
  1790.         (progn
  1791.           (if (= skipc ?\")        ; quote must skip next char
  1792.           (teco:get-command nil))
  1793.           (throw 'teco:skip skipc)))
  1794.     (if (/= (logand ta 1) 0)    ; other special char
  1795.         (cond
  1796.          ((eq skipc ?@)        ; use alternative text terminator
  1797.           (setq atsw t))
  1798.          ((eq skipc ?\C-^)        ; ^^ is value of next char
  1799.                     ; skip that char
  1800.           (teco:get-command nil))
  1801.          ((eq skipc ?\C-a)        ; type text
  1802.           (setq term (if atsw (teco:get-command nil) ?\C-a)
  1803.             atsw nil)
  1804.           (while (/= (teco:get-command nil) term)
  1805.         nil))            ; skip text
  1806.          ((eq skipc ?!)        ; tag 
  1807.           (if arg
  1808.           (throw 'teco:skip skipc))
  1809.           (while (/= (teco:get-command nil) ?!)
  1810.         nil))            ; skip until next !
  1811.          ((or (eq skipc ?e)
  1812.           (eq skipc ?f))    ; first char of two-letter E or F
  1813.                     ; command
  1814.           nil)))            ; not implemented
  1815.     (if (/= (logand ta 2) 0)    ; command with a text
  1816.                     ; argument
  1817.         (progn
  1818.           (setq term (if atsw (teco:get-command nil) ?\e)
  1819.             atsw nil)
  1820.           (while (/= (teco:get-command nil) term)
  1821.         nil)            ; skip text
  1822.           ))))))
  1823.  
  1824.  
  1825. (defvar teco:command-keymap (make-vector 128 'teco:command-self-insert)
  1826.   "Keymap used while reading teco commands.")
  1827.  
  1828. (define-key teco:command-keymap "\^g" 'teco:command-ctrl-g)
  1829. (define-key teco:command-keymap "\^m" 'teco:command-return)
  1830. (define-key teco:command-keymap "\^u" 'teco:command-ctrl-u)
  1831. (define-key teco:command-keymap "\e" 'teco:command-escape)
  1832. (define-key teco:command-keymap "\^?" 'teco:command-delete)
  1833.  
  1834. (defvar teco:command-escapes nil
  1835.   "Records where ESCs are, since they are represented in the command buffer
  1836. by $.")
  1837.  
  1838. (defun teco:command ()
  1839.   "Read and execute a Teco command string."
  1840.   (interactive)
  1841.   (let* ((teco:command-escapes nil)
  1842.      (command (catch 'teco:command-quit
  1843.             (read-from-minibuffer teco:prompt nil
  1844.                       teco:command-keymap))))
  1845.     (if command
  1846.     (progn
  1847.       (while teco:command-escapes
  1848.         (aset command (car teco:command-escapes) ?\e)
  1849.         (setq teco:command-escapes (cdr teco:command-escapes)))
  1850.       (setq teco:output-buffer (get-buffer-create "*Teco Output*"))
  1851.       (save-excursion
  1852.         (set-buffer teco:output-buffer)
  1853.         (goto-char (point-max))
  1854.         (insert teco:prompt command))
  1855.       (teco:execute-command command)))))
  1856.  
  1857. (defun teco:read-command ()
  1858.   "Read a teco command string from the user."
  1859.   (let ((command (catch 'teco:command-quit
  1860.            (read-from-minibuffer teco:prompt nil
  1861.                      teco:command-keymap)))
  1862.     teco:command-escapes)
  1863.     (if command
  1864.     (while teco:command-escapes
  1865.       (aset command (car teco:command-escapes ?\e))
  1866.       (setq teco:command-escapes (cdr teco:command-escapes))))
  1867.     command))
  1868.  
  1869. (defun teco:command-self-insert ()
  1870.   (interactive)
  1871.   (insert last-command-char)
  1872.   (if (not (pos-visible-in-window-p))
  1873.       (enlarge-window 1)))
  1874.  
  1875. (defun teco:command-ctrl-g ()
  1876.   (interactive)
  1877.   (beep)
  1878.   (throw 'teco:command-quit nil))
  1879.  
  1880. (defun teco:command-return ()
  1881.   (interactive)
  1882.   (setq last-command-char ?\n)
  1883.   (teco:command-self-insert))
  1884.  
  1885. (defun teco:command-escape ()
  1886.   (interactive)
  1887.   ;; Two ESCs in a row terminate the command string
  1888.   (if (eq last-command 'teco:command-escape)
  1889.       (throw 'teco:command-quit (buffer-string)))
  1890.   (setq teco:command-escapes (cons (1- (point)) teco:command-escapes))
  1891.   (setq last-command-char ?$)
  1892.   (teco:command-self-insert))
  1893.  
  1894. (defun teco:command-ctrl-u ()
  1895.   (interactive)
  1896.   ;; delete the characters
  1897.   (kill-line 0)
  1898.   ;; forget that they were ESCs
  1899.   (while (and teco:command-escapes (<= (point) (car teco:command-escapes)))
  1900.       (setq teco:command-escapes (cdr teco:command-escapes)))
  1901.   ;; decide whether to shrink the window
  1902.   (while (let ((a (insert ?\n))
  1903.            (b (pos-visible-in-window-p))
  1904.            (c (backward-delete-char 1)))
  1905.        b)
  1906.     (shrink-window 1)))
  1907.  
  1908. (defun teco:command-delete ()
  1909.   (interactive)
  1910.   ;; delete the character
  1911.   (backward-delete-char 1)
  1912.   ;; forget that it was an ESC
  1913.   (if (and teco:command-escapes (= (point) (car teco:command-escapes)))
  1914.       (setq teco:command-escapes (cdr teco:command-escapes)))
  1915.   ;; decide whether to shrink the window
  1916.   (insert ?\n)
  1917.   (if (prog1 (pos-visible-in-window-p)
  1918.     (backward-delete-char 1))
  1919.       (shrink-window 1)))
  1920.