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