diff --git a/README.md b/README.md
index c54ed7e..c7269fe 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,9 @@
# decstuff
Various bits of data and code related to Digital Equipment Corporation
+
+This repository contains programs and data related, perhaps loosely,
+to DEC and its products.
+
+Current contents:
+* Fonts
+* TECO
diff --git a/fonts/Handbook/Handbook-Regular.ttf b/fonts/Handbook/Handbook-Regular.ttf
new file mode 100644
index 0000000..df92982
Binary files /dev/null and b/fonts/Handbook/Handbook-Regular.ttf differ
diff --git a/fonts/Handbook/Handbook.otf b/fonts/Handbook/Handbook.otf
new file mode 100644
index 0000000..77a6321
Binary files /dev/null and b/fonts/Handbook/Handbook.otf differ
diff --git a/fonts/Handbook/Handbook.sfd b/fonts/Handbook/Handbook.sfd
new file mode 100644
index 0000000..49af97b
--- /dev/null
+++ b/fonts/Handbook/Handbook.sfd
@@ -0,0 +1,1979 @@
+SplineFontDB: 3.0
+FontName: Handbook
+FullName: Handbook
+FamilyName: Handbook
+Weight: Book
+Copyright: (c) Paul Koning
+Version: 1.0
+ItalicAngle: 0
+UnderlinePosition: 0
+UnderlineWidth: 0
+Ascent: 800
+Descent: 200
+InvalidEm: 0
+sfntRevision: 0x00010000
+LayerCount: 2
+Layer: 0 1 "Back" 1
+Layer: 1 1 "Fore" 0
+XUID: [1021 82 -590886842 5483728]
+StyleMap: 0x0040
+FSType: 0
+OS2Version: 0
+OS2_WeightWidthSlopeOnly: 0
+OS2_UseTypoMetrics: 0
+CreationTime: -2082535712
+ModificationTime: 1461867665
+PfmFamily: 17
+TTFWeight: 400
+TTFWidth: 5
+LineGap: 0
+VLineGap: 0
+Panose: 2 11 6 3 5 3 2 2 2 4
+OS2TypoAscent: 941
+OS2TypoAOffset: 0
+OS2TypoDescent: -201
+OS2TypoDOffset: 0
+OS2TypoLinegap: 0
+OS2WinAscent: 941
+OS2WinAOffset: 0
+OS2WinDescent: 201
+OS2WinDOffset: 0
+HheadAscent: 941
+HheadAOffset: 0
+HheadDescent: -201
+HheadDOffset: 0
+OS2SubXSize: 0
+OS2SubYSize: 0
+OS2SubXOff: 0
+OS2SubYOff: 0
+OS2SupXSize: 0
+OS2SupYSize: 0
+OS2SupXOff: 0
+OS2SupYOff: 0
+OS2StrikeYSize: 0
+OS2StrikeYPos: 0
+OS2FamilyClass: 1283
+OS2Vendor: 'PfEd'
+OS2CodePages: 00000001.c0000000
+OS2UnicodeRanges: 00000001.00000000.00000000.00000000
+Lookup: 258 0 0 "'kern' Horizontal Kerning in Latin lookup 0" { "'kern' Horizontal Kerning in Latin lookup 0-1" [153,15,0] } ['kern' ('DFLT' <'dflt' > 'latn' <'dflt' > ) ]
+MarkAttachClasses: 1
+DEI: 91125
+KernClass2: 4 5 "'kern' Horizontal Kerning in Latin lookup 0-1"
+ 1 r
+ 1 t
+ 1 f
+ 13 a c d e g o q
+ 1 f
+ 1 t
+ 1 v
+ 0 {} 0 {} 0 {} 0 {} 0 {} 0 {} -98 {} 0 {} 42 {} 17 {} 0 {} -78 {} 0 {} -68 {} -98 {} 0 {} -98 {} -59 {} 39 {} 0 {}
+ShortTable: maxp 16
+ 1
+ 0
+ 42
+ 122
+ 3
+ 0
+ 0
+ 1
+ 0
+ 16
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+EndShort
+LangName: 1033 "" "" "Regular" "Handbook" "" "" "" "" "" "G. Paul Koning"
+Encoding: UnicodeBmp
+Compacted: 1
+UnicodeInterp: none
+NameList: AGL For New Fonts
+DisplaySize: -48
+AntiAlias: 1
+FitToEm: 0
+WidthSeparation: 100
+WinInfo: 0 16 6
+BeginPrivate: 0
+EndPrivate
+TeXData: 1 0 0 198656 99328 66218 573440 1048576 66218 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
+BeginChars: 65539 39
+
+StartChar: space
+Encoding: 32 32 0
+Width: 300
+Flags: W
+LayerCount: 2
+Fore
+Validated: 1
+EndChar
+
+StartChar: period
+Encoding: 46 46 1
+Width: 197
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+101 118 m 0,0,1
+ 113 118 113 118 123.5 113.5 c 128,-1,2
+ 134 109 134 109 142 101 c 128,-1,3
+ 150 93 150 93 154.5 82 c 128,-1,4
+ 159 71 159 71 159 60 c 0,5,6
+ 159 47 159 47 154.5 36 c 128,-1,7
+ 150 25 150 25 142 17.5 c 128,-1,8
+ 134 10 134 10 123 5 c 128,-1,9
+ 112 0 112 0 101 0 c 0,10,11
+ 88 0 88 0 77 5 c 128,-1,12
+ 66 10 66 10 58.5 17.5 c 128,-1,13
+ 51 25 51 25 46 36 c 128,-1,14
+ 41 47 41 47 41 60 c 0,15,16
+ 41 72 41 72 46 82.5 c 128,-1,17
+ 51 93 51 93 58.5 101 c 128,-1,18
+ 66 109 66 109 77 113.5 c 128,-1,19
+ 88 118 88 118 101 118 c 0,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: a
+Encoding: 97 97 2
+Width: 637
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+313 120 m 0,0,1
+ 344 120 344 120 372.5 132.5 c 128,-1,2
+ 401 145 401 145 421.5 166 c 128,-1,3
+ 442 187 442 187 454.5 214.5 c 128,-1,4
+ 467 242 467 242 467 274 c 0,5,6
+ 467 305 467 305 454.5 333.5 c 128,-1,7
+ 442 362 442 362 421.5 382.5 c 128,-1,8
+ 401 403 401 403 373 415.5 c 128,-1,9
+ 345 428 345 428 313 428 c 0,10,11
+ 281 428 281 428 253.5 415.5 c 128,-1,12
+ 226 403 226 403 205 382.5 c 128,-1,13
+ 184 362 184 362 171.5 334 c 128,-1,14
+ 159 306 159 306 159 274 c 0,15,16
+ 159 242 159 242 171.5 214.5 c 128,-1,17
+ 184 187 184 187 205 166 c 128,-1,18
+ 226 145 226 145 253.5 132.5 c 128,-1,19
+ 281 120 281 120 313 120 c 0,0,1
+469 52 m 1,20,21
+ 452 40 452 40 433.5 30.5 c 128,-1,22
+ 415 21 415 21 394.5 14 c 128,-1,23
+ 374 7 374 7 353.5 3.5 c 128,-1,24
+ 333 0 333 0 313 0 c 0,25,26
+ 285 0 285 0 258 6 c 128,-1,27
+ 231 12 231 12 207 22 c 128,-1,28
+ 183 32 183 32 161 47 c 128,-1,29
+ 139 62 139 62 120.5 81 c 128,-1,30
+ 102 100 102 100 86.5 122 c 128,-1,31
+ 71 144 71 144 61 168.5 c 128,-1,32
+ 51 193 51 193 45 219.5 c 128,-1,33
+ 39 246 39 246 39 274 c 0,34,35
+ 39 301 39 301 45 328 c 128,-1,36
+ 51 355 51 355 61 379.5 c 128,-1,37
+ 71 404 71 404 86.5 426 c 128,-1,38
+ 102 448 102 448 120.5 467 c 128,-1,39
+ 139 486 139 486 161 501 c 128,-1,40
+ 183 516 183 516 207 526.5 c 128,-1,41
+ 231 537 231 537 258 542.5 c 128,-1,42
+ 285 548 285 548 313 548 c 0,43,44
+ 333 548 333 548 353.5 544.5 c 128,-1,45
+ 374 541 374 541 394.5 534 c 128,-1,46
+ 415 527 415 527 433.5 518 c 128,-1,47
+ 452 509 452 509 469 497 c 1,48,-1
+ 469 544 l 1,49,-1
+ 587 544 l 1,50,-1
+ 587 0 l 1,51,-1
+ 469 0 l 1,52,-1
+ 469 52 l 1,20,21
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: b
+Encoding: 98 98 3
+Width: 640
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+322 120 m 0,0,1
+ 354 120 354 120 382 132.5 c 128,-1,2
+ 410 145 410 145 431 166 c 128,-1,3
+ 452 187 452 187 464.5 214.5 c 128,-1,4
+ 477 242 477 242 477 274 c 0,5,6
+ 477 305 477 305 464.5 333.5 c 128,-1,7
+ 452 362 452 362 431 382.5 c 128,-1,8
+ 410 403 410 403 382 415.5 c 128,-1,9
+ 354 428 354 428 322 428 c 0,10,11
+ 291 428 291 428 262.5 415.5 c 128,-1,12
+ 234 403 234 403 213 382.5 c 128,-1,13
+ 192 362 192 362 180.5 334 c 128,-1,14
+ 169 306 169 306 169 274 c 0,15,16
+ 169 242 169 242 180.5 214.5 c 128,-1,17
+ 192 187 192 187 213 166 c 128,-1,18
+ 234 145 234 145 262.5 132.5 c 128,-1,19
+ 291 120 291 120 322 120 c 0,0,1
+166 52 m 1,20,-1
+ 166 2 l 1,21,-1
+ 48 2 l 1,22,-1
+ 46 742 l 1,23,-1
+ 166 744 l 1,24,-1
+ 166 497 l 1,25,26
+ 183 509 183 509 202 518 c 128,-1,27
+ 221 527 221 527 241 534 c 128,-1,28
+ 261 541 261 541 282 544.5 c 128,-1,29
+ 303 548 303 548 322 548 c 0,30,31
+ 350 548 350 548 376.5 542.5 c 128,-1,32
+ 403 537 403 537 428 526.5 c 128,-1,33
+ 453 516 453 516 475 501 c 128,-1,34
+ 497 486 497 486 515.5 467 c 128,-1,35
+ 534 448 534 448 549 426 c 128,-1,36
+ 564 404 564 404 574.5 379.5 c 128,-1,37
+ 585 355 585 355 591 328.5 c 128,-1,38
+ 597 302 597 302 597 274 c 0,39,40
+ 597 246 597 246 591 219.5 c 128,-1,41
+ 585 193 585 193 574.5 168.5 c 128,-1,42
+ 564 144 564 144 549 122 c 128,-1,43
+ 534 100 534 100 515.5 81 c 128,-1,44
+ 497 62 497 62 475 47 c 128,-1,45
+ 453 32 453 32 428 22 c 128,-1,46
+ 403 12 403 12 377 6 c 128,-1,47
+ 351 0 351 0 322 0 c 0,48,49
+ 302 0 302 0 281.5 3.5 c 128,-1,50
+ 261 7 261 7 241 14 c 128,-1,51
+ 221 21 221 21 202 30.5 c 128,-1,52
+ 183 40 183 40 166 52 c 1,20,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: c
+Encoding: 99 99 4
+Width: 586
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+550 411 m 1,0,-1
+ 446 351 l 1,1,2
+ 435 369 435 369 421 383 c 128,-1,3
+ 407 397 407 397 390 407 c 128,-1,4
+ 373 417 373 417 353 422 c 0,5,6
+ 332 428 332 428 312 428 c 0,7,8
+ 281 428 281 428 253 416 c 128,-1,9
+ 225 404 225 404 204 383 c 128,-1,10
+ 183 362 183 362 170.5 334 c 128,-1,11
+ 158 306 158 306 158 273 c 0,12,13
+ 158 242 158 242 170.5 214 c 128,-1,14
+ 183 186 183 186 204 165 c 128,-1,15
+ 225 144 225 144 253 132 c 0,16,17
+ 280 119 280 119 312 119 c 0,18,19
+ 333 119 333 119 353 124.5 c 128,-1,20
+ 373 130 373 130 390 140 c 128,-1,21
+ 407 150 407 150 422 165 c 128,-1,22
+ 437 180 437 180 446 197 c 1,23,-1
+ 549 137 l 1,24,25
+ 531 106 531 106 505.5 80.5 c 128,-1,26
+ 480 55 480 55 449.5 37.5 c 128,-1,27
+ 419 20 419 20 384.5 10 c 128,-1,28
+ 350 0 350 0 312 0 c 0,29,30
+ 284 0 284 0 257.5 5.5 c 128,-1,31
+ 231 11 231 11 206.5 21.5 c 128,-1,32
+ 182 32 182 32 160 47 c 128,-1,33
+ 138 62 138 62 119.5 80.5 c 128,-1,34
+ 101 99 101 99 86 121 c 128,-1,35
+ 71 143 71 143 60.5 167.5 c 128,-1,36
+ 50 192 50 192 44.5 218.5 c 128,-1,37
+ 39 245 39 245 39 273 c 256,38,39
+ 39 301 39 301 44.5 328 c 128,-1,40
+ 50 355 50 355 60.5 380 c 128,-1,41
+ 71 405 71 405 86 426.5 c 128,-1,42
+ 101 448 101 448 119.5 467 c 128,-1,43
+ 138 486 138 486 160 501 c 128,-1,44
+ 182 516 182 516 206.5 526 c 128,-1,45
+ 231 536 231 536 257.5 542 c 128,-1,46
+ 284 548 284 548 312 548 c 0,47,48
+ 349 548 349 548 384 538 c 128,-1,49
+ 419 528 419 528 449.5 510.5 c 128,-1,50
+ 480 493 480 493 506 467.5 c 128,-1,51
+ 532 442 532 442 550 411 c 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: d
+Encoding: 100 100 5
+Width: 637
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+313 120 m 0,0,1
+ 344 120 344 120 372.5 132.5 c 128,-1,2
+ 401 145 401 145 421.5 166 c 128,-1,3
+ 442 187 442 187 454.5 214.5 c 128,-1,4
+ 467 242 467 242 467 274 c 0,5,6
+ 467 305 467 305 454.5 333.5 c 128,-1,7
+ 442 362 442 362 421.5 382.5 c 128,-1,8
+ 401 403 401 403 373 415.5 c 128,-1,9
+ 345 428 345 428 313 428 c 0,10,11
+ 281 428 281 428 253.5 415.5 c 128,-1,12
+ 226 403 226 403 205 382.5 c 128,-1,13
+ 184 362 184 362 171.5 334 c 128,-1,14
+ 159 306 159 306 159 274 c 0,15,16
+ 159 242 159 242 171.5 214.5 c 128,-1,17
+ 184 187 184 187 205 166 c 128,-1,18
+ 226 145 226 145 253.5 132.5 c 128,-1,19
+ 281 120 281 120 313 120 c 0,0,1
+469 52 m 1,20,21
+ 452 40 452 40 433.5 30.5 c 128,-1,22
+ 415 21 415 21 394.5 14 c 128,-1,23
+ 374 7 374 7 353.5 3.5 c 128,-1,24
+ 333 0 333 0 313 0 c 0,25,26
+ 285 0 285 0 258 6 c 128,-1,27
+ 231 12 231 12 207 22 c 128,-1,28
+ 183 32 183 32 161 47 c 128,-1,29
+ 139 62 139 62 120.5 81 c 128,-1,30
+ 102 100 102 100 86.5 122 c 128,-1,31
+ 71 144 71 144 61 168.5 c 128,-1,32
+ 51 193 51 193 45 219.5 c 128,-1,33
+ 39 246 39 246 39 274 c 0,34,35
+ 39 301 39 301 45 328 c 128,-1,36
+ 51 355 51 355 61 379.5 c 128,-1,37
+ 71 404 71 404 86.5 426 c 128,-1,38
+ 102 448 102 448 120.5 467 c 128,-1,39
+ 139 486 139 486 161 501 c 128,-1,40
+ 183 516 183 516 207 526.5 c 128,-1,41
+ 231 537 231 537 258 542.5 c 128,-1,42
+ 285 548 285 548 313 548 c 0,43,44
+ 333 548 333 548 353.5 544.5 c 128,-1,45
+ 374 541 374 541 394.5 534 c 128,-1,46
+ 415 527 415 527 433.5 518 c 128,-1,47
+ 452 509 452 509 469 497 c 1,48,-1
+ 469 744 l 1,49,-1
+ 587 744 l 1,50,-1
+ 587 2 l 1,51,-1
+ 469 2 l 1,52,-1
+ 469 52 l 1,20,21
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: e
+Encoding: 101 101 6
+Width: 630
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+453 332 m 1,0,1
+ 445 353 445 353 430.5 370.5 c 128,-1,2
+ 416 388 416 388 397.5 400.5 c 128,-1,3
+ 379 413 379 413 357.5 420.5 c 128,-1,4
+ 336 428 336 428 313 428 c 0,5,6
+ 290 428 290 428 268 421 c 128,-1,7
+ 246 414 246 414 228 401.5 c 128,-1,8
+ 210 389 210 389 196 371.5 c 128,-1,9
+ 182 354 182 354 173 332 c 1,10,-1
+ 453 332 l 1,0,1
+175 214 m 1,11,12
+ 183 193 183 193 197 175.5 c 128,-1,13
+ 211 158 211 158 229 146 c 128,-1,14
+ 247 134 247 134 269 127 c 128,-1,15
+ 291 120 291 120 313 120 c 0,16,17
+ 332 120 332 120 351 125.5 c 128,-1,18
+ 370 131 370 131 387 141 c 128,-1,19
+ 404 151 404 151 418.5 165.5 c 128,-1,20
+ 433 180 433 180 442 198 c 1,21,-1
+ 552 138 l 1,22,23
+ 532 108 532 108 505.5 82.5 c 128,-1,24
+ 479 57 479 57 448.5 38.5 c 128,-1,25
+ 418 20 418 20 383.5 10 c 128,-1,26
+ 349 0 349 0 313 0 c 0,27,28
+ 285 0 285 0 258 6 c 128,-1,29
+ 231 12 231 12 207 22 c 128,-1,30
+ 183 32 183 32 161 47 c 128,-1,31
+ 139 62 139 62 120.5 81 c 128,-1,32
+ 102 100 102 100 86.5 122 c 128,-1,33
+ 71 144 71 144 61 168 c 128,-1,34
+ 51 192 51 192 45 219 c 128,-1,35
+ 39 246 39 246 39 273 c 0,36,37
+ 39 301 39 301 45 328 c 128,-1,38
+ 51 355 51 355 61 379.5 c 128,-1,39
+ 71 404 71 404 86.5 426 c 128,-1,40
+ 102 448 102 448 120.5 466.5 c 128,-1,41
+ 139 485 139 485 161 500.5 c 128,-1,42
+ 183 516 183 516 207 526 c 128,-1,43
+ 231 536 231 536 258 542 c 128,-1,44
+ 285 548 285 548 313 548 c 0,45,46
+ 340 548 340 548 367.5 542 c 128,-1,47
+ 395 536 395 536 419 526 c 128,-1,48
+ 443 516 443 516 465 500.5 c 128,-1,49
+ 487 485 487 485 505.5 466.5 c 128,-1,50
+ 524 448 524 448 539.5 426 c 128,-1,51
+ 555 404 555 404 565.5 379.5 c 128,-1,52
+ 576 355 576 355 581.5 328.5 c 128,-1,53
+ 587 302 587 302 587 273 c 0,54,55
+ 587 258 587 258 584 243 c 128,-1,56
+ 581 228 581 228 578 214 c 1,57,-1
+ 175 214 l 1,11,12
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: g
+Encoding: 103 103 7
+Width: 637
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+159 273 m 0,0,1
+ 159 242 159 242 171.5 214.5 c 128,-1,2
+ 184 187 184 187 205 166 c 128,-1,3
+ 226 145 226 145 253.5 132.5 c 128,-1,4
+ 281 120 281 120 313 120 c 0,5,6
+ 344 120 344 120 372.5 132.5 c 128,-1,7
+ 401 145 401 145 422 166 c 0,8,9
+ 444 188 444 188 456 214 c 128,-1,10
+ 468 240 468 240 468 269 c 0,11,12
+ 468 271 468 271 468 273 c 0,13,14
+ 468 305 468 305 455.5 333 c 128,-1,15
+ 443 361 443 361 422 382 c 128,-1,16
+ 401 403 401 403 373 415.5 c 128,-1,17
+ 345 428 345 428 313 428 c 128,-1,18
+ 281 428 281 428 253.5 415.5 c 128,-1,19
+ 226 403 226 403 205 382 c 128,-1,20
+ 184 361 184 361 171.5 333 c 128,-1,21
+ 159 305 159 305 159 273 c 0,0,1
+39 274 m 256,22,23
+ 39 302 39 302 45 328.5 c 128,-1,24
+ 51 355 51 355 61 379.5 c 128,-1,25
+ 71 404 71 404 86.5 426 c 128,-1,26
+ 102 448 102 448 120.5 467 c 128,-1,27
+ 139 486 139 486 161 501 c 128,-1,28
+ 183 516 183 516 207 526.5 c 128,-1,29
+ 231 537 231 537 258 542.5 c 128,-1,30
+ 285 548 285 548 313 548 c 0,31,32
+ 333 548 333 548 353.5 544.5 c 128,-1,33
+ 374 541 374 541 394.5 534 c 128,-1,34
+ 415 527 415 527 433.5 518 c 128,-1,35
+ 452 509 452 509 469 497 c 1,36,-1
+ 469 544 l 1,37,-1
+ 587 544 l 1,38,-1
+ 587 72 l 2,39,40
+ 587 44 587 44 581.5 18 c 128,-1,41
+ 576 -8 576 -8 566 -32.5 c 128,-1,42
+ 556 -57 556 -57 540.5 -79 c 128,-1,43
+ 525 -101 525 -101 506.5 -119.5 c 128,-1,44
+ 488 -138 488 -138 466 -153 c 128,-1,45
+ 444 -168 444 -168 420 -178 c 128,-1,46
+ 396 -188 396 -188 369 -194 c 128,-1,47
+ 342 -200 342 -200 313 -200 c 0,48,49
+ 267 -200 267 -200 225 -185 c 128,-1,50
+ 183 -170 183 -170 147.5 -143.5 c 128,-1,51
+ 112 -117 112 -117 87 -80 c 128,-1,52
+ 62 -43 62 -43 50 0 c 1,53,-1
+ 177 0 l 1,54,55
+ 188 -18 188 -18 202 -33 c 128,-1,56
+ 216 -48 216 -48 234 -58.5 c 128,-1,57
+ 252 -69 252 -69 272 -75 c 128,-1,58
+ 292 -81 292 -81 313 -81 c 0,59,60
+ 341 -81 341 -81 367.5 -71 c 128,-1,61
+ 394 -61 394 -61 414.5 -42.5 c 128,-1,62
+ 435 -24 435 -24 448.5 -0.5 c 128,-1,63
+ 462 23 462 23 466 51 c 1,64,65
+ 448 40 448 40 430 30.5 c 128,-1,66
+ 412 21 412 21 392.5 14.5 c 128,-1,67
+ 373 8 373 8 353 4 c 128,-1,68
+ 333 0 333 0 313 0 c 0,69,70
+ 285 0 285 0 258.5 6 c 128,-1,71
+ 232 12 232 12 207.5 22 c 128,-1,72
+ 183 32 183 32 161 47 c 128,-1,73
+ 139 62 139 62 120.5 81 c 128,-1,74
+ 102 100 102 100 86.5 122 c 128,-1,75
+ 71 144 71 144 61 168.5 c 128,-1,76
+ 51 193 51 193 45 219.5 c 128,-1,77
+ 39 246 39 246 39 274 c 256,22,23
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: h
+Encoding: 104 104 8
+Width: 641
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+594 274 m 2,0,-1
+ 594 0 l 1,1,-1
+ 475 0 l 1,2,-1
+ 475 276 l 2,3,4
+ 474 307 474 307 461.5 335 c 128,-1,5
+ 449 363 449 363 428.5 383.5 c 128,-1,6
+ 408 404 408 404 380 416 c 128,-1,7
+ 352 428 352 428 320 428 c 0,8,9
+ 304 428 304 428 289 424.5 c 128,-1,10
+ 274 421 274 421 260 414 c 128,-1,11
+ 246 407 246 407 233.5 398.5 c 128,-1,12
+ 221 390 221 390 210 378.5 c 128,-1,13
+ 199 367 199 367 191 355 c 128,-1,14
+ 183 343 183 343 177 329 c 128,-1,15
+ 171 315 171 315 167.5 301.5 c 128,-1,16
+ 164 288 164 288 164 274 c 2,17,-1
+ 164 2 l 1,18,-1
+ 46 2 l 1,19,-1
+ 46 744 l 1,20,-1
+ 164 744 l 1,21,-1
+ 164 497 l 1,22,23
+ 181 509 181 509 200 518 c 128,-1,24
+ 219 527 219 527 239 534 c 128,-1,25
+ 259 541 259 541 279.5 544.5 c 128,-1,26
+ 300 548 300 548 320 548 c 0,27,28
+ 348 548 348 548 374.5 542.5 c 128,-1,29
+ 401 537 401 537 425.5 526.5 c 128,-1,30
+ 450 516 450 516 472 500.5 c 128,-1,31
+ 494 485 494 485 513 466.5 c 128,-1,32
+ 532 448 532 448 547 426 c 128,-1,33
+ 562 404 562 404 572.5 379.5 c 128,-1,34
+ 583 355 583 355 588.5 328 c 128,-1,35
+ 594 301 594 301 594 274 c 2,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: i
+Encoding: 105 105 9
+Width: 214
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+105 744 m 0,0,1
+ 117 744 117 744 128 739.5 c 128,-1,2
+ 139 735 139 735 147 727 c 128,-1,3
+ 155 719 155 719 159.5 708 c 128,-1,4
+ 164 697 164 697 164 686 c 0,5,6
+ 164 673 164 673 159.5 662 c 128,-1,7
+ 155 651 155 651 147 643 c 128,-1,8
+ 139 635 139 635 128 630.5 c 128,-1,9
+ 117 626 117 626 105 626 c 0,10,11
+ 92 626 92 626 81.5 630.5 c 128,-1,12
+ 71 635 71 635 63.5 643 c 128,-1,13
+ 56 651 56 651 51 662 c 128,-1,14
+ 46 673 46 673 46 686 c 0,15,16
+ 46 698 46 698 51 708.5 c 128,-1,17
+ 56 719 56 719 63.5 727 c 128,-1,18
+ 71 735 71 735 81.5 739.5 c 128,-1,19
+ 92 744 92 744 105 744 c 0,0,1
+46 549 m 1,20,-1
+ 164 549 l 1,21,-1
+ 164 0 l 1,22,-1
+ 46 0 l 1,23,-1
+ 46 549 l 1,20,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: k
+Encoding: 107 107 10
+Width: 539
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+499 0 m 1,0,1
+ 494 0 l 0,2,3
+ 488 0 488 0 480 0 c 128,-1,4
+ 472 0 472 0 460.5 0 c 128,-1,5
+ 449 0 449 0 438 0 c 128,-1,6
+ 427 0 427 0 416 0 c 128,-1,7
+ 405 0 405 0 396.5 0 c 128,-1,8
+ 388 0 388 0 383 0 c 0,9,-1
+ 378 0 l 1,10,11
+ 378 22 378 22 373.5 42.5 c 128,-1,12
+ 369 63 369 63 361 83 c 128,-1,13
+ 353 103 353 103 341 120 c 128,-1,14
+ 329 137 329 137 315 151 c 128,-1,15
+ 301 165 301 165 284 176.5 c 128,-1,16
+ 267 188 267 188 247.5 196.5 c 128,-1,17
+ 228 205 228 205 207.5 209.5 c 128,-1,18
+ 187 214 187 214 164 214 c 1,19,-1
+ 164 0 l 1,20,-1
+ 46 0 l 1,21,-1
+ 46 745 l 1,22,-1
+ 164 745 l 1,23,-1
+ 164 334 l 1,24,25
+ 186 334 186 334 207 338.5 c 128,-1,26
+ 228 343 228 343 247 351 c 128,-1,27
+ 266 359 266 359 283 370.5 c 128,-1,28
+ 300 382 300 382 314.5 396.5 c 128,-1,29
+ 329 411 329 411 340.5 428 c 128,-1,30
+ 352 445 352 445 360 464 c 128,-1,31
+ 368 483 368 483 372.5 504 c 128,-1,32
+ 377 525 377 525 377 547 c 1,33,-1
+ 497 547 l 1,34,35
+ 497 507 497 507 487.5 468 c 128,-1,36
+ 478 429 478 429 459.5 393.5 c 128,-1,37
+ 441 358 441 358 415.5 328 c 128,-1,38
+ 390 298 390 298 356 274 c 1,39,40
+ 389 252 389 252 415.5 221 c 128,-1,41
+ 442 190 442 190 460.5 154.5 c 128,-1,42
+ 479 119 479 119 489 80 c 128,-1,43
+ 499 41 499 41 499 0 c 1,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: l
+Encoding: 108 108 11
+Width: 214
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+46 744 m 1,0,-1
+ 164 744 l 1,1,-1
+ 164 0 l 1,2,-1
+ 46 0 l 1,3,-1
+ 46 744 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: m
+Encoding: 109 109 12
+Width: 1070
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+1022 274 m 2,0,-1
+ 1022 0 l 1,1,-1
+ 902 0 l 1,2,-1
+ 902 276 l 2,3,4
+ 902 307 902 307 890 335 c 128,-1,5
+ 878 363 878 363 857 383.5 c 128,-1,6
+ 836 404 836 404 808 416 c 128,-1,7
+ 780 428 780 428 748 428 c 0,8,9
+ 732 428 732 428 717 424.5 c 128,-1,10
+ 702 421 702 421 688 414.5 c 128,-1,11
+ 674 408 674 408 661.5 399 c 128,-1,12
+ 649 390 649 390 638.5 379 c 128,-1,13
+ 628 368 628 368 619 355.5 c 128,-1,14
+ 610 343 610 343 604.5 329 c 128,-1,15
+ 599 315 599 315 596 301.5 c 128,-1,16
+ 593 288 593 288 593 274 c 2,17,-1
+ 593 2 l 1,18,-1
+ 475 3 l 1,19,-1
+ 475 279 l 2,20,21
+ 474 311 474 311 461.5 338.5 c 128,-1,22
+ 449 366 449 366 428.5 386.5 c 128,-1,23
+ 408 407 408 407 380 419.5 c 128,-1,24
+ 352 432 352 432 320 432 c 0,25,26
+ 304 432 304 432 289 428 c 128,-1,27
+ 274 424 274 424 260 417.5 c 128,-1,28
+ 246 411 246 411 233.5 402 c 128,-1,29
+ 221 393 221 393 210 382 c 128,-1,30
+ 199 371 199 371 191 358.5 c 128,-1,31
+ 183 346 183 346 177 332.5 c 128,-1,32
+ 171 319 171 319 167.5 305 c 128,-1,33
+ 164 291 164 291 164 277 c 2,34,-1
+ 164 6 l 1,35,-1
+ 46 6 l 1,36,-1
+ 46 547 l 1,37,-1
+ 164 547 l 1,38,-1
+ 164 500 l 1,39,40
+ 181 512 181 512 200 521.5 c 128,-1,41
+ 219 531 219 531 239 537.5 c 128,-1,42
+ 259 544 259 544 279.5 548 c 128,-1,43
+ 300 552 300 552 320 552 c 0,44,45
+ 352 552 352 552 383 544 c 128,-1,46
+ 414 536 414 536 441.5 522.5 c 128,-1,47
+ 469 509 469 509 492.5 489.5 c 128,-1,48
+ 516 470 516 470 534 445 c 1,49,50
+ 554 469 554 469 578.5 488.5 c 128,-1,51
+ 603 508 603 508 630 521 c 128,-1,52
+ 657 534 657 534 687.5 541 c 128,-1,53
+ 718 548 718 548 748 548 c 0,54,55
+ 776 548 776 548 803 542.5 c 128,-1,56
+ 830 537 830 537 855 527 c 128,-1,57
+ 880 517 880 517 902 501.5 c 128,-1,58
+ 924 486 924 486 942.5 467.5 c 128,-1,59
+ 961 449 961 449 975.5 427 c 128,-1,60
+ 990 405 990 405 1000.5 380.5 c 128,-1,61
+ 1011 356 1011 356 1016.5 329 c 128,-1,62
+ 1022 302 1022 302 1022 274 c 2,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: n
+Encoding: 110 110 13
+Width: 641
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+594 274 m 2,0,-1
+ 594 0 l 1,1,-1
+ 475 0 l 1,2,-1
+ 475 276 l 2,3,4
+ 474 307 474 307 461.5 335 c 128,-1,5
+ 449 363 449 363 428.5 383.5 c 128,-1,6
+ 408 404 408 404 380 416 c 128,-1,7
+ 352 428 352 428 320 428 c 0,8,9
+ 304 428 304 428 289 424.5 c 128,-1,10
+ 274 421 274 421 260 414 c 128,-1,11
+ 246 407 246 407 233.5 398.5 c 128,-1,12
+ 221 390 221 390 210 378.5 c 128,-1,13
+ 199 367 199 367 191 355 c 128,-1,14
+ 183 343 183 343 177 329 c 128,-1,15
+ 171 315 171 315 167.5 301.5 c 128,-1,16
+ 164 288 164 288 164 274 c 2,17,-1
+ 164 2 l 1,18,-1
+ 46 2 l 1,19,-1
+ 46 544 l 1,20,-1
+ 164 544 l 1,21,-1
+ 164 497 l 1,22,23
+ 181 509 181 509 200 518 c 128,-1,24
+ 219 527 219 527 239 534 c 128,-1,25
+ 259 541 259 541 279.5 544.5 c 128,-1,26
+ 300 548 300 548 320 548 c 0,27,28
+ 348 548 348 548 374.5 542.5 c 128,-1,29
+ 401 537 401 537 425.5 526.5 c 128,-1,30
+ 450 516 450 516 472 500.5 c 128,-1,31
+ 494 485 494 485 513 466.5 c 128,-1,32
+ 532 448 532 448 547 426 c 128,-1,33
+ 562 404 562 404 572.5 379.5 c 128,-1,34
+ 583 355 583 355 588.5 328 c 128,-1,35
+ 594 301 594 301 594 274 c 2,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: o
+Encoding: 111 111 14
+Width: 631
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+312 0 m 256,0,1
+ 284 0 284 0 257.5 5.5 c 128,-1,2
+ 231 11 231 11 206.5 21.5 c 128,-1,3
+ 182 32 182 32 160 47 c 128,-1,4
+ 138 62 138 62 119.5 80.5 c 128,-1,5
+ 101 99 101 99 86 121 c 128,-1,6
+ 71 143 71 143 60.5 167.5 c 128,-1,7
+ 50 192 50 192 44.5 218.5 c 128,-1,8
+ 39 245 39 245 39 273 c 256,9,10
+ 39 301 39 301 44.5 328 c 128,-1,11
+ 50 355 50 355 60.5 380 c 128,-1,12
+ 71 405 71 405 86 426.5 c 128,-1,13
+ 101 448 101 448 119.5 467 c 128,-1,14
+ 138 486 138 486 160 501 c 128,-1,15
+ 182 516 182 516 206.5 526 c 128,-1,16
+ 231 536 231 536 257.5 542 c 128,-1,17
+ 284 548 284 548 312 548 c 256,18,19
+ 340 548 340 548 367.5 542 c 128,-1,20
+ 395 536 395 536 419.5 526 c 128,-1,21
+ 444 516 444 516 465.5 501 c 128,-1,22
+ 487 486 487 486 506 467 c 128,-1,23
+ 525 448 525 448 540 426.5 c 128,-1,24
+ 555 405 555 405 565 380 c 128,-1,25
+ 575 355 575 355 581 328.5 c 128,-1,26
+ 587 302 587 302 587 273 c 256,27,28
+ 587 245 587 245 581 218.5 c 128,-1,29
+ 575 192 575 192 565 167.5 c 128,-1,30
+ 555 143 555 143 540 121 c 128,-1,31
+ 525 99 525 99 506 80.5 c 128,-1,32
+ 487 62 487 62 465.5 47 c 128,-1,33
+ 444 32 444 32 419.5 21.5 c 128,-1,34
+ 395 11 395 11 367.5 5.5 c 128,-1,35
+ 340 0 340 0 312 0 c 256,0,1
+312 119 m 0,36,37
+ 344 119 344 119 372.5 131.5 c 128,-1,38
+ 401 144 401 144 422 165 c 128,-1,39
+ 443 186 443 186 455.5 214 c 128,-1,40
+ 468 242 468 242 468 273 c 0,41,42
+ 468 305 468 305 455.5 333.5 c 128,-1,43
+ 443 362 443 362 422 383 c 128,-1,44
+ 401 404 401 404 373 416 c 0,45,46
+ 344 429 344 429 312 429 c 0,47,48
+ 281 429 281 429 253 416.5 c 128,-1,49
+ 225 404 225 404 204 383 c 128,-1,50
+ 183 362 183 362 170.5 334 c 128,-1,51
+ 158 306 158 306 158 273 c 0,52,53
+ 158 242 158 242 170.5 214 c 128,-1,54
+ 183 186 183 186 204 165 c 128,-1,55
+ 225 144 225 144 253 131.5 c 128,-1,56
+ 281 119 281 119 312 119 c 0,36,37
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: p
+Encoding: 112 112 15
+Width: 641
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+322 428 m 0,0,1
+ 291 428 291 428 262.5 415.5 c 128,-1,2
+ 234 403 234 403 213 382 c 128,-1,3
+ 192 361 192 361 180.5 333.5 c 128,-1,4
+ 169 306 169 306 169 274 c 0,5,6
+ 169 242 169 242 180.5 214.5 c 128,-1,7
+ 192 187 192 187 213 166 c 128,-1,8
+ 234 145 234 145 262.5 132.5 c 128,-1,9
+ 291 120 291 120 322 120 c 0,10,11
+ 354 120 354 120 382 132.5 c 128,-1,12
+ 410 145 410 145 431 166 c 128,-1,13
+ 452 187 452 187 464.5 214.5 c 128,-1,14
+ 477 242 477 242 477 274 c 0,15,16
+ 477 305 477 305 464.5 333 c 128,-1,17
+ 452 361 452 361 431 382 c 128,-1,18
+ 410 403 410 403 382 415.5 c 128,-1,19
+ 354 428 354 428 322 428 c 0,0,1
+166 497 m 1,20,21
+ 183 509 183 509 202 518 c 128,-1,22
+ 221 527 221 527 241 534 c 128,-1,23
+ 261 541 261 541 282 544.5 c 128,-1,24
+ 303 548 303 548 322 548 c 0,25,26
+ 350 548 350 548 376.5 542.5 c 128,-1,27
+ 403 537 403 537 428 526.5 c 128,-1,28
+ 453 516 453 516 475 500.5 c 128,-1,29
+ 497 485 497 485 515.5 466.5 c 128,-1,30
+ 534 448 534 448 549 426 c 128,-1,31
+ 564 404 564 404 574.5 379.5 c 128,-1,32
+ 585 355 585 355 591 328.5 c 128,-1,33
+ 597 302 597 302 597 274 c 0,34,35
+ 597 246 597 246 591 219 c 128,-1,36
+ 585 192 585 192 574.5 168 c 128,-1,37
+ 564 144 564 144 549 122 c 128,-1,38
+ 534 100 534 100 515.5 81 c 128,-1,39
+ 497 62 497 62 475 47 c 128,-1,40
+ 453 32 453 32 428 21.5 c 128,-1,41
+ 403 11 403 11 377 5.5 c 128,-1,42
+ 351 0 351 0 322 0 c 0,43,44
+ 302 0 302 0 281.5 3.5 c 128,-1,45
+ 261 7 261 7 241 14 c 128,-1,46
+ 221 21 221 21 202 30 c 128,-1,47
+ 183 39 183 39 166 51 c 1,48,-1
+ 166 -195 l 1,49,-1
+ 46 -195 l 1,50,-1
+ 46 546 l 1,51,-1
+ 166 546 l 1,52,-1
+ 166 497 l 1,20,21
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: q
+Encoding: 113 113 16
+Width: 641
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+313 428 m 0,0,1
+ 281 428 281 428 253.5 415.5 c 128,-1,2
+ 226 403 226 403 205 382 c 128,-1,3
+ 184 361 184 361 171.5 333.5 c 128,-1,4
+ 159 306 159 306 159 274 c 0,5,6
+ 159 242 159 242 171.5 214.5 c 128,-1,7
+ 184 187 184 187 205 166 c 128,-1,8
+ 226 145 226 145 253.5 132.5 c 128,-1,9
+ 281 120 281 120 313 120 c 0,10,11
+ 344 120 344 120 372.5 132.5 c 128,-1,12
+ 401 145 401 145 421.5 166 c 128,-1,13
+ 442 187 442 187 454.5 214.5 c 128,-1,14
+ 467 242 467 242 467 274 c 0,15,16
+ 467 305 467 305 454.5 333 c 128,-1,17
+ 442 361 442 361 421.5 382 c 128,-1,18
+ 401 403 401 403 372.5 415.5 c 128,-1,19
+ 344 428 344 428 313 428 c 0,0,1
+469 497 m 1,20,-1
+ 469 546 l 1,21,-1
+ 590 546 l 1,22,-1
+ 590 -195 l 1,23,-1
+ 469 -195 l 1,24,-1
+ 469 51 l 1,25,26
+ 452 39 452 39 433.5 30 c 128,-1,27
+ 415 21 415 21 394.5 14 c 128,-1,28
+ 374 7 374 7 353.5 3.5 c 128,-1,29
+ 333 0 333 0 313 0 c 0,30,31
+ 285 0 285 0 258 5.5 c 128,-1,32
+ 231 11 231 11 207 21.5 c 128,-1,33
+ 183 32 183 32 161 47 c 128,-1,34
+ 139 62 139 62 120.5 81 c 128,-1,35
+ 102 100 102 100 86.5 122 c 128,-1,36
+ 71 144 71 144 61 168 c 128,-1,37
+ 51 192 51 192 45 219 c 128,-1,38
+ 39 246 39 246 39 274 c 0,39,40
+ 39 301 39 301 45 328 c 128,-1,41
+ 51 355 51 355 61 379.5 c 128,-1,42
+ 71 404 71 404 86.5 426 c 128,-1,43
+ 102 448 102 448 120.5 466.5 c 128,-1,44
+ 139 485 139 485 161 500.5 c 128,-1,45
+ 183 516 183 516 207 526.5 c 128,-1,46
+ 231 537 231 537 258 542.5 c 128,-1,47
+ 285 548 285 548 313 548 c 0,48,49
+ 333 548 333 548 353.5 544.5 c 128,-1,50
+ 374 541 374 541 394.5 534 c 128,-1,51
+ 415 527 415 527 433.5 518 c 128,-1,52
+ 452 509 452 509 469 497 c 1,20,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: r
+Encoding: 114 114 17
+Width: 511
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+407 399 m 1,0,1
+ 388 411 388 411 366.5 418.5 c 128,-1,2
+ 345 426 345 426 320 426 c 0,3,4
+ 304 426 304 426 289 422 c 128,-1,5
+ 274 418 274 418 260 411.5 c 128,-1,6
+ 246 405 246 405 233.5 396.5 c 128,-1,7
+ 221 388 221 388 210 376.5 c 128,-1,8
+ 199 365 199 365 191 352.5 c 128,-1,9
+ 183 340 183 340 177 326.5 c 128,-1,10
+ 171 313 171 313 167.5 299.5 c 128,-1,11
+ 164 286 164 286 164 271 c 2,12,-1
+ 164 0 l 1,13,-1
+ 46 0 l 1,14,-1
+ 46 541 l 1,15,-1
+ 164 541 l 1,16,-1
+ 164 495 l 1,17,18
+ 181 507 181 507 200 516 c 128,-1,19
+ 219 525 219 525 239 532 c 128,-1,20
+ 259 539 259 539 279.5 542.5 c 128,-1,21
+ 300 546 300 546 320 546 c 0,22,23
+ 363 546 363 546 402.5 533 c 128,-1,24
+ 442 520 442 520 476 496 c 1,25,-1
+ 407 399 l 1,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: t
+Encoding: 116 116 18
+Width: 506
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+162 275 m 2,0,1
+ 163 244 163 244 175.5 216 c 128,-1,2
+ 188 188 188 188 208.5 166.5 c 128,-1,3
+ 229 145 229 145 257.5 132 c 128,-1,4
+ 286 119 286 119 317 119 c 0,5,6
+ 341 119 341 119 364 127 c 128,-1,7
+ 387 135 387 135 405 147 c 1,8,-1
+ 475 50 l 1,9,10
+ 441 27 441 27 400.5 13.5 c 128,-1,11
+ 360 0 360 0 317 0 c 0,12,13
+ 289 0 289 0 262.5 5.5 c 128,-1,14
+ 236 11 236 11 211.5 21.5 c 128,-1,15
+ 187 32 187 32 165 47 c 128,-1,16
+ 143 62 143 62 124 80.5 c 128,-1,17
+ 105 99 105 99 90.5 121 c 128,-1,18
+ 76 143 76 143 65.5 167.5 c 128,-1,19
+ 55 192 55 192 49.5 219 c 128,-1,20
+ 44 246 44 246 44 274 c 2,21,-1
+ 44 745 l 1,22,-1
+ 162 745 l 1,23,-1
+ 162 546 l 1,24,-1
+ 353 546 l 1,25,-1
+ 353 428 l 1,26,-1
+ 162 425 l 1,27,-1
+ 162 275 l 2,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: u
+Encoding: 117 117 19
+Width: 643
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+44 274 m 2,0,-1
+ 44 549 l 1,1,-1
+ 164 549 l 1,2,-1
+ 164 272 l 2,3,4
+ 164 240 164 240 176 212.5 c 128,-1,5
+ 188 185 188 185 209 164.5 c 128,-1,6
+ 230 144 230 144 258 132 c 128,-1,7
+ 286 120 286 120 318 120 c 0,8,9
+ 334 120 334 120 349 124 c 128,-1,10
+ 364 128 364 128 378.5 134.5 c 128,-1,11
+ 393 141 393 141 405 149.5 c 128,-1,12
+ 417 158 417 158 427.5 169.5 c 128,-1,13
+ 438 181 438 181 447 193.5 c 128,-1,14
+ 456 206 456 206 462 219 c 128,-1,15
+ 468 232 468 232 471.5 246.5 c 128,-1,16
+ 475 261 475 261 475 274 c 2,17,-1
+ 475 546 l 1,18,-1
+ 593 546 l 1,19,-1
+ 593 5 l 1,20,-1
+ 475 5 l 1,21,-1
+ 475 51 l 1,22,23
+ 457 39 457 39 438.5 30 c 128,-1,24
+ 420 21 420 21 399.5 14 c 128,-1,25
+ 379 7 379 7 358.5 3.5 c 128,-1,26
+ 338 0 338 0 318 0 c 0,27,28
+ 290 0 290 0 263 6 c 128,-1,29
+ 236 12 236 12 212 22 c 128,-1,30
+ 188 32 188 32 166 47 c 128,-1,31
+ 144 62 144 62 125 81 c 128,-1,32
+ 106 100 106 100 91 122 c 128,-1,33
+ 76 144 76 144 66 168.5 c 128,-1,34
+ 56 193 56 193 50 219.5 c 128,-1,35
+ 44 246 44 246 44 274 c 2,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: v
+Encoding: 118 118 20
+Width: 607
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+361 0 m 1,0,-1
+ 243 0 l 1,1,-1
+ 31 547 l 1,2,-1
+ 158 547 l 1,3,-1
+ 303 158 l 1,4,-1
+ 447 547 l 1,5,-1
+ 574 547 l 1,6,-1
+ 361 0 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: x
+Encoding: 120 120 21
+Width: 699
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+33 547 m 1,0,-1
+ 186 547 l 1,1,-1
+ 349 360 l 1,2,-1
+ 512 547 l 1,3,-1
+ 664 547 l 1,4,-1
+ 426 273 l 1,5,-1
+ 664 0 l 1,6,-1
+ 511 0 l 1,7,-1
+ 349 186 l 1,8,-1
+ 187 0 l 1,9,-1
+ 33 0 l 1,10,-1
+ 272 273 l 1,11,-1
+ 33 547 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: y
+Encoding: 121 121 22
+Width: 642
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+592 546 m 1,0,-1
+ 592 72 l 2,1,2
+ 592 44 592 44 586.5 18 c 128,-1,3
+ 581 -8 581 -8 571 -32.5 c 128,-1,4
+ 561 -57 561 -57 545.5 -79 c 128,-1,5
+ 530 -101 530 -101 511.5 -119.5 c 128,-1,6
+ 493 -138 493 -138 471 -153 c 128,-1,7
+ 449 -168 449 -168 424.5 -178 c 128,-1,8
+ 400 -188 400 -188 373.5 -194 c 128,-1,9
+ 347 -200 347 -200 318 -200 c 0,10,11
+ 272 -200 272 -200 230 -185 c 128,-1,12
+ 188 -170 188 -170 152.5 -143.5 c 128,-1,13
+ 117 -117 117 -117 91.5 -80 c 128,-1,14
+ 66 -43 66 -43 55 0 c 1,15,-1
+ 182 0 l 1,16,17
+ 193 -18 193 -18 207 -33 c 128,-1,18
+ 221 -48 221 -48 239 -58.5 c 128,-1,19
+ 257 -69 257 -69 277 -75 c 128,-1,20
+ 297 -81 297 -81 318 -81 c 0,21,22
+ 346 -81 346 -81 372 -71 c 128,-1,23
+ 398 -61 398 -61 418.5 -42.5 c 128,-1,24
+ 439 -24 439 -24 453 -0.5 c 128,-1,25
+ 467 23 467 23 471 51 c 1,26,27
+ 453 40 453 40 435 30.5 c 128,-1,28
+ 417 21 417 21 397.5 14.5 c 128,-1,29
+ 378 8 378 8 358 4 c 128,-1,30
+ 338 0 338 0 318 0 c 0,31,32
+ 290 0 290 0 263.5 6 c 128,-1,33
+ 237 12 237 12 212.5 22 c 128,-1,34
+ 188 32 188 32 166 47 c 128,-1,35
+ 144 62 144 62 125 81 c 128,-1,36
+ 106 100 106 100 91 122 c 128,-1,37
+ 76 144 76 144 66 168.5 c 128,-1,38
+ 56 193 56 193 50 219.5 c 128,-1,39
+ 44 246 44 246 44 274 c 2,40,-1
+ 44 549 l 1,41,-1
+ 164 549 l 1,42,-1
+ 164 273 l 2,43,44
+ 164 242 164 242 176 214.5 c 128,-1,45
+ 188 187 188 187 209 166 c 128,-1,46
+ 230 145 230 145 258 132.5 c 128,-1,47
+ 286 120 286 120 318 120 c 0,48,49
+ 349 120 349 120 377.5 132.5 c 128,-1,50
+ 406 145 406 145 427 166 c 128,-1,51
+ 448 187 448 187 461 214.5 c 128,-1,52
+ 474 242 474 242 474 274 c 2,53,-1
+ 474 546 l 1,54,-1
+ 592 546 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: z
+Encoding: 122 122 23
+Width: 632
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+222 118 m 1,0,-1
+ 587 118 l 1,1,-1
+ 587 0 l 1,2,-1
+ 43 0 l 1,3,-1
+ 43 118 l 1,4,-1
+ 401 430 l 1,5,-1
+ 43 430 l 1,6,-1
+ 43 548 l 1,7,-1
+ 587 548 l 1,8,-1
+ 587 430 l 1,9,-1
+ 222 118 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: R
+Encoding: 82 82 24
+Width: 593
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+454 349 m 1,0,1
+ 444 367 444 367 430 381 c 128,-1,2
+ 416 395 416 395 398.5 405 c 128,-1,3
+ 381 415 381 415 361.5 420.5 c 128,-1,4
+ 342 426 342 426 320 426 c 0,5,6
+ 304 426 304 426 289 422 c 128,-1,7
+ 274 418 274 418 260 411.5 c 128,-1,8
+ 246 405 246 405 233.5 396.5 c 128,-1,9
+ 221 388 221 388 210 376.5 c 128,-1,10
+ 199 365 199 365 191 352.5 c 128,-1,11
+ 183 340 183 340 177 326.5 c 128,-1,12
+ 171 313 171 313 167.5 299.5 c 128,-1,13
+ 164 286 164 286 164 271 c 2,14,-1
+ 164 0 l 1,15,-1
+ 46 0 l 1,16,-1
+ 46 541 l 1,17,-1
+ 164 541 l 1,18,-1
+ 164 495 l 1,19,20
+ 181 507 181 507 200 516 c 128,-1,21
+ 219 525 219 525 239 532 c 128,-1,22
+ 259 539 259 539 279.5 542.5 c 128,-1,23
+ 300 546 300 546 320 546 c 0,24,25
+ 357 546 357 546 392.5 535.5 c 128,-1,26
+ 428 525 428 525 458.5 507 c 128,-1,27
+ 489 489 489 489 514.5 463.5 c 128,-1,28
+ 540 438 540 438 558 407 c 1,29,-1
+ 454 349 l 1,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: T
+Encoding: 84 84 25
+Width: 586
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+162 275 m 2,0,1
+ 163 244 163 244 175.5 216 c 128,-1,2
+ 188 188 188 188 208.5 166.5 c 128,-1,3
+ 229 145 229 145 257.5 132 c 128,-1,4
+ 286 119 286 119 317 119 c 0,5,6
+ 338 119 338 119 358 124.5 c 128,-1,7
+ 378 130 378 130 395 140 c 128,-1,8
+ 412 150 412 150 426.5 165 c 128,-1,9
+ 441 180 441 180 451 197 c 1,10,-1
+ 554 137 l 1,11,12
+ 536 106 536 106 510.5 80.5 c 128,-1,13
+ 485 55 485 55 454.5 37.5 c 128,-1,14
+ 424 20 424 20 389 10 c 128,-1,15
+ 354 0 354 0 317 0 c 0,16,17
+ 289 0 289 0 262.5 5.5 c 128,-1,18
+ 236 11 236 11 211.5 21.5 c 128,-1,19
+ 187 32 187 32 165 47 c 128,-1,20
+ 143 62 143 62 124 80.5 c 128,-1,21
+ 105 99 105 99 90.5 121 c 128,-1,22
+ 76 143 76 143 65.5 167.5 c 128,-1,23
+ 55 192 55 192 49.5 219 c 128,-1,24
+ 44 246 44 246 44 274 c 2,25,-1
+ 44 745 l 1,26,-1
+ 162 745 l 1,27,-1
+ 162 546 l 1,28,-1
+ 353 546 l 1,29,-1
+ 353 428 l 1,30,-1
+ 162 425 l 1,31,-1
+ 162 275 l 2,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: s
+Encoding: 115 115 26
+Width: 539
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+328 317 m 0,0,1
+ 364 313 364 313 395.5 299 c 128,-1,2
+ 427 285 427 285 449.5 264 c 128,-1,3
+ 472 243 472 243 484.5 216.5 c 128,-1,4
+ 497 190 497 190 497 162 c 0,5,6
+ 497 144 497 144 492 128.5 c 128,-1,7
+ 487 113 487 113 478.5 98.5 c 128,-1,8
+ 470 84 470 84 457 71.5 c 128,-1,9
+ 444 59 444 59 428.5 47.5 c 128,-1,10
+ 413 36 413 36 394 27.5 c 128,-1,11
+ 375 19 375 19 354.5 13 c 128,-1,12
+ 334 7 334 7 311.5 3.5 c 128,-1,13
+ 289 0 289 0 266 0 c 0,14,15
+ 231 0 231 0 195.5 10 c 128,-1,16
+ 160 20 160 20 130 36.5 c 128,-1,17
+ 100 53 100 53 75.5 73.5 c 128,-1,18
+ 51 94 51 94 36 114 c 1,19,-1
+ 135 171 l 1,20,21
+ 142 161 142 161 156 149.5 c 128,-1,22
+ 170 138 170 138 187.5 127 c 128,-1,23
+ 205 116 205 116 225 109 c 128,-1,24
+ 245 102 245 102 264 102 c 0,25,26
+ 284 102 284 102 303.5 106.5 c 128,-1,27
+ 323 111 323 111 339 120 c 128,-1,28
+ 355 129 355 129 365.5 140 c 128,-1,29
+ 376 151 376 151 376 164 c 256,30,31
+ 376 177 376 177 365.5 187 c 128,-1,32
+ 355 197 355 197 334.5 205.5 c 128,-1,33
+ 314 214 314 214 282.5 220.5 c 128,-1,34
+ 251 227 251 227 206 231 c 0,35,36
+ 170 235 170 235 139 249.5 c 128,-1,37
+ 108 264 108 264 85.5 285 c 128,-1,38
+ 63 306 63 306 50.5 332 c 128,-1,39
+ 38 358 38 358 38 387 c 0,40,41
+ 38 404 38 404 43 420 c 128,-1,42
+ 48 436 48 436 56.5 450 c 128,-1,43
+ 65 464 65 464 78 477 c 128,-1,44
+ 91 490 91 490 107 501 c 128,-1,45
+ 123 512 123 512 141.5 520.5 c 128,-1,46
+ 160 529 160 529 180.5 535.5 c 128,-1,47
+ 201 542 201 542 223.5 545 c 128,-1,48
+ 246 548 246 548 270 548 c 0,49,50
+ 289 548 289 548 306 545.5 c 128,-1,51
+ 323 543 323 543 340.5 538.5 c 128,-1,52
+ 358 534 358 534 375 527.5 c 128,-1,53
+ 392 521 392 521 407.5 513.5 c 128,-1,54
+ 423 506 423 506 437 497 c 128,-1,55
+ 451 488 451 488 463.5 478 c 128,-1,56
+ 476 468 476 468 485.5 457.5 c 128,-1,57
+ 495 447 495 447 501 436 c 1,58,-1
+ 402 380 l 1,59,60
+ 395 389 395 389 381 400.5 c 128,-1,61
+ 367 412 367 412 349 422.5 c 128,-1,62
+ 331 433 331 433 311 440 c 128,-1,63
+ 291 447 291 447 272 447 c 0,64,65
+ 251 447 251 447 231.5 442.5 c 128,-1,66
+ 212 438 212 438 196 429 c 128,-1,67
+ 180 420 180 420 170 408.5 c 128,-1,68
+ 160 397 160 397 160 385 c 256,69,70
+ 160 372 160 372 170 362 c 128,-1,71
+ 180 352 180 352 200 343.5 c 128,-1,72
+ 220 335 220 335 252 329 c 128,-1,73
+ 284 323 284 323 328 317 c 0,0,1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: exclam
+Encoding: 33 33 27
+Width: 688
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+250 547 m 1,0,-1
+ 355 547 l 1,1,-1
+ 355 450 l 1,2,-1
+ 415 450 l 2,3,4
+ 441 451 441 451 464.5 459 c 128,-1,5
+ 488 467 488 467 505 480 c 128,-1,6
+ 522 493 522 493 532 510 c 128,-1,7
+ 542 527 542 527 542 547 c 1,8,-1
+ 641 547 l 1,9,-1
+ 641 0 l 1,10,-1
+ 510 0 l 1,11,-1
+ 510 356 l 1,12,-1
+ 355 356 l 1,13,-1
+ 355 0 l 1,14,-1
+ 225 0 l 1,15,-1
+ 225 356 l 1,16,-1
+ 39 356 l 1,17,-1
+ 39 450 l 1,18,-1
+ 125 450 l 2,19,20
+ 150 451 150 451 173 459.5 c 128,-1,21
+ 196 468 196 468 213 481 c 128,-1,22
+ 230 494 230 494 240 511 c 128,-1,23
+ 250 528 250 528 250 547 c 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: f
+Encoding: 102 102 28
+Width: 506
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+164 471 m 1,0,-1
+ 354 472 l 1,1,-1
+ 354 353 l 1,2,-1
+ 165 353 l 1,3,-1
+ 164 0 l 1,4,-1
+ 46 0 l 1,5,-1
+ 46 471 l 2,6,7
+ 46 499 46 499 51.5 526 c 128,-1,8
+ 57 553 57 553 67.5 578 c 128,-1,9
+ 78 603 78 603 92.5 624.5 c 128,-1,10
+ 107 646 107 646 126 665 c 128,-1,11
+ 145 684 145 684 166.5 698.5 c 128,-1,12
+ 188 713 188 713 213 723.5 c 128,-1,13
+ 238 734 238 734 264.5 739.5 c 128,-1,14
+ 291 745 291 745 319 745 c 0,15,16
+ 362 745 362 745 402 732 c 128,-1,17
+ 442 719 442 719 477 695 c 1,18,-1
+ 407 598 l 1,19,20
+ 388 611 388 611 366 618.5 c 128,-1,21
+ 344 626 344 626 319 626 c 0,22,23
+ 288 626 288 626 259.5 613.5 c 128,-1,24
+ 231 601 231 601 210 580 c 128,-1,25
+ 189 559 189 559 176.5 530.5 c 128,-1,26
+ 164 502 164 502 164 471 c 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: F
+Encoding: 70 70 29
+Width: 585
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+164 471 m 1,0,-1
+ 354 472 l 1,1,-1
+ 354 353 l 1,2,-1
+ 165 353 l 1,3,-1
+ 164 0 l 1,4,-1
+ 46 0 l 1,5,-1
+ 46 471 l 2,6,7
+ 46 499 46 499 51.5 526 c 128,-1,8
+ 57 553 57 553 67.5 578 c 128,-1,9
+ 78 603 78 603 92.5 624.5 c 128,-1,10
+ 107 646 107 646 126 665 c 128,-1,11
+ 145 684 145 684 166.5 698.5 c 128,-1,12
+ 188 713 188 713 213 723.5 c 128,-1,13
+ 238 734 238 734 264.5 739.5 c 128,-1,14
+ 291 745 291 745 319 745 c 0,15,16
+ 356 745 356 745 391 735.5 c 128,-1,17
+ 426 726 426 726 456.5 708 c 128,-1,18
+ 487 690 487 690 512.5 665 c 128,-1,19
+ 538 640 538 640 556 608 c 1,20,-1
+ 453 548 l 1,21,22
+ 443 566 443 566 428.5 580.5 c 128,-1,23
+ 414 595 414 595 397 605 c 128,-1,24
+ 380 615 380 615 360 620.5 c 128,-1,25
+ 340 626 340 626 319 626 c 0,26,27
+ 288 626 288 626 259.5 613.5 c 128,-1,28
+ 231 601 231 601 210 580 c 128,-1,29
+ 189 559 189 559 176.5 530.5 c 128,-1,30
+ 164 502 164 502 164 471 c 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: j
+Encoding: 106 106 30
+Width: 509
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+399 744 m 0,0,1
+ 411 744 411 744 422.5 739.5 c 128,-1,2
+ 434 735 434 735 441.5 727 c 128,-1,3
+ 449 719 449 719 454 708 c 128,-1,4
+ 459 697 459 697 459 686 c 0,5,6
+ 459 673 459 673 454 662 c 128,-1,7
+ 449 651 449 651 441.5 643 c 128,-1,8
+ 434 635 434 635 422.5 630.5 c 128,-1,9
+ 411 626 411 626 399 626 c 0,10,11
+ 386 626 386 626 375.5 630.5 c 128,-1,12
+ 365 635 365 635 357.5 643 c 128,-1,13
+ 350 651 350 651 345 662 c 128,-1,14
+ 340 673 340 673 340 686 c 0,15,16
+ 340 698 340 698 345 708.5 c 128,-1,17
+ 350 719 350 719 357.5 727 c 128,-1,18
+ 365 735 365 735 375.5 739.5 c 128,-1,19
+ 386 744 386 744 399 744 c 0,0,1
+459 77 m 2,20,21
+ 459 49 459 49 453 22.5 c 128,-1,22
+ 447 -4 447 -4 437 -28.5 c 128,-1,23
+ 427 -53 427 -53 411.5 -75 c 128,-1,24
+ 396 -97 396 -97 377.5 -115.5 c 128,-1,25
+ 359 -134 359 -134 337 -149 c 128,-1,26
+ 315 -164 315 -164 291 -174.5 c 128,-1,27
+ 267 -185 267 -185 240 -190.5 c 128,-1,28
+ 213 -196 213 -196 185 -196 c 0,29,30
+ 143 -196 143 -196 102.5 -183 c 128,-1,31
+ 62 -170 62 -170 28 -146 c 1,32,-1
+ 97 -48 l 1,33,34
+ 117 -62 117 -62 139 -69.5 c 128,-1,35
+ 161 -77 161 -77 185 -77 c 0,36,37
+ 217 -77 217 -77 245 -64.5 c 128,-1,38
+ 273 -52 273 -52 294 -30.5 c 128,-1,39
+ 315 -9 315 -9 327.5 19 c 128,-1,40
+ 340 47 340 47 340 79 c 2,41,-1
+ 340 548 l 1,42,-1
+ 459 548 l 1,43,-1
+ 459 77 l 2,20,21
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: J
+Encoding: 74 74 31
+Width: 588
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+479 744 m 0,0,1
+ 491 744 491 744 502 739.5 c 128,-1,2
+ 513 735 513 735 521 727 c 128,-1,3
+ 529 719 529 719 533.5 708 c 128,-1,4
+ 538 697 538 697 538 686 c 0,5,6
+ 538 673 538 673 533.5 662 c 128,-1,7
+ 529 651 529 651 521 643 c 128,-1,8
+ 513 635 513 635 502 630.5 c 128,-1,9
+ 491 626 491 626 479 626 c 0,10,11
+ 466 626 466 626 455.5 630.5 c 128,-1,12
+ 445 635 445 635 437.5 643 c 128,-1,13
+ 430 651 430 651 425 662 c 128,-1,14
+ 420 673 420 673 420 686 c 0,15,16
+ 420 698 420 698 425 708.5 c 128,-1,17
+ 430 719 430 719 437.5 727 c 128,-1,18
+ 445 735 445 735 455.5 739.5 c 128,-1,19
+ 466 744 466 744 479 744 c 0,0,1
+538 78 m 2,20,21
+ 538 50 538 50 532.5 23.5 c 128,-1,22
+ 527 -3 527 -3 517 -28 c 128,-1,23
+ 507 -53 507 -53 492 -75 c 128,-1,24
+ 477 -97 477 -97 458 -115.5 c 128,-1,25
+ 439 -134 439 -134 417.5 -149 c 128,-1,26
+ 396 -164 396 -164 371.5 -174.5 c 128,-1,27
+ 347 -185 347 -185 320 -190.5 c 128,-1,28
+ 293 -196 293 -196 265 -196 c 0,29,30
+ 229 -196 229 -196 194 -186.5 c 128,-1,31
+ 159 -177 159 -177 128.5 -159 c 128,-1,32
+ 98 -141 98 -141 72 -115.5 c 128,-1,33
+ 46 -90 46 -90 28 -59 c 1,34,-1
+ 131 0 l 1,35,36
+ 142 -17 142 -17 156 -31 c 128,-1,37
+ 170 -45 170 -45 187.5 -55 c 128,-1,38
+ 205 -65 205 -65 224.5 -71 c 128,-1,39
+ 244 -77 244 -77 265 -77 c 0,40,41
+ 297 -77 297 -77 325.5 -64.5 c 128,-1,42
+ 354 -52 354 -52 375 -30.5 c 128,-1,43
+ 396 -9 396 -9 408 19 c 128,-1,44
+ 420 47 420 47 420 79 c 2,45,-1
+ 420 548 l 1,46,-1
+ 538 548 l 1,47,-1
+ 538 78 l 2,20,21
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: six
+Encoding: 54 54 32
+Width: 624
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+43 273 m 2,0,-1
+ 43 476 l 2,1,2
+ 43 504 43 504 48.5 531 c 128,-1,3
+ 54 558 54 558 64.5 582 c 128,-1,4
+ 75 606 75 606 89.5 628 c 128,-1,5
+ 104 650 104 650 123 669 c 128,-1,6
+ 142 688 142 688 164 702.5 c 128,-1,7
+ 186 717 186 717 210.5 727.5 c 128,-1,8
+ 235 738 235 738 261.5 743.5 c 128,-1,9
+ 288 749 288 749 316 749 c 0,10,11
+ 362 749 362 749 404.5 734.5 c 128,-1,12
+ 447 720 447 720 482.5 693 c 128,-1,13
+ 518 666 518 666 543 629.5 c 128,-1,14
+ 568 593 568 593 580 549 c 1,15,-1
+ 453 549 l 1,16,17
+ 443 568 443 568 428.5 583 c 128,-1,18
+ 414 598 414 598 396.5 608 c 128,-1,19
+ 379 618 379 618 358.5 624 c 128,-1,20
+ 338 630 338 630 317 630 c 0,21,22
+ 288 630 288 630 262 619.5 c 128,-1,23
+ 236 609 236 609 215.5 591.5 c 128,-1,24
+ 195 574 195 574 182 549.5 c 128,-1,25
+ 169 525 169 525 165 497 c 1,26,27
+ 182 509 182 509 200.5 518 c 128,-1,28
+ 219 527 219 527 238 534 c 128,-1,29
+ 257 541 257 541 277 544.5 c 128,-1,30
+ 297 548 297 548 317 548 c 0,31,32
+ 344 548 344 548 371 542.5 c 128,-1,33
+ 398 537 398 537 422.5 526.5 c 128,-1,34
+ 447 516 447 516 469 501 c 128,-1,35
+ 491 486 491 486 509.5 467 c 128,-1,36
+ 528 448 528 448 543.5 426 c 128,-1,37
+ 559 404 559 404 569.5 379.5 c 128,-1,38
+ 580 355 580 355 585.5 328.5 c 128,-1,39
+ 591 302 591 302 591 273 c 0,40,41
+ 591 246 591 246 585.5 219 c 128,-1,42
+ 580 192 580 192 570 168 c 128,-1,43
+ 560 144 560 144 544.5 122 c 128,-1,44
+ 529 100 529 100 510.5 81 c 128,-1,45
+ 492 62 492 62 470 47 c 128,-1,46
+ 448 32 448 32 423.5 21.5 c 128,-1,47
+ 399 11 399 11 372.5 5.5 c 128,-1,48
+ 346 0 346 0 317 0 c 256,49,50
+ 289 0 289 0 262 5.5 c 128,-1,51
+ 235 11 235 11 211 21.5 c 128,-1,52
+ 187 32 187 32 165 47 c 128,-1,53
+ 143 62 143 62 124 80.5 c 128,-1,54
+ 105 99 105 99 90 121 c 128,-1,55
+ 75 143 75 143 65 167.5 c 128,-1,56
+ 55 192 55 192 49 218.5 c 128,-1,57
+ 43 245 43 245 43 273 c 2,0,-1
+160 273 m 0,58,59
+ 161 242 161 242 173.5 214 c 128,-1,60
+ 186 186 186 186 207.5 165 c 128,-1,61
+ 229 144 229 144 257 131.5 c 128,-1,62
+ 285 119 285 119 317 119 c 256,63,64
+ 349 119 349 119 377 131.5 c 128,-1,65
+ 405 144 405 144 426 165.5 c 128,-1,66
+ 447 187 447 187 459.5 215 c 128,-1,67
+ 472 243 472 243 472 274 c 0,68,69
+ 471 306 471 306 458.5 334 c 128,-1,70
+ 446 362 446 362 425 382.5 c 128,-1,71
+ 404 403 404 403 376.5 415.5 c 128,-1,72
+ 349 428 349 428 317 428 c 0,73,74
+ 285 428 285 428 257 415.5 c 128,-1,75
+ 229 403 229 403 207.5 382 c 128,-1,76
+ 186 361 186 361 173 333 c 128,-1,77
+ 160 305 160 305 160 273 c 0,58,59
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: five
+Encoding: 53 53 33
+Width: 588
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+159 626 m 1,0,-1
+ 159 521 l 1,1,2
+ 187 535 187 535 216.5 541.5 c 128,-1,3
+ 246 548 246 548 278 548 c 0,4,5
+ 306 548 306 548 333 542 c 128,-1,6
+ 360 536 360 536 384.5 526 c 128,-1,7
+ 409 516 409 516 431 501 c 128,-1,8
+ 453 486 453 486 471.5 467 c 128,-1,9
+ 490 448 490 448 505.5 426.5 c 128,-1,10
+ 521 405 521 405 531 380 c 128,-1,11
+ 541 355 541 355 547 328.5 c 128,-1,12
+ 553 302 553 302 553 273 c 256,13,14
+ 553 245 553 245 547 218.5 c 128,-1,15
+ 541 192 541 192 531 167.5 c 128,-1,16
+ 521 143 521 143 505.5 121 c 128,-1,17
+ 490 99 490 99 471.5 80.5 c 128,-1,18
+ 453 62 453 62 431 47 c 128,-1,19
+ 409 32 409 32 384.5 21.5 c 128,-1,20
+ 360 11 360 11 333.5 5.5 c 128,-1,21
+ 307 0 307 0 278 0 c 0,22,23
+ 242 0 242 0 207.5 10 c 128,-1,24
+ 173 20 173 20 142 37.5 c 128,-1,25
+ 111 55 111 55 85.5 80 c 128,-1,26
+ 60 105 60 105 42 137 c 1,27,-1
+ 145 197 l 1,28,29
+ 156 179 156 179 170 164.5 c 128,-1,30
+ 184 150 184 150 201.5 140 c 128,-1,31
+ 219 130 219 130 238.5 124.5 c 128,-1,32
+ 258 119 258 119 278 119 c 0,33,34
+ 310 119 310 119 338.5 131.5 c 128,-1,35
+ 367 144 367 144 388 165 c 128,-1,36
+ 409 186 409 186 421.5 214 c 128,-1,37
+ 434 242 434 242 434 273 c 0,38,39
+ 434 305 434 305 421.5 333.5 c 128,-1,40
+ 409 362 409 362 388 383 c 128,-1,41
+ 367 404 367 404 339 416 c 128,-1,42
+ 311 428 311 428 278 428 c 0,43,44
+ 257 428 257 428 240 426 c 128,-1,45
+ 223 424 223 424 208 417.5 c 128,-1,46
+ 193 411 193 411 181 400 c 128,-1,47
+ 169 389 169 389 159 371 c 1,48,-1
+ 41 412 l 1,49,-1
+ 42 744 l 1,50,-1
+ 552 744 l 1,51,-1
+ 552 626 l 1,52,-1
+ 159 626 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: nine
+Encoding: 57 57 34
+Width: 625
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+585 476 m 2,0,-1
+ 586 273 l 2,1,2
+ 586 245 586 245 580 218 c 128,-1,3
+ 574 191 574 191 564 167 c 128,-1,4
+ 554 143 554 143 538.5 121 c 128,-1,5
+ 523 99 523 99 504.5 80.5 c 128,-1,6
+ 486 62 486 62 464 47 c 128,-1,7
+ 442 32 442 32 418 21.5 c 128,-1,8
+ 394 11 394 11 367 5.5 c 128,-1,9
+ 340 0 340 0 312 0 c 0,10,11
+ 266 0 266 0 223.5 15 c 128,-1,12
+ 181 30 181 30 146 56.5 c 128,-1,13
+ 111 83 111 83 85.5 119.5 c 128,-1,14
+ 60 156 60 156 48 200 c 1,15,-1
+ 175 200 l 1,16,17
+ 186 181 186 181 200.5 166 c 128,-1,18
+ 215 151 215 151 232.5 141 c 128,-1,19
+ 250 131 250 131 270 125 c 128,-1,20
+ 290 119 290 119 312 119 c 0,21,22
+ 340 119 340 119 366 129.5 c 128,-1,23
+ 392 140 392 140 412.5 157.5 c 128,-1,24
+ 433 175 433 175 446.5 199.5 c 128,-1,25
+ 460 224 460 224 464 252 c 1,26,27
+ 446 240 446 240 428 231 c 128,-1,28
+ 410 222 410 222 390.5 215 c 128,-1,29
+ 371 208 371 208 351.5 204.5 c 128,-1,30
+ 332 201 332 201 312 201 c 0,31,32
+ 284 201 284 201 257 206.5 c 128,-1,33
+ 230 212 230 212 205.5 222.5 c 128,-1,34
+ 181 233 181 233 159 248.5 c 128,-1,35
+ 137 264 137 264 118.5 282.5 c 128,-1,36
+ 100 301 100 301 84.5 323 c 128,-1,37
+ 69 345 69 345 59 369.5 c 128,-1,38
+ 49 394 49 394 43 420.5 c 128,-1,39
+ 37 447 37 447 37 476 c 256,40,41
+ 37 504 37 504 42.5 530.5 c 128,-1,42
+ 48 557 48 557 58.5 581.5 c 128,-1,43
+ 69 606 69 606 84 627.5 c 128,-1,44
+ 99 649 99 649 118 668.5 c 128,-1,45
+ 137 688 137 688 159 702.5 c 128,-1,46
+ 181 717 181 717 205 727.5 c 128,-1,47
+ 229 738 229 738 256 743.5 c 128,-1,48
+ 283 749 283 749 312 749 c 256,49,50
+ 340 749 340 749 366.5 743.5 c 128,-1,51
+ 393 738 393 738 417.5 727.5 c 128,-1,52
+ 442 717 442 717 464 702.5 c 128,-1,53
+ 486 688 486 688 504.5 669 c 128,-1,54
+ 523 650 523 650 538 628 c 128,-1,55
+ 553 606 553 606 563.5 582 c 128,-1,56
+ 574 558 574 558 579.5 531 c 128,-1,57
+ 585 504 585 504 585 476 c 2,0,-1
+468 476 m 0,58,59
+ 468 507 468 507 455 535 c 128,-1,60
+ 442 563 442 563 420.5 584 c 128,-1,61
+ 399 605 399 605 371 617.5 c 128,-1,62
+ 343 630 343 630 312 630 c 0,63,64
+ 280 630 280 630 251.5 617.5 c 128,-1,65
+ 223 605 223 605 202 583.5 c 128,-1,66
+ 181 562 181 562 169 534.5 c 128,-1,67
+ 157 507 157 507 157 475 c 0,68,69
+ 157 444 157 444 169.5 415.5 c 128,-1,70
+ 182 387 182 387 203 366.5 c 128,-1,71
+ 224 346 224 346 251.5 333.5 c 128,-1,72
+ 279 321 279 321 312 321 c 256,73,74
+ 344 321 344 321 372 333.5 c 128,-1,75
+ 400 346 400 346 421.5 367 c 128,-1,76
+ 443 388 443 388 455.5 416 c 128,-1,77
+ 468 444 468 444 468 476 c 0,58,59
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: one
+Encoding: 49 49 35
+Width: 311
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+263 0 m 1,0,-1
+ 132 0 l 1,1,-1
+ 132 554 l 1,2,-1
+ 34 554 l 1,3,-1
+ 32 648 l 1,4,5
+ 58 649 58 649 81 657 c 128,-1,6
+ 104 665 104 665 121 678.5 c 128,-1,7
+ 138 692 138 692 147.5 709.5 c 128,-1,8
+ 157 727 157 727 157 744 c 1,9,-1
+ 263 744 l 1,10,-1
+ 263 0 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: copyright
+Encoding: 169 169 36
+Width: 821
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+411 0 m 256,0,1
+ 373 0 373 0 336.5 8 c 128,-1,2
+ 300 16 300 16 266.5 30 c 128,-1,3
+ 233 44 233 44 203.5 64 c 128,-1,4
+ 174 84 174 84 148.5 109.5 c 128,-1,5
+ 123 135 123 135 103 164.5 c 128,-1,6
+ 83 194 83 194 69 227.5 c 128,-1,7
+ 55 261 55 261 47 297.5 c 128,-1,8
+ 39 334 39 334 39 372 c 0,9,10
+ 39 411 39 411 47 447 c 128,-1,11
+ 55 483 55 483 69 517 c 128,-1,12
+ 83 551 83 551 103 580.5 c 128,-1,13
+ 123 610 123 610 148.5 635 c 128,-1,14
+ 174 660 174 660 203.5 680.5 c 128,-1,15
+ 233 701 233 701 266.5 715 c 128,-1,16
+ 300 729 300 729 336.5 736.5 c 128,-1,17
+ 373 744 373 744 411 744 c 256,18,19
+ 449 744 449 744 485.5 736.5 c 128,-1,20
+ 522 729 522 729 555.5 715 c 128,-1,21
+ 589 701 589 701 618.5 680.5 c 128,-1,22
+ 648 660 648 660 673.5 635 c 128,-1,23
+ 699 610 699 610 719 580.5 c 128,-1,24
+ 739 551 739 551 753.5 517 c 128,-1,25
+ 768 483 768 483 775.5 447 c 128,-1,26
+ 783 411 783 411 783 372 c 0,27,28
+ 783 334 783 334 775.5 297.5 c 128,-1,29
+ 768 261 768 261 753.5 227.5 c 128,-1,30
+ 739 194 739 194 719 164.5 c 128,-1,31
+ 699 135 699 135 673.5 109.5 c 128,-1,32
+ 648 84 648 84 618.5 64 c 128,-1,33
+ 589 44 589 44 555.5 30 c 128,-1,34
+ 522 16 522 16 485.5 8 c 128,-1,35
+ 449 0 449 0 411 0 c 256,0,1
+411 93 m 0,36,37
+ 440 93 440 93 467 98.5 c 128,-1,38
+ 494 104 494 104 519.5 115 c 128,-1,39
+ 545 126 545 126 567.5 141 c 128,-1,40
+ 590 156 590 156 608.5 175 c 128,-1,41
+ 627 194 627 194 642 216.5 c 128,-1,42
+ 657 239 657 239 668 264 c 128,-1,43
+ 679 289 679 289 684.5 316.5 c 128,-1,44
+ 690 344 690 344 690 372 c 0,45,46
+ 690 401 690 401 684.5 428.5 c 128,-1,47
+ 679 456 679 456 668 481 c 128,-1,48
+ 657 506 657 506 642 528.5 c 128,-1,49
+ 627 551 627 551 608.5 569.5 c 128,-1,50
+ 590 588 590 588 567.5 603 c 128,-1,51
+ 545 618 545 618 519.5 629 c 128,-1,52
+ 494 640 494 640 467 645.5 c 128,-1,53
+ 440 651 440 651 411 651 c 0,54,55
+ 383 651 383 651 355.5 645.5 c 128,-1,56
+ 328 640 328 640 302.5 629 c 128,-1,57
+ 277 618 277 618 255 603 c 128,-1,58
+ 233 588 233 588 214 569.5 c 128,-1,59
+ 195 551 195 551 180 528.5 c 128,-1,60
+ 165 506 165 506 154.5 481 c 128,-1,61
+ 144 456 144 456 138 428.5 c 128,-1,62
+ 132 401 132 401 132 372 c 0,63,64
+ 132 344 132 344 138 316.5 c 128,-1,65
+ 144 289 144 289 154.5 264 c 128,-1,66
+ 165 239 165 239 180 216.5 c 128,-1,67
+ 195 194 195 194 214 175 c 128,-1,68
+ 233 156 233 156 255 141 c 128,-1,69
+ 277 126 277 126 302.5 115 c 128,-1,70
+ 328 104 328 104 355.5 98.5 c 128,-1,71
+ 383 93 383 93 411 93 c 0,36,37
+593 478 m 1,72,-1
+ 513 432 l 1,73,74
+ 505 445 505 445 494 456 c 128,-1,75
+ 483 467 483 467 470 474.5 c 128,-1,76
+ 457 482 457 482 442 486 c 128,-1,77
+ 427 490 427 490 411 490 c 0,78,79
+ 387 490 387 490 365 481 c 128,-1,80
+ 343 472 343 472 327 455.5 c 128,-1,81
+ 311 439 311 439 301.5 417.5 c 128,-1,82
+ 292 396 292 396 292 372 c 256,83,84
+ 292 348 292 348 301.5 326.5 c 128,-1,85
+ 311 305 311 305 327 288.5 c 128,-1,86
+ 343 272 343 272 365 262.5 c 128,-1,87
+ 387 253 387 253 411 253 c 0,88,89
+ 427 253 427 253 442 257.5 c 128,-1,90
+ 457 262 457 262 470 269.5 c 128,-1,91
+ 483 277 483 277 494.5 288.5 c 128,-1,92
+ 506 300 506 300 514 313 c 1,93,-1
+ 592 268 l 1,94,95
+ 578 244 578 244 558.5 224 c 128,-1,96
+ 539 204 539 204 515.5 190.5 c 128,-1,97
+ 492 177 492 177 465 169.5 c 128,-1,98
+ 438 162 438 162 411 162 c 0,99,100
+ 390 162 390 162 369.5 166.5 c 128,-1,101
+ 349 171 349 171 330 179 c 128,-1,102
+ 311 187 311 187 294 198.5 c 128,-1,103
+ 277 210 277 210 262.5 224 c 128,-1,104
+ 248 238 248 238 237 254.5 c 128,-1,105
+ 226 271 226 271 218 290.5 c 128,-1,106
+ 210 310 210 310 205.5 330.5 c 128,-1,107
+ 201 351 201 351 201 372 c 256,108,109
+ 201 393 201 393 205.5 414 c 128,-1,110
+ 210 435 210 435 218 454 c 128,-1,111
+ 226 473 226 473 237 489.5 c 128,-1,112
+ 248 506 248 506 262.5 520 c 128,-1,113
+ 277 534 277 534 294 546 c 128,-1,114
+ 311 558 311 558 330 565.5 c 128,-1,115
+ 349 573 349 573 369.5 577.5 c 128,-1,116
+ 390 582 390 582 411 582 c 0,117,118
+ 438 582 438 582 465 574.5 c 128,-1,119
+ 492 567 492 567 515.5 553.5 c 128,-1,120
+ 539 540 539 540 559 520.5 c 128,-1,121
+ 579 501 579 501 593 478 c 1,72,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: two
+Encoding: 50 50 37
+Width: 595
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+248 118 m 1,0,-1
+ 551 118 l 1,1,-1
+ 551 0 l 1,2,-1
+ 41 0 l 1,3,-1
+ 40 116 l 1,4,-1
+ 367 346 l 2,5,6
+ 382 357 382 357 393.5 370 c 128,-1,7
+ 405 383 405 383 414 399 c 128,-1,8
+ 423 415 423 415 428 433 c 128,-1,9
+ 433 451 433 451 433 471 c 0,10,11
+ 433 503 433 503 420.5 531 c 128,-1,12
+ 408 559 408 559 387 580 c 128,-1,13
+ 366 601 366 601 338 613 c 128,-1,14
+ 310 625 310 625 277 625 c 0,15,16
+ 256 625 256 625 237 619.5 c 128,-1,17
+ 218 614 218 614 200.5 604 c 128,-1,18
+ 183 594 183 594 168.5 579.5 c 128,-1,19
+ 154 565 154 565 144 548 c 1,20,-1
+ 41 607 l 1,21,22
+ 59 638 59 638 84.5 663.5 c 128,-1,23
+ 110 689 110 689 141 707.5 c 128,-1,24
+ 172 726 172 726 206.5 735 c 128,-1,25
+ 241 744 241 744 277 744 c 0,26,27
+ 305 744 305 744 332 738.5 c 128,-1,28
+ 359 733 359 733 383.5 723 c 128,-1,29
+ 408 713 408 713 430 698 c 128,-1,30
+ 452 683 452 683 470.5 664.5 c 128,-1,31
+ 489 646 489 646 504.5 624 c 128,-1,32
+ 520 602 520 602 530 577.5 c 128,-1,33
+ 540 553 540 553 546 526 c 128,-1,34
+ 552 499 552 499 552 471 c 0,35,36
+ 552 436 552 436 543 403.5 c 128,-1,37
+ 534 371 534 371 518.5 342 c 128,-1,38
+ 503 313 503 313 481.5 289 c 128,-1,39
+ 460 265 460 265 433 246 c 2,40,-1
+ 248 118 l 1,0,-1
+EndSplineSet
+Validated: 1
+EndChar
+
+StartChar: w
+Encoding: 119 119 38
+Width: 1070
+Flags: W
+LayerCount: 2
+Fore
+SplineSet
+532 103 m 1,0,1
+ 448 0 448 0 318 0 c 0,2,3
+ 204 0 204 0 124 80 c 128,-1,4
+ 44 160 44 160 44 274 c 2,5,-1
+ 44 548 l 1,6,-1
+ 164 548 l 1,7,-1
+ 164 272 l 2,8,9
+ 164 208 164 208 209 164 c 128,-1,10
+ 254 120 254 120 318 120 c 0,11,12
+ 380 120 380 120 427.5 169.5 c 128,-1,13
+ 475 219 475 219 475 274 c 2,14,-1
+ 474 548 l 1,15,-1
+ 591 548 l 1,16,-1
+ 591 274 l 2,17,18
+ 591 218 591 218 637 169 c 128,-1,19
+ 683 120 683 120 746 120 c 256,20,21
+ 809 120 809 120 854 164 c 128,-1,22
+ 899 208 899 208 900 272 c 2,23,-1
+ 900 548 l 1,24,-1
+ 1021 548 l 1,25,-1
+ 1021 274 l 2,26,27
+ 1021 160 1021 160 940 80 c 128,-1,28
+ 859 0 859 0 746 0 c 0,29,30
+ 615 0 615 0 532 103 c 1,0,1
+EndSplineSet
+Validated: 1
+EndChar
+EndChars
+EndSplineFont
diff --git a/fonts/Handbook/README.md b/fonts/Handbook/README.md
new file mode 100644
index 0000000..5010dca
--- /dev/null
+++ b/fonts/Handbook/README.md
@@ -0,0 +1,12 @@
+# DEC Handbook font
+
+This is a reconstruction of the font used on DEC processor handbook
+covers and other manuals in the early 1970s. Some characters did not
+appear in the originals (like "x") so they are made up in the style of
+the others.
+
+This is a lower case only font. A few letters have alternate shapes,
+with short and long curving parts. The long curve shapes are the
+lower case letters; these are suitable for the end of a word (f r t)
+and the start (j). The corresponding upper case letters are for use
+in the middle of a word.
diff --git a/fonts/README.md b/fonts/README.md
new file mode 100644
index 0000000..f4df57e
--- /dev/null
+++ b/fonts/README.md
@@ -0,0 +1,6 @@
+# DEC related fonts
+
+This subtree contains various fonts reconstructed from DEC documents.
+
+* Handbook -- the font used on DEC processor handbooks and manuals in
+the earli 1970s, such as the PDP-11/20 processor handbook.
diff --git a/teco/README.md b/teco/README.md
new file mode 100644
index 0000000..46d5eda
--- /dev/null
+++ b/teco/README.md
@@ -0,0 +1,14 @@
+# TECO in Python
+
+This is an implementation of TECO in Python 3. I originally wrote it
+as a programming language learning exercise, so it's not really
+polished, but it is functional. Since it uses Python 3, it has the
+rather unusual property of supporting Unicode directly.
+
+Contents:
+* teco.py -- the program. It supports a "GT40" style via wxPython, if
+installed. "Curses" support (for ANSI terminals) is not yet
+operational.
+* bmp.tec -- a sample TECO macro showing Unicode support. It fills
+the buffer with all the characters of the Unicode Basic Multinational
+Plane.
diff --git a/teco/bmp.tec b/teco/bmp.tec
new file mode 100644
index 0000000..34437ae
--- /dev/null
+++ b/teco/bmp.tec
@@ -0,0 +1,4 @@
+^d 16^r 0ua 10000/20 qbr @i/: /
+ 20@i/
+/> w
+
diff --git a/teco/teco.py b/teco/teco.py
new file mode 100755
index 0000000..3807353
--- /dev/null
+++ b/teco/teco.py
@@ -0,0 +1,3400 @@
+#!/usr/bin/env python3
+
+"""TECO for Python
+
+Copyright (C) 2006, 2014 by Paul Koning
+
+This is an implementation of DEC Standard TECO in Python.
+It corresponds to PDP-11/VAX TECO V40, give or take a few details
+that don't really carry over.
+"""
+
+import os
+import sys
+import re
+import time
+import traceback
+import glob
+import warnings
+import copy
+import atexit
+import threading
+import tempfile
+
+try:
+ import curses
+ curses.initscr ()
+ curses.endwin ()
+ curses.def_shell_mode ()
+ cursespresent = True
+except ImportError:
+ cursespresent = False
+
+try:
+ import wx
+ wxpresent = True
+except ImportError:
+ wxpresent = False
+
+# char codes
+null = '\000'
+ctrlc = '\003'
+ctrle = '\005'
+bs = '\010'
+bell = '\007'
+tab = '\011'
+lf = '\012'
+vt = '\013'
+ff = '\014'
+cr = '\015'
+crlf = cr + lf
+ctrls = '\023'
+ctrlu = '\025'
+ctrlx = '\030'
+esc = '\033'
+rub = '\177'
+eol = lf + vt + ff # all these are TECO end of line (TODO)
+
+# global variables
+screen = None
+display = None
+dsem = None
+exiting = False
+
+# Other useful constants
+VERSION = 40
+
+# There is no good match for the CPU and OS types. Based on the
+# features, PDP-11 makes sense, since this TECO looks like TECO-11.
+# The implementation of ^B says we'd like to call it RSX/VMS, but
+# that won't work because various code (like TECO.TEC) will use that
+# as a hint to construct filenames with RMS format switches in them,
+# and those look like Unix directory names, so all hell will break
+# loose. The best answer, therefore, is to call it RT-11, which
+# has neither directories nor file version numbers nor filename
+# switches. RSX/VMS has all of those, and RSTS/E has all except
+# versions -- but any of those would give Unix filename handlers
+# conniption fits...
+CPU = 0 # Pretend to be a PDP-11, that's closest
+OS = 7 # OS is Unix, but pretend it's RT-11
+
+# unbuffered input: Python Cookbook V2 section 2.23
+try:
+ from msvcrt import getch
+ rubchr = '\010'
+except ImportError:
+ rubchr = '\177'
+ def getch ():
+ """Get a character in raw (unechoed, single character) mode.
+ """
+ import tty, termios
+ fd = sys.stdin.fileno ()
+ old_settings = termios.tcgetattr (fd)
+ try:
+ tty.setraw (fd)
+ ch = sys.stdin.read (1)
+ finally:
+ termios.tcsetattr (fd, termios.TCSADRAIN, old_settings)
+ return ch
+
+# Enhanced traceback, from Python Cookbook section 8.6, slightly tweaked
+maxstrlen = 200
+def print_exc_plus ():
+ '''Print all the usual traceback information, followed by a listing of
+ all the local variables in each frame.
+
+ Variable values are truncated to 200 characters max for readability,
+ and converted to printable characters in standard TECO fashion.
+ '''
+ tb = sys.exc_info ()[2]
+ while tb.tb_next:
+ tb = tb.tb_next
+ stack = [ ]
+ f = tb.tb_frame
+ while f:
+ stack.append (f)
+ f = f.f_back
+ stack.reverse ()
+ endwin ()
+ traceback.print_exc ()
+ print("Locals by frame, innermost last")
+ if stack[0].f_code.co_name == "?":
+ del stack[0]
+ for frame in stack:
+ print()
+ print("Frame %s in %s at line %s" % (frame.f_code.co_name,
+ frame.f_code.co_filename,
+ frame.f_lineno))
+ for key, value in list(frame.f_locals.items ()):
+ print("\t%20s = " % key, end=' ')
+ try:
+ value = printable (str (value))
+ if len (value) > maxstrlen:
+ value = value[:maxstrlen] + "..."
+ print(value)
+ except:
+ print("")
+
+# Transform a generic binary string to a printable one. Try to
+# optimize this because sometimes it is fed big strings.
+# tab through cr are printed as is; other control chars are uparrowed
+# except for esc of course.
+# Taken from Python Cookbook, section 1.18
+_printre = re.compile ("[\000-\007\016-\037\177]")
+_printdict = { }
+for c in range (0o40):
+ _printdict[chr (c)] = '^' + chr (c + 64)
+_printdict[esc] = '$'
+_printdict[rub] = "^?"
+
+def _makeprintable (m):
+ return _printdict[m.group (0)]
+
+def printable(s):
+ """Convert the supplied string to a printable string,
+ by converting all unusual control characters to uparrow
+ form, and escape to $ sign.
+ """
+ return _printre.sub (_makeprintable, s)
+
+# Error handling
+class err (Exception):
+ '''Base class for TECO errors.
+
+ Specific errors are derived from this class; the class name is
+ the three-letter code for the error, and the class doc string
+ is the event message string.
+ '''
+ def __init__ (self, teco, *a):
+ self.teco = teco
+ self.args = tuple (printable (arg) for arg in a)
+ teco.clearargs ()
+
+ def show (self):
+ endwin ()
+ detail = self.teco.eh & 3
+ if detail == 1:
+ print("?%s" % self.__class__.__name__)
+ else:
+ if self.args:
+ msg = self.__class__.__doc__ % self.args
+ else:
+ msg = self.__class__.__doc__
+ print("?%s %s" % (self.__class__.__name__, msg))
+ if self.teco.eh & 4:
+ print(printable (self.teco.failedcommand ()), "?")
+
+class ARG (err): 'Improper Arguments'
+class BNI (err): '> not in iteration'
+class FER (err): 'File Error'
+class FNF (err): 'File not found "%s"'
+class ICE (err): 'Illegal ^E Command in Search Argument'
+class IEC (err): 'Illegal character "%s" after E'
+class IFC (err): 'Illegal character "%s" after F'
+class IFN (err): 'Illegal character "%s" in filename'
+class IIA (err): 'Illegal insert arg'
+class ILL (err): 'Illegal command "%s"'
+class ILN (err): 'Illegal number'
+class INP (err): 'Input error'
+class IPA (err): 'Negative or 0 argument to P'
+class IQC (err): 'Illegal " character'
+class IQN (err): 'Illegal Q-register name "%s"'
+class IRA (err): 'Illegal radix argument to ^R'
+class ISA (err): 'Illegal search arg'
+class ISS (err): 'Illegal search string'
+class IUC (err): 'Illegal character "%s" following ^'
+class MAP (err): "Missing '"
+class MLA (err): 'Missing Left Angle Bracket'
+class MLP (err): 'Missing ('
+class MRA (err): 'Missing Right Angle Bracket'
+class MRP (err): 'Missing )'
+class NAB (err): 'No arg before ^_'
+class NAC (err): 'No arg before ,'
+class NAE (err): 'No arg before ='
+class NAP (err): 'No arg before )'
+class NAQ (err): 'No arg before "'
+class NAS (err): 'No arg before ;'
+class NAU (err): 'No arg before U'
+class NCA (err): 'Negative argument to ,'
+class NFI (err): 'No file for input'
+class NFO (err): 'No file for output'
+class NPA (err): 'Negative or 0 argument to P'
+class NYA (err): 'Numeric argument with Y'
+class NYI (err): 'Not Yet Implemented'
+class OFO (err): 'Output file already open'
+class OUT (err): 'Output error'
+class PES (err): 'Attempt to Pop Empty Stack'
+class POP (err): 'Attempt to move Pointer Off Page with "%s"'
+class SNI (err): '; not in iteration'
+class SRH (err): 'Search failure "%s"'
+class TAG (err): 'Missing Tag !%s!'
+class UTC (err): 'Unterminated command "%s"'
+class UTM (err): 'Unterminated macro'
+class XAB (err): 'Execution aborted'
+class YCA (err): 'Y command aborted'
+
+# Other exceptions used for misc purposes
+class ExitLevel (Exception): pass
+class ExitExecution (Exception): pass
+
+# text reformatting for screen display
+tabre = re.compile (tab)
+_tabadjust = 0
+def _untabify (m):
+ global _curcol, _tabadjust
+ pos = m.start () + _tabadjust
+ count = 8 - (pos & 7)
+ if _curcol > pos:
+ _curcol += count - 1
+ _tabadjust += count - 1
+ return " " * count
+
+def untabify (line, curpos, width):
+ """Convert tabs to spaces, and wrap the line as needed into chunks
+ of the specified width. Returns the list of chunks, and the row
+ and column corresponding to the supplied curpos. There is always
+ at least one chunk, which may have an empty string if the supplied
+ line was empty.
+
+ Each chunk is a pair of text and wrap flag. Wrap flag is True
+ if this chunk of text is wrapped, i.e., it does not end with a
+ carriage return, and False if it is the end of the line.
+
+ Note that a trailing cr and/or lf is stripped from the input line.
+ """
+ global _curcol, _tabadjust
+ _curcol = curpos
+ _tabadjust = 0
+ line = tabre.sub (_untabify, printable (line.rstrip (crlf)))
+ currow = 0
+ if True: # todo: truncate vs. wrap mode
+ lines = [ ]
+ while len (line) > width:
+ lines.append ((line[:width], True))
+ line = line[width:]
+ if _curcol > width:
+ currow += 1
+ _curcol -= width
+ lines.append ((line, False))
+ return lines, currow, _curcol
+
+# Property makers
+def commonprop (name, doc=None):
+ """Define a property that references an attribute of 'teco'
+ (the common state object for TECO).
+ """
+ def _fget (obj):
+ return getattr (obj.teco, name)
+ def _fset (obj, val):
+ return setattr (obj.teco, name, val)
+ _fget.__name__ = "get_%s" % name
+ _fset.__name__ = "set_%s" % name
+ return property (_fget, _fset, doc=doc)
+
+def bufprop (name, doc=None):
+ """Define a property that references an attribute of 'buffer'
+ (the text buffer object for TECO).
+ """
+ def _fget (obj):
+ return getattr (obj.buffer, name)
+ def _fset (obj, val):
+ return setattr (obj.buffer, name, val)
+ _fget.__name__ = "get_%s" % name
+ _fset.__name__ = "set_%s" % name
+ return property (_fget, _fset, doc=doc)
+
+# Global state handling
+class teco (object):
+ '''This class defines the global state for TECO, i.e., the state
+ that is independent of the macro level. It also points to state
+ that is kept in separate classes, such as the buffer, the command
+ input, and the command level for the interactive level.
+ '''
+ def __init__(self):
+ self.radix = 10
+ self.ed = 0
+ self.eh = 0
+ self.es = 0
+ if wxpresent:
+ self.etfixed = 1024 # Display available
+ elif cursespresent:
+ self.etfixed = 512 # text terminal "watch" available
+ else:
+ self.etfixed = 0 # neither available
+ self.et = 128 + self.etfixed
+ self.eu = -1
+ self.ev = 0
+ setattr (self, ctrlx, 0) # ^X flag
+ self.trace = False
+ self.laststringlen = 0
+ self.qregs = { }
+ self.lastsearch = ""
+ self.lastfilename = ""
+ self.qstack = [ ]
+ self.clearargs ()
+ self.interactive = command_level (self)
+ self.buffer = buffer (self)
+ self.cmdhandler = command_handler (self)
+ self.screenok = False
+ self.incurses = False
+ self.watchparams = [ 8, 80, 24, 0, 0, 0, 0, 0 ]
+ self.curline = 16
+
+ buf = bufprop ("text")
+ dot = bufprop ("dot")
+ end = bufprop ("end")
+
+ def doop (self, c):
+ """Process a pending arithmetic operation, if any.
+ self.arg is left with the current term value.
+ """
+ if self.op:
+ if self.op in '+-' and self.arg is None:
+ self.arg = 0
+ if self.num is None:
+ raise ILL (self, c)
+ if self.op == '+':
+ self.arg += self.num
+ elif self.op == '-':
+ self.arg -= self.num
+ elif self.op == '*':
+ self.arg *= self.num
+ elif self.op == '/':
+ if not self.num:
+ raise ILL (self, '/')
+ self.arg //= self.num
+ elif self.op == '&':
+ self.arg &= self.num
+ elif self.op == '#':
+ self.arg |= self.num
+ else:
+ self.arg = self.num
+
+ def getterm (self, c):
+ """Get the current term, i.e., the innermost expression
+ part in parentheses.
+ """
+ self.doop (c)
+ ret = self.arg
+ self.num = None
+ self.op = None
+ self.arg = None
+ return ret
+
+ def leftparen (self):
+ """Proces a left parenthesis command, by pushing the current
+ partial expression state onto the operation stack.
+ """
+ self.opstack.append ((self.arg, self.op))
+ self.arg = None
+ self.op = None
+
+ def rightparen (self):
+ """Process a right parenthesis command, by setting the current
+ right-hand side to the expression term value, and popping the
+ operation stack state for the left hand and operation (if any).
+ """
+ if self.opstack:
+ try:
+ self.num = self.getterm (')')
+ except err:
+ raise NAP (self)
+ self.arg, self.op = self.opstack.pop ()
+ else:
+ raise MLP (self)
+
+ def operator (self, c):
+ """Process an arithmetic operation character.
+ """
+ if self.num is None:
+ if c in "+-" and self.arg is None:
+ self.op = c
+ return
+ else:
+ raise ILL (self, c)
+ self.doop (c)
+ self.num = None
+ self.op = c
+
+ def digit (self, c):
+ """Process a decimal digit. 8 and 9 generate an error if
+ the current radix is octal.
+ """
+ if self.num is None:
+ self.num = 0
+ n = int (c)
+ if n >= self.radix:
+ raise ILN (self)
+ self.num = self.num * self.radix + n
+
+ def getarg (self, c):
+ """Get a complete argument, or None if there isn't one.
+ If there are left parentheses that have not yet been matched,
+ that is an error. + or - alone are taken to be +1 and -1
+ respectively.
+ """
+ if self.opstack:
+ raise MRP (self)
+ if self.op and self.op in '+-' and self.num is None and self.arg is None:
+ self.num = 1
+ return self.getterm (c)
+
+ def getoptarg (self, c):
+ """Get an optional argument. Unlike getarg, this is legal
+ while we're in an incomplete expression. This method is used
+ for commands that do something if given an argument, but return
+ a value if not. This way, the second case can be used as
+ an element of an expression.
+ """
+ if self.op and self.op in '+-' and self.num is None and self.arg is None:
+ self.num = 1
+ if self.num is None:
+ return None
+ return self.getarg (c)
+
+ def setval (self, val):
+ """Set the command result value into the expression state.
+ """
+ self.num = val
+ self.clearmods ()
+
+ def bitflag (self, name):
+ """Process a bit-flag type command, i.e., one that is read by
+ supplying no argument, set by supplying one, and has its bits
+ fiddled by two arguments.
+ """
+ n = self.getoptarg (name)
+ if n is None:
+ self.setval (getattr (self, name))
+ else:
+ if self.arg2 is not None:
+ n = (getattr (self, name) | n) & (~self.arg2)
+ if n & 32768:
+ # Sign extend upper 16 bits
+ n |= -32768
+ fixed = getattr (self, name + "fixed", 0)
+ self.clearargs ()
+ setattr (self, name, n | fixed)
+
+ def numflag (self, name):
+ """Process a numeric flag type command, i.e., one that is
+ read by supplying no argument, and set by supplying the new value.
+ """
+ n = self.getoptarg (name)
+ if n is None:
+ self.setval (getattr (self, name))
+ else:
+ self.clearargs ()
+ setattr (self, name, n)
+
+ def lineargs(self, c):
+ """Process the argument(s) for a command that references lines.
+ If one argument is present, that is taken as a line count
+ displacement from dot. If two arguments are present, that is
+ the start and end of the the range.
+ """
+ m, n = self.arg2, self.getarg (c)
+ if n is None:
+ n = 1
+ if m is None:
+ if n > 0:
+ m, n = self.dot, self.buffer.line (n)
+ else:
+ m, n = self.buffer.line (n), self.dot
+ else:
+ if m < 0 or n > self.end or m > n:
+ raise POP (self, c)
+ return (m, n)
+
+ def clearmods (self):
+ """Clear modifier flags (colon and at sign).
+ """
+ self.colons = 0
+ self.atmod = False
+
+ def clearargs (self):
+ """Reinitialize all expression state, as well as modifiers.
+ """
+ self.opstack = [ ]
+ self.arg = None
+ self.arg2 = None
+ self.num = None
+ self.op = None
+ self.clearmods ()
+
+ def failedcommand (self):
+ """Return the last failed interactive command, i.e., the last
+ command up to the point where execution was aborted.
+ """
+ return self.interactive.failedcommand ()
+
+ def lastcommand (self):
+ """Return the last interactive command, in full.
+ """
+ return self.interactive.lastcommand ()
+
+ def mainloop (self):
+ """This is the TECO command loop. It fetches the command string,
+ handles special immediate action forms, and otherwise executes
+ the command as supplied. Errors are handled by catching the
+ TECO error exception, and printing the error information as
+ controlled by the EH flag.
+ """
+ preverror = False
+ try:
+ while True:
+ if not self.cmdhandler.eifile:
+ if screen:
+ y, x = screen.getmaxyx ()
+ screen.untouchwin ()
+ screen.move (y - 1, 0)
+ screen.clrtoeol ()
+ screen.refresh ()
+ curses.reset_shell_mode ()
+ self.incurses = False
+ self.screenok = False
+ self.updatedisplay ()
+ # clear "in startup mode" flag
+ self.et &= ~128
+ self.autoverify (self.ev)
+ sys.stdout.write ("*")
+ sys.stdout.flush ()
+ cmdline = self.cmdhandler.teco_cmdstring ()
+ self.clearargs ()
+ if cmdline and cmdline[-1] != esc:
+ # it was an immediate action command -- handle that
+ cmd = cmdline[0]
+ if cmd == '*':
+ try:
+ q = self.interactive.qreg (cmdline[1])
+ except err as e:
+ e.show ()
+ else:
+ q.setstr (self.lastcommand ())
+ continue
+ elif cmd == '?':
+ if preverror:
+ print(printable (self.failedcommand ()))
+ continue
+ elif cmd == lf:
+ cmdline = "lt"
+ else:
+ cmdline = "-lt"
+ try:
+ preverror = False
+ self.runcommand (cmdline)
+ except ExitExecution:
+ pass
+ except SystemExit:
+ endwin ()
+ enddisplay ()
+ break
+ except err as e:
+ preverror = True
+ e.show ()
+ ###print_exc_plus () # *** for debug
+ # Turn off any EI
+ self.cmdhandler.ei ("")
+ except:
+ print_exc_plus ()
+ except:
+ print_exc_plus ()
+
+ def runcommand (self, s):
+ """Execute the specified TECO command string as an interactive
+ level command.
+ """
+ self.interactive.run (s)
+
+ def screentext (self, height, width, curlinenum):
+ """Given a screen height and width in characters, and the
+ line on which we want 'dot' to appear, determine the text that
+ fits on the screen.
+
+ Returns a three-element tuple: lines, row, and column corresponding
+ to dot.
+
+ Lines is a list; each list element is a pair of text and
+ wrap flag. Wrap flag is True if this chunk of text is wrapped,
+ i.e., it does not end with a carriage return, and False if
+ it is the end of the line.
+ """
+ curlinestart = self.buffer.line (0)
+ curcol = self.dot - curlinestart
+ line = self.buf[curlinestart:self.buffer.line(1)]
+ lines, currow, curcol = untabify (line, curcol, width)
+ n = 1
+ # First add on lines after the current line, up to the
+ # window height, if we have that many
+ while len (lines) < height:
+ start, end = self.buffer.line (n), self.buffer.line (n + 1)
+ if start >= self.end:
+ break
+ line, i, i = untabify (self.buf[start:end], 0, width)
+ lines += line
+ n += 1
+ # Next, add lines before the current line, until we have
+ # enough to put the cursor onto the line where we want it,
+ # but also try to fill the screen
+ n = 0
+ while currow < curlinenum or len (lines) < height:
+ start, end = self.buffer.line (-n - 1), self.buffer.line (-n)
+ if not end:
+ break
+ line, i, i = untabify (self.buf[start:end], 0, width)
+ lines = line + lines
+ currow += len (line)
+ n += 1
+ # Now trim things, since (a) the topmost line may have wrapped
+ # so the cursor may be lower than we want it to be, and (b)
+ # we now probably have more lines than we want at the end
+ # of the screen.
+ trim = min (currow - curlinenum, len (lines) - height)
+ if trim > 0:
+ lines = lines[trim:]
+ currow -= trim
+ if len (lines) > height:
+ lines = lines[:height]
+ return lines, currow, curcol
+
+ def enable_curses (self):
+ """Enable curses (VT100 style screen watch) mode, if available
+ in this Python installation. This is a NOP if curses is not
+ available.
+ """
+ global screen
+ if not cursespresent:
+ return
+ if not screen:
+ atexit.register (endwin)
+ screen = curses.initscr ()
+ curses.noecho ()
+ curses.nonl ()
+ curses.raw ()
+ curses.def_prog_mode ()
+ else:
+ curses.reset_prog_mode ()
+ self.incurses = True
+ self.watchparams[2], self.watchparams[1] = screen.getmaxyx ()
+
+ def watch (self):
+ """Do a screen watch operation, i.e., update the screen to
+ reflect the buffer contents around the current dot, in curses mode.
+ """
+ if not cursespresent:
+ return
+ self.enable_curses ()
+ curlinenum = self.curline
+ width, height = self.watchparams[1], self.watchparams[2]
+ lines, currow, curcol = self.screentext (height, width, curlinenum)
+ if currow >= height:
+ currow = height - 1
+ if curcol >= width:
+ curcol = width - 1
+ for row, line in enumerate (lines):
+ line, wrap = line
+ screen.addstr (row, 0, line)
+ screen.clrtoeol ()
+ screen.clrtobot ()
+ if not self.screenok:
+ screen.clearok (1)
+ self.screenok = True
+ screen.move (currow, curcol)
+ screen.refresh ()
+
+ # Interface to the display thread
+ def startdisplay (self):
+ """Start the wxPython display (GT40 emulation, essentially).
+ This is a NOP if wxPython is not available.
+ """
+ if not display:
+ atexit.register (enddisplay)
+ # Release the main thread, allowing it to start the display
+ dsem.release ()
+ else:
+ self.updatedisplay ()
+
+ def updatedisplay (self):
+ """Refresh the GT40 style display to reflect the current
+ buffer state around dot.
+ """
+ if display:
+ display.show ()
+
+ def hidedisplay (self):
+ """Turn off (hide) the GT40 display.
+ """
+ if display:
+ display.show (False)
+
+ def autoverify (self, flag):
+ """Handle automatic verify for the ES and EV flags. The input
+ is the flag in question.
+ """
+ if flag:
+ if flag == -1:
+ flag = 0
+ ch = flag & 255
+ if ch:
+ if ch < 32:
+ ch = lf
+ else:
+ ch = chr (ch)
+ flag >>= 8
+ start = self.buffer.line (-flag)
+ end = self.buffer.line (flag + 1)
+ sys.stdout.write (printable (self.buf[start:self.dot]))
+ if ch:
+ sys.stdout.write (ch)
+ sys.stdout.write (printable (self.buf[self.dot:end]))
+ sys.stdout.flush ()
+ self.screenok = False
+
+# A metaclass to allow non-alphanumeric methods to be defined, which
+# is handy when you use method names directly for command character
+# processing. Inspired by the Python Cookbook, chapter 20 intro.
+def _repchar (m):
+ return chr (int (m.group (1), 8))
+class Anychar (type):
+ def __new__ (cls, cname, cbases, cdict):
+ newnames = {}
+ charre = re.compile ("char([0-7]{3})")
+ for name in cdict:
+ newname, cnt = charre.subn (_repchar, name)
+ if cnt:
+ fun = cdict[name]
+ newnames[newname] = fun
+ cdict.update (newnames)
+ return super (Anychar, cls).__new__ (cls, cname, cbases, cdict)
+
+class qreg (object):
+ '''Queue register object. Stores text and numeric parts, with
+ methods to access each part.
+ '''
+ def __init__ (self):
+ self.num = 0
+ self.text = ""
+
+ def getnum (self):
+ return self.num
+
+ def setnum (self, val):
+ self.num = val
+
+ def getstr (self):
+ return self.text
+
+ def setstr (self, val):
+ self.text = val
+
+ def appendstr (self, val):
+ self.text += val
+
+# Atexit handlers. These are guarded so they can be called even
+# if the corresponding module isn't present.
+def endwin ():
+ """Close down curses mode.
+ """
+ global screen
+ if screen:
+ try:
+ curses.endwin ()
+ except:
+ pass
+ screen = None
+
+def enddisplay ():
+ """Stop wxPython display.
+ """
+ global display
+ if display:
+ display.stop ()
+
+if wxpresent:
+ pointsize = 12
+
+ class displayApp ():
+ """This class wraps the App main loop for wxPython.
+
+ Due to limitations in some OS (Mac OS at least), this
+ class must be created in the main thread -- the first
+ thread of the process. Furthermore, the "start" method
+ will create the application and run the main loop, and will
+ not return until application exit. So for any other things
+ that need to run in the meantime, like user interaction,
+ the caller will need to create an additional thread.
+
+ This class creates a 24 by 80 character window, and initializes
+ some common state such as the font used to display text
+ in the window.
+ """
+
+ def __init__ (self, teco):
+ self.running = False
+ self.teco = teco
+ self.displayline = 16
+
+ def start (self):
+ """Start the wx App main loop.
+ This finds a font, then opens up a Frame initially
+ sized for 80 by 24 characters.
+ """
+ global display
+ self.app = wx.App ()
+ self.font = wx.Font (pointsize, wx.FONTFAMILY_MODERN,
+ wx.FONTSTYLE_NORMAL,
+ wx.FONTWEIGHT_NORMAL)
+ dc = wx.MemoryDC ()
+ dc.SetFont (self.font)
+ self.fontextent = dc.GetTextExtent ("a")
+ cw, ch = self.fontextent
+ self.margin = cw
+ cw = cw * 80 + self.margin * 2
+ ch = ch * 24 + self.margin * 2
+ self.frame = displayframe (self, wx.ID_ANY, "TECO display",
+ wx.Size (cw, ch))
+ self.frame.Show (True)
+ self.running = True
+ self.app.MainLoop ()
+ # Come here only on application exit.
+ display = None
+
+ def show (self, show = True):
+ """If the display is active, this refreshes it to display
+ the current text around dot. If "show" is False, it tells
+ the display to go hide itself.
+ """
+ if self.running:
+ self.frame.doShow = show
+ self.frame.doRefresh = True
+ wx.WakeUpIdle ()
+
+ def stop (self):
+ """Stop the display thread by closing the Frame.
+ """
+ if self.running:
+ self.running = False
+ self.frame.AddPendingEvent (wx.CloseEvent (wx.wxEVT_CLOSE_WINDOW))
+
+ class displayframe (wx.Frame):
+ """Simple text display window class derived from wxFrame.
+ It handles repaint, close, and timer events. The timer
+ event is used for the blinking text cursor.
+
+ When instantiated, this class creats the window using the
+ supplied size, and starts the cursor blink timer.
+ """
+ def __init__ (self, display, id, name, size):
+ framestyle = (wx.MINIMIZE_BOX |
+ wx.MAXIMIZE_BOX |
+ wx.RESIZE_BORDER |
+ wx.SYSTEM_MENU |
+ wx.CAPTION |
+ wx.CLOSE_BOX |
+ wx.FULL_REPAINT_ON_RESIZE)
+ wx.Frame.__init__ (self, None, id, name, style = framestyle)
+ self.SetClientSize (size)
+ timerId = 666
+ self.Bind (wx.EVT_PAINT, self.OnPaint)
+ self.Bind (wx.EVT_CLOSE, self.OnClose)
+ self.Bind (wx.EVT_TIMER, self.OnTimer)
+ self.Bind (wx.EVT_IDLE, self.OnIdle)
+ self.display = display
+ self.cursor = None, None, False
+ self.timer = wx.Timer (self, timerId)
+ self.timer.Start (500)
+ self.cursorState = True
+ self.doRefresh = False
+ self.SetBackgroundColour (wx.WHITE)
+
+ def OnIdle (self, event = None):
+ """Used to make a refresh happen, if one has been requested.
+ """
+ if self.doRefresh:
+ self.doRefresh = False
+ self.Show (self.doShow)
+ if self.doShow:
+ self.Refresh ()
+
+ def OnTimer (self, event = None):
+ """Draw a GT40-TECO style cursor: vertical line with
+ a narrow horizontal line across the bottom, essentially
+ an upside-down T.
+
+ If dot is between a CR and LF, the cursor is drawn upside
+ down (right side up T) at the left margin.
+ """
+ x, y, flip = self.cursor
+ if x is not None:
+ cw, ch = self.display.fontextent
+ if self.cursorState:
+ pen = wx.BLACK_PEN
+ else:
+ pen = wx.WHITE_PEN
+ self.cursorState = not self.cursorState
+ dc = wx.ClientDC (self)
+ dc.SetPen (pen)
+ if flip:
+ dc.DrawLine (x, y, x, y - ch)
+ dc.DrawLine (x - cw / 2, y - ch, x + cw / 2 + 1, y - ch)
+ else:
+ dc.DrawLine (x, y, x, y - ch)
+ dc.DrawLine (x - cw / 2, y, x + cw / 2 + 1, y)
+
+ def OnPaint (self, event = None):
+ """This is the event handler for window repaint events,
+ which is also done on window resize. It fills the window
+ with the buffer contents, centered on dot.
+
+ Line wrap is indicated in GT40 fashion: the continuation line
+ segments have a right-pointing arrow in the left margin.
+ """
+ dc = wx.PaintDC (self)
+ dc.Clear ()
+ dc.SetFont (self.display.font)
+ w, h = dc.GetSize ()
+ w -= 2 * self.display.margin
+ h -= 2 * self.display.margin
+ cw, ch = self.display.fontextent
+ w //= cw
+ h //= ch
+ lines, currow, curcol = self.display.teco.screentext (h, w, h // 2)
+ if curcol > len (lines[currow][0]):
+ self.cursor = self.display.margin, \
+ (currow + 2) * ch + self.display.margin, \
+ True
+ else:
+ self.cursor = curcol * cw + self.display.margin, \
+ (currow + 1) * ch + self.display.margin, \
+ False
+ wrap = False
+ dc.SetPen (wx.BLACK_PEN)
+ for row, line in enumerate (lines):
+ y = self.display.margin + row * ch
+ if wrap:
+ y2 = y + ch - ch / 2
+ dc.DrawLine (1, y2, cw - 1, y2)
+ dc.DrawLines ([ wx.Point (cw / 2, y2 - cw / 3),
+ wx.Point (cw - 1, y2),
+ wx.Point (cw / 2, y2 + cw / 3 + 1)])
+ line, wrap = line
+ dc.DrawText (line, self.display.margin, y)
+
+ def OnClose (self, event = None):
+ """Close the GT40 window, and stop the cursor blink timer.
+ """
+ self.timer.Stop ()
+ self.cursor = None, None
+ self.Destroy ()
+
+# Nice hairy regexp for scanning across bracketed constructs looking
+# for the end of a range (conditional or iteration). It doesn't bother
+# looking for parentheses since none of the constructs we have to scan
+# for ("else" or condition end, or iteration end, or label) are allowed
+# inside parentheses -- and it isn't the job of this scanner to catch
+# illegal commands. For the same reason, it doesn't do things like
+# look for missing arguments, or invalid q-reg names, etc.
+#
+# The recipe here goes like this: the first half is for @-modified commands,
+# so it matches string arguments wrapped in matching delimiters.
+# The second half is the corresponding set of rules for non-@-modified
+# commands, so they have escape as the string terminator, except for
+# those oddballs that use something else, like ctrl/a. It also covers
+# the cases of commands that don't take string arguments and thus
+# don't care about @ modifiers
+#
+# The indenting is meant to show grouping. This pattern must be compiled
+# with the "verbose" flag.
+#
+# This pattern is subsequently modified to make three very similar patterns:
+# one to scan across iterations, one to scan across conditionals, and
+# one to search for tags (labels). A single base pattern is used to
+# form all three, so I don't have to keep three almost-identical copies
+# of these things in sync.
+basepat = """
+ # First any commands that take string arguments, @ modified flavor
+ (?:(?:@(?:\\:*(?:(?:f(?:(?:[cns_](.).*?\\1.*?\\1)|
+ (?:[br](.).*?\\2)|
+ .))|
+ (?:e(?:[bginrw_](.).*?\\3|.))|
+ # Control A and Control U in uparrow form
+ (?:\\^(?:(?:a(.).*?\\4)|
+ (?:u\\.?.(.).*?\\5)|.))|
+ # Tag start is included here, so tags are skipped
+ # The ! is removed for tag search so tags are
+ # not skipped there.
+ (?:[\001!inos_](.).*?\\6)|
+ (?:\025\\.?.(.).*?\\7))))|
+ # Next commands that take string arguments, no @
+ (?:(?:f(?:(?:[cns_].*?\033.*?\033)|
+ (?:[br].*?\033)|
+ .))|
+ (?:e(?:[bginrw_].*?\033|.))|
+ # Control A, Control U, Control ^ in uparrow form
+ (?:\\^(?:(?:a.*?\001)|
+ (?:u\\.?..*?\025)|
+ (?:\\^.)|.))|
+ (?:[inos_].*?\033)|
+ (?:\001.*?\001)|
+ # At this point we insert one of several subexpressions,
+ # depending on what we need: a pattern to skip tags,
+ # or a pattern to skip condition starts, or both, or
+ # neither
+ ### insert here
+ (?:\025\\.?..*?\033)|
+ (?:\036.)|
+ (?:[][%gmqux]\\.?.)|
+ # The tilde is replaced by the terminator character set
+ [^~]))*
+ """
+# These two can be inserted into basepat at "### insert here"
+marker = "### insert here"
+exclpat = "(?:!.*?!)|"
+dqpat = '(?:".)|'
+
+# These are the terminator sets, inserted at two places into basepat to
+# specify what set of characters terminates the scan
+iterset = "<>"
+condset = "\"|\'<>"
+tagset = "!<>"
+
+# Construct the three patterns
+iterpat = basepat.replace (marker, exclpat + dqpat).replace ('~', iterset)
+condpat = basepat.replace (marker, exclpat).replace ('~', condset)
+tagpat = basepat.replace ("!", "").replace (marker, dqpat).replace ('~', tagset)
+
+iterre = re.compile (iterpat, re.IGNORECASE | re.DOTALL | re.VERBOSE)
+condre = re.compile (condpat, re.IGNORECASE | re.DOTALL | re.VERBOSE)
+tagre = re.compile (tagpat, re.IGNORECASE | re.DOTALL | re.VERBOSE)
+
+class iter (object):
+ '''State for command iterations.
+ '''
+ def __init__ (self, teco, cmd, count):
+ self.start = cmd.cmdpos
+ self.count = count
+ self.cmd = cmd
+ self.teco = teco
+
+ def again (self, atend = True, delta = 1):
+ if self.count:
+ self.count -= delta
+ if not self.count:
+ if not atend:
+ self.cmd.skipiter ()
+ if self.teco.trace:
+ sys.stdout.write ('>')
+ sys.stdout.flush ()
+ self.cmd.iterstack.pop ()
+ return
+ self.cmd.cmdpos = self.start
+ self.teco.clearargs ()
+
+# assorted regular expressions used below:
+
+# patterns for \ command, for the three possible radix values
+decre = re.compile (r'[+-]?\d+')
+octre = re.compile (r'[+-]?[0-7]+')
+hexre = re.compile (r'[+-]?[0-9a-f]+', re.IGNORECASE)
+
+# Patterns for the string builder, with and without ^x to control-x
+# conversion. Note that a single replacer function is used with
+# either pattern, so bldpat must be a superset of buildpatnoup,
+# and the common groups must come first and in the same order.
+_bldpat = re.compile('''
+ (?:(?:(?:\\^[qr])|[\021\022])(.))| # ^Qx or ^Rx
+ (?:(?:(?:\\^e)|\005)q(\\.?.))| # ^EQq
+ (?:(?:(?:\\^e)|\005)u(\\.?.))| # ^EUq
+ (?:(?:(?:\\^v)|\026)(.))| # ^Vx
+ (?:(?:(?:\\^w)|\027)(.))| # ^Wx
+ (?:\\^(.)) # ^x
+ ''', re.IGNORECASE |re.DOTALL | re.VERBOSE)
+_bldpatnoup = re.compile('''
+ (?:[\021\022](.))| # ^Qx or ^Rx
+ (?:\005q(\\.?.))| # ^EQq
+ (?:\005u(\\.?.))| # ^EUq
+ (?:\026(.))| # ^Vx
+ (?:\027(.)) # ^Wx
+ ''', re.IGNORECASE | re.DOTALL | re.VERBOSE)
+
+# pattern for the search string to search regexp converter
+_searchpat = re.compile ('''
+ # A regexp special character (must be quoted)
+ ([][\\\\^$.?+(){}])|
+ # ^ES -- One or more spaces/tabs; ^EX -- any char
+ # These two do not accept ^N
+ ((?:\005[sx])|\030)|
+ # Check for leading ^N (inverse match)
+ (?:(\016)?
+ (?:
+ # ^EGq -- table match, with optional ^N
+ (?:\005g(\\.?.))|
+ # All other special match characters
+ ((?:\005[abcdlrvwx])|\023)))|
+ # Check for ^EE -- regexp match (teco.py addition)
+ (?:\005e(.+))
+ ''', re.IGNORECASE | re.DOTALL | re.VERBOSE)
+
+# Substitution dictionary for the special match characters
+#
+# These are regexp subexpressions corresponding to TECO match patterns
+_searchdict2 = { ctrle + "s" : "[ \t]+",
+ ctrle + "x" : ".",
+ ctrlx : "." }
+
+# These are rexexp character class expressions, so they go inside
+# [...], or [^...] if ^N was present in the TECO string
+_searchdict5 = { ctrle + "a" : "A-Za-z",
+ ctrle + "b" : "\\W",
+ ctrle + "c" : "\\w$_.",
+ ctrle + "d" : "\d",
+ ctrle + "l" : eol,
+ ctrle + "r" : "\\w",
+ ctrle + "v" : "a-z",
+ ctrle + "w" : "A-Z",
+ ctrls : "\\W"}
+
+class command_level(metaclass=Anychar):
+ '''This state handles a single command level (interactive or macro
+ execution) for TECO.
+
+ Any method with a one-character name is the handler for the
+ corresponding TECO command. Two-character methods are for two-
+ character TECO command names (the dispatch is via the one-character
+ method matching the start character; for example method "fb" is
+ invoked via method "f").
+
+ TECO command characters that are not valid Python symbol names
+ are represented by methods with "charnnn" in the name. The metaclass
+ creates synonyms for those methods with the real name, which is
+ the character with octal char code nnn. For example, char042 is
+ the " (double quote) command method, and fchar074 is the f< command
+ method.
+ '''
+ def __init__ (self, teco, q = None):
+ self.qregs = q or { }
+ self.teco = teco
+ self.enlist = [ ]
+ self.enstring = ""
+ self.iterstack = [ ]
+
+ # Define a bunch of properties for cleaner access to state that
+ # is kept in other places.
+ # First the ones that are common across all command levels, and
+ # are kept by the "teco" class:
+ atmod = commonprop ("atmod")
+ arg2 = commonprop ("arg2")
+ colons = commonprop ("colons")
+ ctrlxflag = commonprop (ctrlx)
+ edflag = commonprop ("ed")
+ etflag = commonprop ("et")
+ radix = commonprop ("radix")
+ laststringlen = commonprop ("laststringlen")
+ lastsearch = commonprop ("lastsearch")
+ lastfilename = commonprop ("lastfilename")
+ trace = commonprop ("trace")
+ buffer = commonprop ("buffer")
+ screenok = commonprop ("screenok")
+
+ # Now the ones that relate to the text buffer, so they are kept
+ # by the "buffer" class:
+ buf = bufprop ("text")
+ dot = bufprop ("dot")
+ end = bufprop ("end")
+ eoflag = bufprop ("eoflag")
+ ffflag = bufprop ("ffflag")
+
+ def do (self, c):
+ """Execute the single teco command named by the argument
+ (a single character, or a two-character string for TECO
+ commands that have two character names). The method for that
+ command is invoked, if it exists; otherwise error ILL
+ (Illegal command) is raised.
+
+ The command name is passed as argument to the method, which is
+ useful when several commands (e.g., all the digits) are
+ bound to a single method.
+ """
+ c = c.lower ()
+ try:
+ op = getattr (self, c)
+ except AttributeError:
+ raise ILL (self.teco, c)
+ op (c)
+
+ def tracechar (self, c):
+ """Show the supplied character (or string) as trace text,
+ if tracing is enabled.
+ """
+ if self.trace:
+ sys.stdout.write (printable (c))
+ sys.stdout.flush ()
+
+ def peeknextcmd (self):
+ """Look at the next command character, without advancing
+ the current command pointer.
+ """
+ try:
+ return self.command[self.cmdpos]
+ except IndexError:
+ return ""
+
+ def nextcmd (self):
+ """Get the next command character; if there isn't one,
+ error UTC (Unterminated Command) is raised.
+ """
+ c = self.peeknextcmd ()
+ if not c:
+ raise UTC (self.teco)
+ self.tracechar (c)
+ self.cmdpos += 1
+ return c
+
+ def colon (self):
+ """Return True if colon modifier(s) are present.
+ """
+ return self.colons != 0
+
+ def getarg (self, c, default = None):
+ '''Get the command argument. If there is no argument, the
+ default argument governs what happens. If no default is
+ supplied, the function returns None. If a default value is
+ supplied, that value is returned. Otherwise, the default argument
+ should be an exception class, and that exception is raised.
+ This function is used for cases where the command does not return
+ a value; it requires that any argument is complete (matching
+ parentheses, right hand side present for a pending operator).
+ '''
+ ret = self.teco.getarg (c)
+ if default is not None:
+ self.clearargs ()
+ if ret is None:
+ # Yuck. If exceptions were new style classes
+ # I wouldn't need this ugly mess!
+ if type (default) is type (Exception):
+ raise default (self.teco)
+ ret = default
+ return ret
+
+ def getoptarg (self, c):
+ '''Get the command argument. Return None if it was not present.
+ This function may be called when we are in the middle of an
+ expression; that is intended for the case where a command may return
+ a value that is then in turn part of an expression.
+ '''
+ return self.teco.getoptarg (c)
+
+ def getargs (self, c, default = None):
+ """Get the command argument pair, as a pair. If there was
+ only one argument, the first element of the pair is None.
+ If there was no argument at all, or nothing after the comma,
+ the supplied default is used for the second element of the pair
+ in the same way as for method getarg.
+ """
+ arg2 = self.arg2
+ return arg2, self.getarg (c, default)
+
+ def getargc (self, c, default = None):
+ """Get the command argument and the colon modifier, as a pair.
+ If there was no argument, the supplied default is used for the
+ first element of the pair in the same way as for method getarg.
+ """
+ col = self.colon ()
+ return self.getarg (c, default), col
+
+ def getargsc (self, c, default = None):
+ """Get the command argument pair and the colon flag, as a tuple.
+ If there was only one argument, the first element of the pair is None.
+ If there was no argument at all, or nothing after the comma,
+ the supplied default is used for the second element of the pair
+ in the same way as for method getarg.
+ """
+ arg2 = self.arg2
+ col = self.colon ()
+ return arg2, self.getarg (c, default), col
+
+ def setval (self, n):
+ """Set the command result value into the expression state.
+ """
+ self.teco.setval (n)
+
+ def clearargs (self):
+ """Clear the expression state and command modifiers.
+ """
+ self.teco.clearargs ()
+
+ def clearmods (self):
+ """Clear the command modifier flags (colon and at sign).
+ """
+ self.teco.clearmods ()
+
+ def bitflag (self, c):
+ """Process a bit flag command, such as ET. See teco.bitflag
+ for details.
+ """
+ self.teco.bitflag (c)
+
+ def numflag (self, c):
+ """Process a numeric flag command, such as EV. See teco.numflag
+ for details.
+ """
+ self.teco.numflag (c)
+
+ def strarg (self, c, term = esc):
+ """Return the string argument for the command. If the at sign
+ modifier is in effect, the next character in the command string
+ is the delimiter. Otherwise, the term argument specifies the
+ delimiter, or ESC is used if term is omitted.
+ """
+ if self.atmod:
+ term = self.nextcmd ()
+ self.atmod = False
+ s = self.cmdpos
+ try:
+ e = self.command.index (term, s)
+ except ValueError:
+ raise UTC (self.teco, c)
+ self.cmdpos = e + 1
+ self.tracechar (self.command[s:self.cmdpos])
+ return self.command[s:e]
+
+ def strargs (self, c):
+ """Return a pair of string arguments for the command. If the at
+ sign modifier is in effect, the next character in the command
+ string is the delimiter. Otherwise, the delimiter is ESC.
+ """
+ term = esc
+ if self.atmod:
+ term = self.peeknextcmd ()
+ s1 = self.strarg (c)
+ return s1, self.strarg (c, term)
+
+ def makecontrol (self, c):
+ """Return the control character correponding to the supplied
+ character; for example, 'a' produces control/A.
+ """
+ n = ord (c)
+ if 0o100 <= n <= 0o137 or 0o141 <= n <= 0o172:
+ return chr (n & 31)
+ else:
+ raise IUC (self.teco, chr (n))
+
+ def _strbuildrep (self, m):
+ if m.group (1):
+ # ^Qx or ^Rx is literally x
+ return m.group (1)
+ elif m.group (2):
+ # ^EQq is text of Q-reg q
+ return self.qregstr (m.group (2))
+ elif m.group (3):
+ # ^EUq is character whose code is in numeric Q-reg q
+ return chr (self.qreg (m.group (3)).getnum ())
+ elif m.group (4):
+ # ^Vx is lowercase x
+ return m.group (4).lower ()
+ elif m.group (5):
+ # ^Vx is uppercase x
+ return m.group (5).upper ()
+ else:
+ # ^x is control-x
+ return self.makecontrol (m.group (6))
+
+ def strbuild (self, s):
+ """TECO string builder. This processes uparrow/char combinations,
+ unless bit 0 in ED is set. It also handles string build
+ characters such as ^Qx (literal x), ^EQq (text in q-reg q), etc.
+ """
+ if self.edflag & 1:
+ pat = _bldpatnoup
+ else:
+ pat = _bldpat
+ return pat.sub (self._strbuildrep, s)
+
+ def _str2rerep (self, m):
+ if m.group (1):
+ return '\\' + m.group (1)
+ elif m.group (2):
+ return _searchdict2[m.group (2).lower ()]
+
+ inverse = m.group (3) is not None
+ if m.group (4):
+ # ^EGq -- table match
+ charset = set (self.qregstr (m.group (4)))
+ pfx = sfx = ''
+ if not charset:
+ return ""
+ if not inverse and len (charset) == 1:
+ c = ''.join (charset)
+ if c in "][\\^$.?+(){}":
+ c = '\\' + c
+ return c
+ if ']' in charset:
+ charset -= set (']')
+ pfx = ']'
+ if '\\' in charset:
+ charset -= set ('\\')
+ pfx += '\\'
+ if '-' in charset:
+ sfx = '-'
+ charset -= set ('-')
+ c = pfx + ''.join (charset) + sfx
+ elif m.group (5):
+ c = _searchdict5[m.group (5).lower ()]
+ else:
+ # ^EE -- regexp pattern. Return it exactly as written.
+ return m.group (6)
+ if inverse:
+ return "[^%s]" % c
+ else:
+ return "[%s]" % c
+
+ def str2re (self, s):
+ """Convert a TECO search string to the equivalent
+ regular expression string.
+ """
+ reflags = re.DOTALL
+ if self.ctrlxflag == 0:
+ reflags |= re.IGNORECASE
+ return re.compile (_searchpat.sub (self._str2rerep, s), reflags)
+
+ def isinteractive (self):
+ '''Return True if executing at the interactive level
+ as opposed to in a macro.
+ '''
+ return self is self.teco.interactive
+
+ def skip (self, pat):
+ '''Skip based on a regexp, starting at the current command
+ position. Updates command position to be one character beyond
+ the end of the match, and returns the character after the match,
+ if any. If no match, returns None.
+
+ The reason for passing over an extra character is that the regexp
+ is coded to terminate on one of the characters we want to look
+ for -- for example, ! < > for tag search. It would make sense
+ to include that set at the end of the regexp, but if you do that
+ then the match attempt can take a very long time if there is no
+ match. (It seems to take exponential time!) To avoid that,
+ the regexp instead describes what we want to skip, and then
+ picks up, skips over, and returns the character after that.
+ '''
+ m = pat.match (self.command, self.cmdpos)
+ if not m:
+ return None
+ self.cmdpos = m.end () + 1
+ try:
+ return self.command[self.cmdpos - 1]
+ except IndexError:
+ return None
+
+ def skipiter (self):
+ '''Skip across nested iterations to the end of the current
+ iteration.
+ '''
+ level = 1
+ while level > 0:
+ tail = self.skip (iterre)
+ if not tail:
+ raise UTC (self.teco, '<')
+ if tail == '<':
+ level += 1
+ else:
+ level -= 1
+
+ def skipcond (self, c):
+ '''Skip across conditional code for the specified end string.
+ Nested conditionals are skipped. Nested iterations are
+ skipped but scanned, because iterations can overlap conditionals.
+ '''
+ while True:
+ tail = self.skip (condre)
+ if not tail:
+ raise MAP (self.teco)
+ if tail in c:
+ break
+ else:
+ # We stopped on something other than what we wanted to skip to.
+ # There are two possibilities: it is the start of an inner
+ # range (either condition or iteration), or it is the end
+ # of some range.
+ #
+ # We can't just recursively skip nested ranges because
+ # of this warped case:
+ # < 0A"A C > '
+ #
+ # So instead, nested conditions are just skipped, but
+ # iterations are handled by stacking a simulated start of
+ # iteration with a repeat count of one onto the iteration
+ # stack and continuing the scan in-line. The count of
+ # one means that this case also works somewhat sanely:
+ # "A < xxx ' >
+ # I suspect that's not legal, but who knows...
+ if tail == '<':
+ self.iterstack.append (iter (self.teco, self, 1))
+ elif tail == '"':
+ self.cmdpos += 1
+ self.skipcond ("'")
+ elif tail == '>':
+ # Found an iteration end. Pop it off the iteration stack
+ try:
+ self.iterstack.pop ()
+ except IndexError:
+ raise BNI (self.teco)
+
+ def findtag (self, c):
+ '''Search for the specified tag, starting at the current
+ command position. Nested iterations are skipped (not searched),
+ so if the tag is in one of those it will not be found.
+ '''
+ while True:
+ tail = self.skip (tagre)
+ if not tail:
+ raise TAG (self.teco, c)
+ if tail == '!':
+ term = '!'
+ if self.command[self.cmdpos-2] == '@':
+ term = self.nextcmd ()
+ if self.command.startswith (c + term, self.cmdpos):
+ self.cmdpos += len (c) + 1
+ return
+ try:
+ e = self.command.index (term, self.cmdpos)
+ self.cmdpos = e + 1
+ except ValueError:
+ raise UTC (self.teco, '!')
+ elif tail == '<':
+ p = self.cmdpos
+ self.skipiter ()
+ else:
+ # Found an iteration end. Pop it off the iteration stack
+ try:
+ self.iterstack.pop ()
+ except IndexError:
+ raise BNI (self.teco)
+
+ def run (self, s):
+ self.command = s
+ self.cmdpos = 0
+ self.iterstack = [ ]
+ try:
+ while self.cmdpos < len (self.command):
+ c = self.nextcmd ()
+ self.do (c)
+ except ExitLevel:
+ pass
+ except KeyboardInterrupt:
+ raise XAB (self.teco)
+
+ def search (self, s, n, start, end, colon, topiffail = True,
+ nextpage = None):
+ """Search in the current buffer for a given string.
+ Stop on the abs(n)th occurrence. If n is negative, search
+ is backward, starting at 'end'; otherwise it is forward,
+ starting at 'start'. The search range is bounded by
+ the range (start, end). If 'nextpage' is specified, it is
+ called if we run out of stuff to match in the current buffer,
+ continuing until end of file. Note that 'nextpage' is only
+ meaningful for forward searches (n > 0); it is ignored for
+ backward searches.
+
+ Note: start and end are the range of buffer positions where
+ the match is allowed to begin, inclusive.
+
+ If the search succeeds, dot is set to the end of the
+ match string, and the ^S variable is set to the negative of
+ the matched length. (I.e., .+^S is the start of the match.)
+ Finally, if 'colon' is true, the current arg is set to -1.
+
+ If the search fails, a bunch of things can happen.
+
+ If topiffail is True or omitted, and the 16 bit is clear in
+ the ED flag, dot is set to zero.
+
+ If 'colon' is true, the current arg is set to 0.
+ The same happens if we're in an iteration, and the next command
+ character is a semicolon.
+
+ Otherwise, if we're in an iteration, a warning message is
+ generated and the iteration is exited (as if a semicolon
+ had been next). If we're not in an iteration, an error
+ ?SRH is generated.
+ """
+ rep = abs (n)
+ if n < 0:
+ pos = end
+ laststart = None
+ # We don't allow paging for reverse searches
+ nextpage = None
+ else:
+ pos = start
+ if s:
+ s = self.strbuild (s)
+ self.lastsearch = s
+ else:
+ s = self.lastsearch
+ re = self.str2re (s)
+ # Bind the buffer text to a local variable to help speed
+ # up the inner loop
+ buf = self.buf
+ while rep:
+ if n < 0:
+ # This is painful. There is no reverse search for
+ # regular expressions, so we do it the hard way,
+ # by repeatedly matching, stepping backwards one
+ # character at a time...
+ #
+ # Note to self: a different way that's probably faster
+ # but harder to do: reverse the string, reverse the
+ # regexp pattern, "unreverse" any [...] and [...]+
+ # inside the regexp, and do an ordinary search with those.
+ # Then some extra work is needed to find any matches
+ # that straddle the search start point (i.e., dot).
+ tmatch = re.match (buf, pos)
+ if tmatch and not (laststart and tmatch.end () > laststart):
+ match = tmatch
+ laststart = match.start ()
+ else:
+ if pos:
+ pos -= 1
+ continue
+ match = None
+ else:
+ match = re.search (buf, pos)
+ if match and not start <= match.start () <= end:
+ match = None
+ if match is None:
+ # If we have a nextpage function and we're not
+ # at the end of the input file, keep going
+ if nextpage and self.eoflag == 0:
+ nextpage ()
+ buf = self.buf
+ start = 0
+ pos = 0
+ end = self.end
+ continue
+ if topiffail and (self.edflag & 16) == 0:
+ self.buffer.goto (0)
+ if colon:
+ self.setval (0)
+ return False
+ elif self.iterstack:
+ self.setval (0)
+ if self.peeknextcmd () != ';':
+ print("%Search fail in iter")
+ # pretend there was a ;
+ self.do (';')
+ return False
+ else:
+ raise SRH (self.teco, s)
+ rep -= 1
+
+ # We found what we were looking for. "match" is a regexp
+ # match object for the matched string.
+ self.buffer.goto (match.end ())
+ self.laststringlen = -(match.end () - match.start ())
+ # Supply the success value if asked for, or if a ; follows
+ if colon or self.iterstack and self.peeknextcmd () == ';':
+ self.setval (-1)
+ self.teco.autoverify (self.teco.es)
+ return True
+
+ def failedcommand (self):
+ """Return the command string up to the point where execution
+ was aborted.
+ """
+ return self.command[:self.cmdpos]
+
+ def lastcommand (self):
+ """Return the command string, in full.
+ """
+ return self.command
+
+ def qregname (self):
+ """Parse a Q-register name from the command string. If the
+ next character is dot, the name is dot plus the character
+ after that; otherwise it is just the next character.
+
+ Note that the name is not validated here; the caller does that
+ if necessary.
+ """
+ c = self.nextcmd ()
+ if c == '.':
+ c += self.nextcmd ()
+ return c.lower ()
+
+ def qdict (self, c):
+ """Return the Q-reg dictionary referenced by the supplied Q-reg
+ name. If the Q-reg name begins with dot, this is the local
+ Q-reg dictionary for the current command level; otherwise it
+ is the TECO-global dictionary.
+
+ Note that the per-level dictionary is not necessarily unique
+ to the level; a colon-modified M command creates a new one,
+ an unmodified M command binds to the one of the invoking level.
+ """
+ if c.isalnum ():
+ return self.teco.qregs
+ elif c[0] == '.' and c[1].isalnum ():
+ return self.qregs
+ else:
+ raise IQN (self.teco, c)
+
+ def qreg (self, c = None):
+ """Return the Q-reg named by the argument, or by the command
+ string if the argument is omitted. If the Q-reg does not yet
+ exist, it is created (with no text and 0 numeric value).
+ """
+ if c:
+ c = c.lower ()
+ else:
+ c = self.qregname ()
+ qd = self.qdict (c)
+ if c not in qd:
+ qd[c] = qreg ()
+ return qd[c]
+
+ def qregstr (self, c = None):
+ '''Return the string value of the specified Q-register,
+ or the last filename string if *, or the last search string
+ if _ was specified for the Q-register name.
+ '''
+ if c is None:
+ t = self.peeknextcmd ()
+ if t in "*_":
+ c = t
+ self.nextcmd ()
+ if c == '*':
+ return self.lastfilename
+ elif c == '_':
+ return self.lastsearch
+ else:
+ return self.qreg (c).getstr ()
+
+ def setqreg (self, q):
+ """Set the Q-reg named by the command string to be the supplied
+ Q-reg. This is used by the ]q (pop Q-reg) command.
+ """
+ c = self.qregname ()
+ qd = self.qdict (c)
+ qd[c] = q
+
+ # From here on we have the actual command handlers. Their names
+ # come in two forms. Commands whose names are alphabetic are
+ # given by functions whose names are simply the command name.
+ # Other commands are given by functions whose names contain
+ # "charnnn" where nnn is the octal character code.
+
+ # a few control chars, and space, are nop
+ def nop (self, c): pass
+ char000 = nop # null (^@)
+ char070 = nop # bell (^G)
+ char012 = nop # line feed (^J)
+ char014 = nop # form feed (^L)
+ char015 = nop # carriage return (^M)
+ char040 = nop # space
+
+ def char001 (self, c): # ^A
+ """^A command -- print text.
+ """
+ s = self.strarg (c, '\001')
+ sys.stdout.write (s)
+ sys.stdout.flush ()
+ self.screenok = False
+ self.clearargs ()
+
+ def char002 (self, c): # ^B
+ """Return the current date. Since we pretend to be RT-11 it
+ would make sense to return the RT-11 format date, but that
+ utterly falls apart starting with 2004 (32 years from 1972)
+ so use the RSX/VMS format instead, which is substantially
+ more Y2K-proof.
+ """
+ now = time.localtime ()
+ self.setval ((now.tm_year - 1900) * 512 + now.tm_mon * 32 + now.tm_mday)
+
+ def char003 (self, c): # ^C
+ """^C command -- exit TECO if done at the interactive level;
+ stop execution and return to interactive prompt otherwise.
+ """
+ if self.isinteractive ():
+ self.exit ()
+ else:
+ raise ExitExecution
+
+ def char004 (self, c): # ^D
+ """^D command -- set radix to decimal.
+ """
+ self.radix = 10
+ self.clearargs ()
+
+ def char005 (self, c): # ^E
+ """^E command -- return form feed flag.
+ """
+ self.setval (self.ffflag)
+
+ def char006 (self, c): # ^F
+ """^F command -- return switch register. We just make it zero
+ for lack of switches...
+ """
+ self.setval (0)
+
+ def char010 (self, c): # ^H
+ """Return the current time of day. Match ^B, so we'll do
+ RSX/VMS format here, too. Amusingly, that happens to be
+ the RT-11 format, too.
+ """
+ now = time.localtime ()
+ self.setval (now.tm_hour * 3600 + now.tm_min * 60 + now.tm_sec)
+
+ def char011 (self, c): # tab
+ """Tab command -- insert text including the leading tab.
+ """
+ s = self.strarg (c)
+ self.buffer.insert (tab + s)
+ self.clearargs ()
+
+ def char016 (self, c): # ^N
+ """^N command -- return end of file flag.
+ """
+ self.setval (self.eoflag)
+
+ def char017 (self, c): # ^O
+ """^O command -- set radix to octal.
+ """
+ self.radix = 8
+ self.clearargs ()
+
+ def char021 (self, c): # ^Q
+ """^Q command -- return character offset corresponding to
+ the line offset supplied as the argument.
+ """
+ self.setval (self.buffer.line (self.getarg (c, 1)))
+
+ def char022 (self, c): # ^R
+ """^R -- Set the radix to the supplied value, which must
+ be 8, 10, or 16.
+ """
+ r = self.getoptarg (c)
+ if r is None:
+ self.clearmods ()
+ self.setval (self.radix)
+ else:
+ self.clearargs ()
+ if r in (8, 10, 16):
+ self.radix = r
+ else:
+ raise IRA (self.teco)
+
+ def char023 (self, c): # ^S
+ """^S command -- return the negative of the length of the
+ last string matched, set as replacement, or inserted.
+ """
+ self.setval (self.laststringlen)
+
+ def char024 (self, c): # ^T
+ """^T command. If an argument is given, output the character
+ with that numeric value (in raw mode if colon is present).
+ Otherwise, read a character from input and return its
+ numeric code.
+
+ If bit 5 in ET is set, return -1 if there is no input; otherwise
+ wait for it. (TODO)
+ """
+ colon = self.colon ()
+ n = self.getoptarg (c)
+ if n is None:
+ self.clearmods ()
+ if (self.etflag & 32) and self.teco.cmdhandler.eifile is None:
+ # TODO -- nowait char fetch from terminal
+ n = -1
+ else:
+ n = ord (self.teco.cmdhandler.getch ())
+ self.setval (n)
+ else:
+ self.clearargs ()
+ if colon:
+ sys.stdout.write (chr (n))
+ else:
+ sys.stdout.write (printable (chr (n)))
+ self.screenok = False
+ sys.stdout.flush ()
+
+ def char025 (self, c): # ^U
+ """^U command -- set Q-reg text.
+ """
+ q = self.qreg ()
+ s = self.strarg (c)
+ if self.colon ():
+ q.appendstr (s)
+ else:
+ q.setstr (s)
+ self.clearargs ()
+
+ def char026 (self, c): # ^V
+ pass
+
+ def char027 (self, c): # ^W
+ pass
+
+ char030 = numflag # ^X
+
+ def char031 (self, c): # ^Y
+ """^Y command -- synonym of ^S+.,.
+ """
+ self.clearargs ()
+ self.arg2 = self.dot + self.laststringlen
+ self.setval (self.dot)
+
+ def char032 (self, c): # ^Z
+ """^Z command -- This is supposed to be total Q-reg text size.
+ Just return 0 for now.
+ """
+ self.setval (0)
+
+ def char033 (self, c): # esc
+ """ESCAPE -- exit the current level if $$, otherwise clear
+ out any expression value and modifiers.
+ """
+ try:
+ if self.peeknextcmd () == esc:
+ raise ExitLevel
+ except UTC:
+ pass
+ self.clearargs ()
+
+ def char036 (self, c): # ^^
+ """^^ command -- return the numeric value of the following character
+ in the command string.
+ """
+ self.setval (ord (self.nextcmd ()))
+
+ def char037 (self, c): # ^_
+ """^_ command -- return one's complement of the argument.
+ """
+ self.setval (~self.getarg (c, NAB))
+
+ def char041 (self, c): # !
+ """! command -- tag (O command target) or comment.
+ """
+ self.strarg (c, '!')
+
+ def char042 (self, c): # "
+ '''" command -- conditional execution range start.
+ '''
+ n = self.getarg (c, NAQ)
+ if 0 <= n < 0x110000:
+ nc = chr (n)
+ else:
+ nc = ""
+ c = self.nextcmd ().lower ()
+ if c == 'a':
+ cond = nc.isalpha ()
+ elif c == 'c':
+ cond = nc.isalnum () or nc in "$._"
+ elif c == 'd':
+ cond = nc.isdigit ()
+ elif c in "efu=":
+ cond = n == 0
+ elif c in "g>":
+ cond = n > 0
+ elif c in "lst<":
+ cond = n < 0
+ elif c in "n":
+ cond = n != 0
+ elif c == 'r':
+ cond = nc.isalnum ()
+ elif c == 'v':
+ cond = nc.islower ()
+ elif c == 'w':
+ cond = nc.isupper ()
+ else:
+ raise IQC (self.teco)
+ if not cond:
+ self.skipcond ("|'")
+ self.tracechar (self.command[self.cmdpos - 1])
+
+ def char045 (self, c): # %
+ """% command -- increment Q-reg numeric value by the specified
+ amount, and return the result.
+ """
+ n = self.getoptarg (c)
+ if n is None:
+ n = 1
+ q = self.qreg ()
+ n += q.getnum ()
+ q.setnum (n)
+ self.setval (n)
+
+ def char047 (self, c): # '
+ """' command -- conditional range end.
+ """
+ pass
+
+ def char050 (self, c): # (
+ """( command -- expression grouping.
+ """
+ self.teco.leftparen ()
+
+ def char051 (self, c): # )
+ """) command -- expression grouping.
+ """
+ self.teco.rightparen ()
+
+ def operator (self, c):
+ """Arithmetic operators. All the operators are bound to
+ this method; the command character (which is the argument)
+ distinguishes them.
+ """
+ self.teco.operator (c)
+
+ char043 = operator # #
+ char046 = operator # &
+ char052 = operator # *
+ char053 = operator # +
+ char055 = operator # -
+ char057 = operator # /
+
+ def char054 (self, c): # ,
+ """, command -- second operand marker.
+ """
+ if self.arg2 is None:
+ n = self.getarg (c, ARG)
+ if n < 0:
+ raise NCA (self.teco)
+ self.arg2 = n
+ else:
+ raise ARG (self.teco)
+
+ def char056 (self, c): # .
+ """. command -- current buffer position.
+ """
+ self.setval (self.dot)
+
+ def digit (self, c):
+ """Digits are handled by this method. All digit methods are
+ bound to this method, and distinguished by the command
+ character argument.
+ """
+ self.teco.digit (c)
+
+ char060 = digit
+ char061 = digit
+ char062 = digit
+ char063 = digit
+ char064 = digit
+ char065 = digit
+ char066 = digit
+ char067 = digit
+ char070 = digit
+ char071 = digit
+
+ def char072 (self, c): # :
+ """: command -- modifier.
+ """
+ self.colons = 1
+ if self.peeknextcmd () == ':':
+ self.nextcmd ()
+ self.colons = 2
+
+ def char073 (self, c): # ;
+ """; command -- iteration exit.
+ """
+ n, colon = self.getargc (c, NAS)
+ if not self.iterstack:
+ raise SNI (self.teco)
+ if (not colon and n >= 0) or (colon and n < 0):
+ self.skipiter ()
+ self.tracechar ('>')
+ self.iterstack.pop ()
+
+ def char074 (self, c): # <
+ """< command -- iteration start.
+ """
+ n = self.getarg (c)
+ self.clearargs ()
+ if n is None:
+ self.iterstack.append (iter (self.teco, self, 0))
+ elif n <= 0:
+ self.skipiter ()
+ self.tracechar ('>')
+ else:
+ self.iterstack.append (iter (self.teco, self, n))
+
+ def char075 (self, c): # =
+ """= command -- display the argument in decimal.
+ == command -- display the argument in octal.
+ === command -- display the argument in hex.
+
+ CRLF is added after the value unless : modifier is given.
+ """
+ n, colon = self.getargc (c, NAE)
+ if colon:
+ term = ""
+ else:
+ term = lf
+ if self.peeknextcmd () == '=':
+ self.nextcmd ()
+ if self.peeknextcmd () == '=':
+ self.nextcmd ()
+ sys.stdout.write ("%x%s" % (n, term))
+ else:
+ sys.stdout.write ("%o%s" % (n, term))
+ else:
+ sys.stdout.write ("%d%s" % (n, term))
+ self.screenok = False
+ sys.stdout.flush ()
+
+ def char076 (self, c): # >
+ """< command -- iteration end.
+ """
+ if not self.iterstack:
+ raise BNI (self.teco)
+ self.clearargs ()
+ self.iterstack[-1].again ()
+
+ def char077 (self, c): # ?
+ """? command -- toggle trace flag.
+ """
+ self.trace = not self.trace
+
+ def char100 (self, c): # @
+ """@ command -- modifier (explicitly supplied string delimiter).
+ """
+ self.atmod = True
+
+ def a (self, c):
+ """A command -- append (if no argument) or return numeric value
+ of character in the text buffer (if argument is given, which is
+ the offset from dot).
+ """
+ n, colon = self.getargc (c)
+ if n is None:
+ self.clearargs ()
+ ret = self.buffer.append ()
+ if colon:
+ self.setval (ret)
+ else:
+ pos = self.dot + n
+ if 0 <= pos < self.end:
+ self.setval (ord (self.buf[pos]))
+ else:
+ self.setval (-1)
+
+ def b (self, c):
+ """B command -- zero (start of buffer).
+ """
+ self.setval (0)
+
+ def c (self, c):
+ """C command -- move forward n characters.
+ """
+ newpos = self.dot + self.getarg (c, 1)
+ if 0 <= newpos <= self.end:
+ self.buffer.goto (newpos)
+ else:
+ raise POP (self.teco, c)
+
+ def d (self, c):
+ """D command -- delete n characters. If two arguments are
+ given, delete that range of characters.
+ """
+ # TODO: two args
+ m, n = self.getargs (c, 1)
+ if m is None:
+ end = self.dot + n
+ if 0 <= end <= self.end:
+ if n < 0:
+ self.buffer.goto (end)
+ n = -n
+ if n:
+ self.buffer.delete (n)
+ else:
+ raise POP (self.teco, c)
+ else:
+ if 0 <= m <= n <= self.end:
+ self.buffer.goto (m)
+ self.buffer.delete (n - m)
+ else:
+ raise POP (self.teco, c)
+ self.clearmods ()
+
+ def e (self, c):
+ """E command -- two character command starting with E.
+ """
+ c = self.nextcmd ()
+ try:
+ self.do ('e' + c)
+ except ILL:
+ raise IEC (self.teco, c)
+
+ def ea (self, c):
+ """EA command -- switch to alternate output stream.
+ """
+ self.buffer.ea ()
+
+ def eb (self, c):
+ """EB command -- open file for editing (input/output, with
+ backup).
+ """
+ fn = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ self.clearargs ()
+ ret = self.buffer.eb (fn, colon)
+ if colon:
+ self.setval (ret)
+
+ def ec (self, c):
+ """EC command -- finish with the current file. If input and
+ output files are open, write remainder of the input to output,
+ then close both.
+ """
+ self.buffer.ec ()
+ self.clearargs ()
+
+ ed = bitflag
+ eh = numflag
+
+ def ef (self, c):
+ """EF command -- close current output file, without any writing.
+ """
+ self.buffer.ef ()
+
+ def eg (self, c):
+ """EG command -- OS dependent action.
+
+ Right now this does nothing.
+ """
+ cmd = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ # TODO: do something
+ if colon:
+ self.setval (0)
+
+ def ei (self, c):
+ """EI command -- read command input from a file.
+ """
+ fn = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ self.clearargs ()
+ ret = self.teco.cmdhandler.ei (fn, colon)
+ if colon:
+ self.setval (ret)
+
+ def ej (self, c):
+ """EJ command -- return environment parameters.
+ """
+ n = self.getarg (c, 0)
+ if n == -1:
+ self.setval (CPU * 256 + OS)
+ elif n == 0:
+ # Don't return too big a number or some things get confused
+ # We use the parent pid, because that's fairly constant
+ # for a given session -- just like the "job" number for
+ # classic DEC operating systems.
+ self.setval (os.getppid () & 255)
+ elif n == 1:
+ self.setval (0)
+ elif n == 2:
+ self.setval (os.getuid ())
+ else:
+ raise ARG (self.teco)
+
+ def ek (self, c):
+ """EK command -- discard output file.
+ """
+ self.buffer.ek ()
+
+ def en (self, c):
+ """EN command -- set wildcard pattern to match, or return
+ next match value.
+ """
+ cmd = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ if len (cmd):
+ self.enlist = glob.glob (cmd)
+ self.enstring = cmd
+ elif self.enlist:
+ self.lastfilename = self.enlist[0]
+ del self.enlist[0]
+ if colon:
+ self.setval (-1)
+ else:
+ if colon:
+ self.setval (0)
+ else:
+ raise FNF (self.teco, self.enstring)
+
+ def eo (self, c):
+ """EO command -- return TECO version number.
+ """
+ self.setval (VERSION)
+
+ def ep (self, c):
+ """EP command -- set alternate input stream.
+ """
+ self.buffer.ep ()
+
+ def er (self, c):
+ """ER command -- open input file.
+ """
+ fn = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ self.clearargs ()
+ ret = self.buffer.er (fn, colon)
+ if colon:
+ self.setval (ret)
+
+ es = numflag
+ et = bitflag
+ eu = numflag
+ ev = numflag
+
+ def ew (self, c):
+ """EW command -- open output file.
+ """
+ fn = self.strbuild (self.strarg (c))
+ colon = self.colon ()
+ self.clearargs ()
+ ret = self.buffer.ew (fn, colon)
+ if colon:
+ self.setval (ret)
+
+ def ex (self, c):
+ """EX command -- finish with files (effect of EC command)
+ then exit TECO.
+ """
+ self.ec (c)
+ self.exit ()
+
+ def exit (self):
+ # Release the main thread, allowing it to start the display
+ global exiting
+ exiting = True
+ if dsem:
+ dsem.release ()
+ sys.exit ()
+
+ def ey (self, c = None):
+ """EY command -- yank unconditionally.
+ """
+ self.buffer.yank (False)
+
+ def f (self, c):
+ """F command -- two character command starting with F.
+ """
+ c = self.nextcmd ()
+ try:
+ self.do ('f' + c)
+ except ILL:
+ raise IFC (self.teco, c)
+
+ def fchar047 (self, c): # f'
+ """F' command -- 'flow' to end of conditional.
+ """
+ self.clearargs ()
+ self.skipcond ("'")
+ self.tracechar ("'")
+
+ def fchar074 (self, c): # f<
+ """F< command -- 'flow' to start of iteration. Not like
+ 'continue' in C, it starts another iteration without
+ decrementing the count of iterations to do.
+ """
+ if not self.iterstack:
+ raise BNI (self.teco)
+ self.iterstack[-1].again (False, 0)
+
+ def fchar076 (self, c): # f>
+ """F> command -- 'flow' to end of iteration. Like
+ 'continue' in C, it decrements the count of iterations
+ left to do, and does another if there are any left.
+ """
+ if not self.iterstack:
+ raise ExitLevel
+ self.iterstack[-1].again (False)
+
+ def fb (self, c):
+ """FB command -- bounded search.
+ """
+ s = self.strarg (c)
+ m, n, colon = self.getargsc (c)
+ if m is None:
+ m = self.dot
+ n = m + self.buffer.line (n)
+ count = 1
+ if m > n:
+ count = -1
+ m, n = n, m
+ self.search (s, count, m, n, colon, False)
+
+ def fc (self, c):
+ """FC command -- bounded search and replace.
+ """
+ s, rep = self.strargs (c)
+ m, n, colon = self.getargsc (c)
+ self.clearargs ()
+ if m is None:
+ m = self.dot
+ n = m + self.buffer.line (n)
+ count = 1
+ if m > n:
+ count = -1
+ m, n = n, m
+ if self.search (s, count, m, n, colon, False):
+ self.buffer.goto (self.dot + self.laststringlen)
+ self.buffer.delete (-self.laststringlen)
+ self.buffer.insert (rep)
+
+ def fr (self, c):
+ """FR command -- replace string previously matched or
+ inserted with the specified string.
+ """
+ rep = self.strarg (c)
+ self.buffer.goto (self.dot + self.laststringlen)
+ self.buffer.delete (-self.laststringlen)
+ self.buffer.insert (rep)
+
+ def fs (self, c):
+ """FS command -- search and replace.
+ """
+ s, rep = self.strargs (c)
+ colons = self.colons
+ topiffail = colons < 2
+ m, n, colon = self.getargsc (c, 1)
+ if not n:
+ raise ISA (self.teco)
+ if m == 0:
+ m = None
+ topiffail = False
+ if n < 0:
+ start, end = 0, self.dot
+ if m is not None:
+ start = end - abs (m)
+ else:
+ start, end = self.dot, self.end
+ if m is not None:
+ end = start + abs (m)
+ if colons > 1:
+ start = self.dot
+ end = self.dot
+ nextpage = None
+ if c == "fn":
+ nextpage = self.buffer.page
+ elif c == "f_":
+ nextpage = self.y
+ if self.search (s, n, start, end, colon, topiffail, nextpage):
+ self.buffer.goto (self.dot + self.laststringlen)
+ self.buffer.delete (-self.laststringlen)
+ self.buffer.insert (rep)
+
+ fn = fs
+ fchar137 = fs # f_
+
+ def fchar174 (self, c): # f|
+ """F| command -- 'flow' to the Else part of a conditional.
+ Exits the condition if there isn't an else part.
+ """
+ self.clearargs ()
+ self.skipcond ("|'")
+
+ def g (self, c):
+ """G command -- get text from the specified Q-register and
+ put it in the text buffer. Print the text if colon-modified.
+ Special name * means the last file spec, _ means the last
+ search string.
+ """
+ c = self.peeknextcmd ()
+ s = self.qregstr ()
+ if self.colon ():
+ sys.stdout.write (s)
+ sys.stdout.flush ()
+ self.screenok = False
+ else:
+ self.buffer.insert (s)
+ self.clearargs ()
+
+ def h (self, c):
+ """H command -- represents the wHole buffer.
+ Synonym for B,Z.
+ """
+ self.clearargs ()
+ self.arg2 = 0
+ self.setval (self.end)
+
+ def i (self,c):
+ """I command -- insert a string. If no string argument is
+ supplied, inserts the character whose numeric value is
+ given as the numeric argument.
+ """
+ n = self.getarg (c)
+ s = self.strarg (c)
+ if len (s) == 0:
+ if n is not None:
+ s = chr (n)
+ elif n is not None:
+ raise IIA (self.teco)
+ self.buffer.insert (s)
+ self.clearargs ()
+
+ def j (self, c):
+ """J command -- move to the specified offset in the buffer.
+ """
+ self.buffer.goto (self.getarg (c, 0))
+
+ def k (self, c):
+ """K command -- delete n lines. If two arguments are given,
+ delete the range of characters between those two positions.
+ """
+ m, n = self.teco.lineargs (c)
+ self.buffer.goto (m)
+ self.buffer.delete (n - m)
+ self.clearargs ()
+
+ def l (self, c):
+ """L command -- move the specified number of lines.
+ """
+ self.buffer.goto (self.buffer.line (self.getarg (c, 1)))
+
+ def m (self, c):
+ """M command -- macro execution. Executes the TECO commands
+ in the specified Q-register. If colon-modified, the new
+ execution level gets its own set of local Q-registers
+ (ones whose names start with . ) -- otherwise the new level
+ shares the local Q-registers of the current level.
+ """
+ q = self.qreg ()
+ if self.colon ():
+ i = command_level (self.teco, self.qregs)
+ self.clearmods ()
+ else:
+ i = command_level (self.teco)
+ i.run (q.getstr ())
+
+ def o (self, c):
+ """O command -- go to the specified tag in the command string.
+ If an argument is supplied, go to that tag in the list of tags
+ given in the string argument, e.g., 2Ofoo,bar,baz$ goes to
+ tag !baz!. If the argument is out of range, execution just
+ continues.
+ """
+ tag = self.strbuild (self.strarg (c))
+ n = self.getarg (c)
+ self.clearargs ()
+ if not len (tag):
+ raise ILL (self.teco, c)
+ if n is not None:
+ n -= 1
+ tags = tag.split (',')
+ if not 0 <= n < len (tags):
+ return
+ tag = tags[n]
+ if self.iterstack:
+ self.cmdpos = self.iterstack[-1].start
+ else:
+ self.cmdpos = 0
+ self.findtag (tag)
+
+ def p (self, c):
+ """P command -- page ahead the specified number of pages
+ in the input file, writing to the output file in the process.
+
+ PW command -- write the current buffer to the output file.
+ """
+ m, n, colon = self.getargsc (c, 1)
+ c2 = self.peeknextcmd ().lower ()
+ if m is not None or c2 == 'w':
+ if c2 == 'w':
+ self.nextcmd ()
+ if m is not None:
+ part = m, n
+ repeat = 1
+ else:
+ part = None
+ repeat = n
+ if n <= 0:
+ raise IPA (self.teco)
+ for i in range (repeat):
+ self.buffer.writepage (part)
+ else:
+ if n <= 0:
+ raise IPA (self.teco)
+ for i in range (n):
+ ret = self.buffer.page ()
+ if colon:
+ self.setval (ret)
+
+ def q (self, c):
+ """Q command -- return the numeric value in the specified Q-register.
+ If an argument is given, return the ASCII value of the
+ character in the text part of the Q-register at the specified
+ offset (counting from zero).
+ """
+ colon = self.colon ()
+ n = self.getoptarg (c)
+ q = self.qreg ()
+ if colon:
+ self.clearmods ()
+ self.setval (len (q.getstr ()))
+ elif n is not None:
+ self.clearargs ()
+ qstr = q.getstr ()
+ if 0 <= n < len (qstr):
+ n = ord (qstr[n])
+ else:
+ n = -1
+ self.setval (n)
+ else:
+ self.clearmods ()
+ self.setval (q.getnum ())
+
+ def r (self, c):
+ """R command -- move backward by the specified number of
+ character positions.
+ """
+ newpos = self.dot - self.getarg (c, 1)
+ if 0 <= newpos <= self.end:
+ self.buffer.goto (newpos)
+ else:
+ raise POP (self.teco, c)
+
+ def s (self, c):
+ """S command -- search for a string. If colon modified,
+ return -1 if ok, 0 if no match. If :: modified, it's a
+ match operation rather than a search (pointer never moves).
+ """
+ s = self.strarg (c)
+ colons = self.colons
+ topiffail = colons < 2
+ m, n, colon = self.getargsc (c, 1)
+ if not n:
+ raise ISA (self.teco)
+ if m == 0:
+ m = None
+ topiffail = False
+ if n < 0:
+ start, end = 0, self.dot
+ if m is not None:
+ start = end - abs (m)
+ else:
+ start, end = self.dot, self.end
+ if m is not None:
+ end = start + abs (m)
+ if colons > 1:
+ start = self.dot
+ end = start
+ nextpage = None
+ if c == "n":
+ nextpage = self.buffer.page
+ elif c == "_":
+ nextpage = self.y
+ elif c == "e_":
+ nextpage = self.ey
+ self.search (s, n, start, end, colon, topiffail, nextpage)
+
+ echar137 = s # e_
+ n = s
+ char137 = s # _
+
+ def t (self, c):
+ """T command -- type the specified number of lines.
+ """
+ m, n = self.teco.lineargs (c)
+ sys.stdout.write (printable (self.buf[m:n]))
+ sys.stdout.flush ()
+ self.screenok = False
+ self.clearargs ()
+
+ def u (self, c):
+ """U command -- set the numeric part of the Q-register
+ to the specified value.
+ """
+ q = self.qreg ()
+ q.setnum (self.getarg (c, NAU))
+
+ def v (self, c):
+ """V command -- display the current line, with n lines to each
+ side of it if argument n is supplied, or m before and n after
+ if argument pair m,n is given.
+ """
+ m, n = self.getargs (c, 1)
+ start = self.buffer.line (1 - (m or n))
+ end = self.buffer.line (n)
+ sys.stdout.write (printable (self.buf[start:end]))
+ sys.stdout.flush ()
+ self.teco.screenok = False
+
+ def w (self, c):
+ """W command -- watch the buffer contents.
+
+ If wxPython is available, a wxPython window is opened showing
+ the current buffer around dot, which will be updated as the
+ buffer changes or dot moves, until further notice. 0W will
+ stop the display.
+
+ If wxPython is not available but curses is, the buffer contents
+ will be displayed using screen control sequences on the current
+ terminal. It is updated only when another W command is issued.
+
+ Also, in that mode, :W does lots of magical things; refer to
+ the manual for all the details.
+ """
+ m, n, colon = self.getargsc (c)
+ if wxpresent:
+ if n is None:
+ self.teco.startdisplay ()
+ elif n == 0:
+ self.teco.hidedisplay ()
+ elif cursespresent:
+ if colon:
+ if n is None:
+ n = 0
+ if n & -256:
+ # insert until...
+ if not n & 1:
+ self.teco.watch ()
+ term = m and [ m & 255, m >> 8 ]
+ if n & 2:
+ m.append (9)
+ while True:
+ ch = screen.getch ()
+ if ch == 3:
+ if self.etflag & 32768:
+ self.etflag &= -32768
+ else:
+ raise XAB (self.teco)
+ if (n & 64) or \
+ (ch != 9 and ch < 32) or ch > 126 or \
+ (term and ch in term):
+ break
+ c = chr (ch)
+ if n & 4:
+ c = c.upper ()
+ self.buffer.insert (c)
+ if not n & 32:
+ self.teco.watch ()
+ self.setval (ch)
+ return
+ if not 0 <= n <= 7:
+ raise ARG (self.teco)
+ if m is None:
+ self.setval (self.teco.watchparams[n])
+ else:
+ if n:
+ self.teco.watchparams[n] = m
+ else:
+ if n is None:
+ endwin ()
+ else:
+ if n == 0:
+ n = 16
+ if n > 0:
+ self.teco.curline = n
+ else:
+ if n == -1000:
+ self.screenok = True
+ self.teco.watch ()
+ else:
+ raise ILL (self.teco, c)
+
+ def x (self, c):
+ """X command -- set the text part of the specified Q-register
+ from text in the buffer. If one numeric argument is present,
+ that is a number of lines. If two arguments are given, it
+ is the range of character positions in the buffer. If colon-
+ modified, the new text is appended to the existing Q-register
+ contents rather than replacing it.
+ """
+ colon = self.colon ()
+ m, n = self.teco.lineargs (c)
+ q = self.qreg ()
+ text = self.buf[m:n]
+ if colon:
+ q.appendstr (text)
+ else:
+ q.setstr (text)
+ self.clearargs ()
+
+ def y (self, c = None):
+ """Y command -- read the next page. If the buffer is not
+ empty, and there is an output file, refuse the operation unless
+ bit 1 is set in ED.
+ """
+ self.buffer.yank ((self.edflag & 2) == 0)
+
+ def z (self, c):
+ """Z command -- the number of characters in the buffer, or in
+ other words, the character position corresponding to the
+ end of the buffer.
+ """
+ self.setval (self.end)
+
+ def char133 (self, c): # [
+ """[ command -- push the specified Q-register onto the
+ Q-register stack.
+ """
+ # We have to make a copy of the Q register so that any later
+ # changes to the existing one are not also reflected in the
+ # pushed copy. A shallow copy suffices.
+ self.teco.qstack.append (copy.copy (self.qreg ()))
+
+ def char134 (self, c): # \
+ r"""\ command -- number/string conversion.
+
+ If an argument is supplied, convert that according to the
+ current radix, and insert it into the buffer. Note that ^S
+ is not updated to reflect that insertion.
+
+ If no argument is present, parse a number from the current
+ buffer position according to the current radix, and return that
+ number as a result. Dot is moved across whatever was parsed.
+ """
+ n = self.getoptarg (c)
+ if n is None:
+ self.clearmods ()
+ if self.radix == 8:
+ m = octre.match (self.buf, self.dot)
+ elif self.radix == 10:
+ m = decre.match (self.buf, self.dot)
+ else:
+ m = hexre.match (self.buf, self.dot)
+ if m is None:
+ n = 0
+ else:
+ n = int (m.group (0), self.radix)
+ self.dot = m.end ()
+ self.setval (n)
+ else:
+ self.clearargs ()
+ if self.radix == 8:
+ s = "%o" % n
+ elif self.radix == 10:
+ s = "%d" % n
+ else:
+ s = "%x" % n
+ self.buffer.insert (s)
+
+ def char135 (self, c): # ]
+ """] command -- pop the Q-register stack into the specified
+ Q-register.
+ """
+ colon = self.colon ()
+ if self.teco.qstack:
+ q = self.teco.qstack.pop ()
+ self.setqreg (q)
+ if colon:
+ self.setval (-1)
+ elif colon:
+ self.nextcmd ()
+ self.setval (0)
+ else:
+ raise PES (self.teco)
+
+ def char136 (self, c): # ^
+ """^ command -- take the next character as a control character,
+ for example '^S' is the same as 'control-S'.
+ """
+ self.do (self.makecontrol (self.nextcmd ()))
+
+ def char174 (self, c): # |
+ """| command -- marks the start of the 'else' part of
+ a conditional execution block.
+ """
+ self.skipcond ("'")
+
+class inputstream (object):
+ def __init__ (self, teco):
+ self.teco = teco
+ self.pages = ""
+ self.eoflag = -1
+ self.ffflag = 0
+ self.infile = False
+
+ def open (self, fn, colon):
+ fn = os.path.expanduser (fn)
+ try:
+ infile = open (fn, "rt", encoding = "utf8", errors = "ignore")
+ self.teco.lastfilename = fn
+ except IOError as err:
+ if colon:
+ return 0
+ if err.errno == 2:
+ raise FNF (self.teco, fn)
+ else:
+ raise FER (self.teco)
+ try:
+ indata = infile.read ()
+ except IOError:
+ raise INP (self.teco)
+ infile.close ()
+ self.pages = indata.split (ff)
+ self.infile = True # input file is "open"
+ self.infn = fn
+ self.eoflag = 0
+ return -1
+
+ def readpage (self):
+ if self.pages:
+ ret = self.pages[0].replace (lf, crlf)
+ del self.pages[0]
+ if len (self.pages):
+ self.ffflag = -1
+ self.eoflag = 0
+ else:
+ self.ffflag = 0
+ self.eoflag = -1
+ return ret, -1
+ else:
+ self.ffflag = 0
+ self.eoflag = -1
+ return "", 0
+
+class outputstream (object):
+ def __init__ (self, teco):
+ self.teco = teco
+ self.outfile = None
+
+ def open (self, fn, colon, scheck = True):
+ if self.outfile:
+ raise OFO (self.teco)
+ fn = os.path.expanduser (fn)
+ if scheck and not fn.lower ().endswith (".tmp") and os.path.isfile (fn):
+ print('%%Superseding existing file "%s"' % fn)
+ fd, self.tempfn = tempfile.mkstemp (text = True)
+ try:
+ self.outfile = open (fd, "wt", encoding = "utf8", errors = "ignore")
+ self.teco.lastfilename = fn
+ except IOError as err:
+ if colon:
+ return 0
+ raise FER (self.teco)
+ self.outfn = fn
+ return -1
+
+class buffer (object):
+ '''This class defines the TECO text buffer, and methods to manipulate
+ its contents.
+ '''
+ def __init__ (self, teco):
+ self.text = ""
+ self.dot = 0
+ self.teco = teco
+ self.ebflag = False
+ self.inputs = [ None, None ]
+ self.istream = 0
+ self.outputs = [ None, None ]
+ self.ostream = 0
+
+ laststringlen = commonprop ("laststringlen")
+
+ def insert (self, text):
+ self.text = self.text[:self.dot] + text + self.text[self.dot:]
+ self.dot += len (text)
+ self.laststringlen = -len (text)
+
+ def delete (self, len):
+ self.text = self.text[:self.dot] + self.text[self.dot + len:]
+
+ def goto (self, pos):
+ if pos < 0: pos = 0
+ if pos > len (self.text): pos = len (self.text)
+ self.dot = pos
+
+ def _end (self):
+ return len (self.text)
+
+ end = property (_end)
+
+ def _ffflag (self):
+ infile = self.inputs[self.istream]
+ if infile:
+ return infile.ffflag
+ else:
+ return 0
+
+ ffflag = property (_ffflag)
+
+ def _eoflag (self):
+ infile = self.inputs[self.istream]
+ if infile:
+ return infile.eoflag
+ else:
+ return -1
+
+ eoflag = property (_eoflag)
+
+ def line (self, linecnt):
+ pos = self.dot
+ if linecnt > 0:
+ while linecnt > 0:
+ try:
+ pos = self.text.index (lf, pos) + 1
+ except ValueError:
+ return len (self.text)
+ linecnt -= 1
+ return pos
+ else:
+ while linecnt <= 0:
+ try:
+ pos = self.text.rindex (lf, 0, pos)
+ except ValueError:
+ return 0
+ linecnt += 1
+ return pos + 1
+
+ def ea (self):
+ self.ostream = 1
+
+ def eb (self, fn,colon):
+ if self.outputs[self.ostream]:
+ raise OFO (self.teco)
+ ret = self.er (fn, colon)
+ if ret == -1:
+ ret = self.ew (fn, colon, False)
+ if ret == -1:
+ self.ebflag = True
+ return ret
+
+ def ec (self):
+ infile = self.inputs[self.istream]
+ outfile = self.outputs[self.ostream]
+ if outfile:
+ if infile:
+ while self.page () < 0:
+ pass
+ else:
+ self.writepage ()
+ self.text = ""
+ self.ef ()
+ elif self.end:
+ raise NFO (self.teco)
+
+ def ef (self):
+ infile = self.inputs[self.istream]
+ self.inputs[self.istream] = None
+ outfile = self.outputs[self.ostream]
+ if outfile:
+ if self.ebflag:
+ try:
+ os.remove (infile.infn + '~')
+ except:
+ pass
+ os.rename (infile.infn, infile.infn + '~')
+ self.ebflag = False
+ outfile.outfile.close ()
+ self.outputs[self.ostream] = None
+ os.rename (outfile.tempfn, outfile.outfn)
+
+ def ek (self):
+ outfile = self.outputs[self.ostream]
+ if outfile:
+ outfile.outfile.close ()
+ self.outputs[self.ostream] = None
+ os.remove (outfile.tempfn)
+ self.ebflag = False
+
+ def ep (self):
+ self.istream = 1
+
+ def er (self, fn, colon):
+ """ This opens an input file, reads the whole file, and breaks it
+ into pages.
+ I suppose that isn't really all that elegant, but unless the
+ file is humongous, it's fast enough these days, and it produces
+ the correct result.
+ """
+ if not len (fn):
+ self.istream = 0
+ return True
+ if not self.inputs[self.istream]:
+ self.inputs[self.istream] = inputstream (self.teco)
+ return self.inputs[self.istream].open (fn, colon)
+
+ def ew (self, fn, colon, scheck = True):
+ """This opens an output file. It creates the output file using
+ a temporary name, in the directory specified. The actual
+ desired name is saved, and will be set when the file is closed.
+ """
+ if not len (fn):
+ self.ostream = 0
+ return True
+ if not self.outputs[self.ostream]:
+ self.outputs[self.ostream] = outputstream (self.teco)
+ return self.outputs[self.ostream].open (fn, colon, scheck)
+
+ def yank (self, protect = True):
+ """Read another page into the text buffer. If 'protect' is
+ True or omitted, the operation is rejected if there is an
+ output file and the buffer is non-empty.
+ Returns -1 if there was more data to read, 0 if we were
+ at end of file already.
+ """
+ if protect and self.outputs[self.ostream] and self.text:
+ raise YCA (self.teco)
+ self.text = ""
+ ret = self.append ()
+ self.goto (0)
+ return ret
+
+ def append (self):
+ """Append another page to the text buffer.
+ """
+ infile = self.inputs[self.istream]
+ if not infile:
+ raise NFI (self.teco)
+ newstr, ret = infile.readpage ()
+ self.text += newstr
+ return ret
+
+ def writepage (self, part = None):
+ outfile = self.outputs[self.ostream]
+ if not outfile:
+ raise NFO (self.teco)
+ if part:
+ start, end = part
+ outfile.outfile.write (self.text[start:end].replace (crlf, lf))
+ else:
+ outfile.outfile.write (self.text.replace (crlf, lf))
+
+ def page (self):
+ """Write out the current page, and read the next.
+ """
+ infile = self.inputs[self.istream]
+ outfile = self.outputs[self.ostream]
+ self.writepage ()
+ if infile and infile.ffflag:
+ outfile.outfile.write (ff)
+ return self.yank (False)
+
+class command_handler (object):
+ '''Class for handling TECO input.
+
+ It handles terminal input as well as input from EI files,
+ either single characters, or a complete TECO command with
+ the usual special character processing.
+ '''
+ def __init__ (self, teco):
+ self.eifile = None
+ self.teco = teco
+
+ etflag = commonprop ("et")
+
+ def ei (self, fn, colon = False):
+ """EI file opener.
+
+ If the supplied file name does not contain a directory spec,
+ we look for the file in several places. The list of places to
+ look is given by environment variable TECO_PATH, if defined,
+ or PATH, if that is defined, or else Python's built in
+ default path. The first match is used; if all choices fail
+ then the EI fails (with a return status of 0 if colon-modified,
+ or error FNF otherwise).
+ """
+ if fn:
+ fn = os.path.expanduser (fn)
+ if self.eifile:
+ self.eifile.close ()
+ f = None
+ if not os.path.dirname (fn):
+ fn
+ for d in (os.environ.get("TECO_PATH",None) or
+ os.environ.get("PATH",None) or
+ os.defpath).split(os.pathsep):
+ realfn = os.path.join (d, fn)
+ try:
+ f = open (realfn, "r", encoding = "utf8",
+ errors = "ignore")
+ break
+ except IOError as err:
+ if err.errno == 2:
+ pass
+ else:
+ raise FER (self.teco)
+ else:
+ try:
+ f = open (fn, "r", encoding = "utf8", errors = "ignore")
+ realfn = fn
+ except IOError as err:
+ if err.errno == 2:
+ pass
+ else:
+ raise FER (self.teco)
+ if f:
+ self.eifile = f
+ elif colon:
+ return 0
+ else:
+ raise FNF (self.teco, fn)
+ else:
+ if self.eifile:
+ self.eifile.close ()
+ self.eifile = None
+ return -1
+
+ def getch (self, trap_ctrlc = True):
+ if self.eifile:
+ try:
+ c = self.eifile.read (1)
+ except IOError:
+ self.eifile = None
+ raise INP (self.teco)
+ if len (c):
+ if c == lf:
+ c = cr
+ return c
+ self.eifile.close ()
+ self.eifile = None
+ if screen and self.teco.incurses:
+ c = screen.getch ()
+ if c < 256:
+ c = chr (c)
+ else:
+ c = '\000'
+ else:
+ c = getch ()
+ if c == ctrlc and trap_ctrlc:
+ if self.etflag & 32768:
+ self.etflag &= 32767
+ else:
+ raise XAB (self.teco)
+ if c == cr:
+ sys.stdout.write (crlf)
+ elif c != rubchr:
+ sys.stdout.write (printable (c))
+ sys.stdout.flush ()
+ return c
+
+ def teco_cmdstring (self):
+ '''Get a command string using the TECO input conventions.
+ Text is accumulated until a double escape is seen. Control/U
+ and rubout are processed. Double control/G exits with a null
+ command (which will cause the main loop to prompt again).
+ '''
+ buf = ""
+ bellflag = False
+ escflag = False
+ immediate = True
+ while True:
+ c = self.getch (False)
+ if not self.eifile:
+ # Most special characters are only special if they
+ # come from the terminal, not from an EI file.
+ if immediate:
+ if c in "\010\012?":
+ print()
+ return c
+ elif c == '*':
+ c = self.getch (False)
+ if c.isalnum ():
+ print()
+ return '*' + c
+ buf = '*'
+ immediate = False
+ if c == bell:
+ if bellflag:
+ print()
+ return ""
+ bellflag = True
+ elif bellflag:
+ bellflag = False
+ if c == ' ':
+ buf = buf[:-1]
+ try:
+ start = buf.rindex (lf)
+ except ValueError:
+ start = 0
+ print()
+ sys.stdout.write (printable (buf[start:]))
+ sys.stdout.flush ()
+ continue
+ elif c == '*':
+ buf = buf[:-1]
+ print()
+ sys.stdout.write (printable (buf))
+ sys.stdout.flush ()
+ continue
+ if c == ctrlu:
+ print()
+ try:
+ ls = buf.rindex (lf)
+ buf = buf[:ls + 1]
+ except ValueError:
+ buf = ""
+ continue
+ elif c == rubchr:
+ if len (buf):
+ sys.stdout.write ("\010 \010")
+ if ord (buf[-1]) < 32 and buf[-1] != esc:
+ sys.stdout.write ("\010 \010")
+ buf = buf[:-1]
+ sys.stdout.flush ()
+ continue
+ if c == esc:
+ buf += c
+ if escflag:
+ if not self.eifile:
+ print()
+ return buf
+ escflag = True
+ continue
+ else:
+ escflag = False
+ if c == cr:
+ buf += crlf
+ else:
+ buf += c
+
+# Here's a rather primitive (but functional) teco command handler.
+# This one is used if we can't find a teco.tec anywhere.
+defmacro = \
+"""0ed 0^x ^d z"e @o/end/' j
+::@s/tec/"s 0u1 :@s*/i*"s -1u1 @fr// <::@s/^ea/; @fr//>'
+j :@s/^es/"f hk @o/end/' b,.k :@s/=/"f hx1 hk
+q1"f @eb/^eq1/ y @o/end/'
+@er/^eq1/ y @o/end/'
+@fr// .,zx1 @er/^eq1/ b,.x1 @ew/^eq1/ hk y @o/end/'
+::@s/mun/"s :@s/^es/"f @^a/?How can I MUNG nothing?
+/ ^c' b,.k :@s/,/"s @fr// 1+' 0"e zj' b,.x1 b,.k @ei/^eq1/ @o/end/'
+::@s/mak/"f @^a/?Illegal command "/ ht @^a/"
+/ ^c' :@s/^es/"f @^a/?How can I MAKE nothing?
+/ ^c' b,.k z-4"e ::@s/love/"s @^a/Not war?
+/ j'' hx1 hk @ew/^eq1/'
+!end!"""
+
+def main ():
+ global t
+ t = teco ()
+ arg0 = os.path.basename (sys.argv[0]).lower ()
+ if arg0.endswith (".py"):
+ arg0 = arg0[:-3]
+ elif arg0.endswith (".pyc"):
+ arg0 = arg0[:-4]
+ cmdline = " ".join ([ arg0 ] + sys.argv[1:])
+ t.buf = cmdline
+ if wxpresent:
+ # Need to create a new thread for interaction, then this
+ # (main) thread will own the window.
+ thr = threading.Thread (target = main2)
+ thr.start ()
+ global display, dsem
+ dsem = threading.Semaphore (value = 0)
+ # Wait for someone to ask for a display
+ dsem.acquire ()
+ if exiting:
+ return
+ # Now start the display
+ display = displayApp (t)
+ display.start ()
+ else:
+ main2 ()
+
+def main2 ():
+ #t.trace = True # *** for debug
+ if not t.cmdhandler.ei ("teco.tec", True):
+ try:
+ t.runcommand (defmacro)
+ except err as e:
+ e.show ()
+ t.mainloop ()
+
+if __name__ == "__main__":
+ main ()