The 8th Programming Environment

The 8th™ Programming Environment Language Manual ver. 16.14 Copyright © Aaron High-Tech, Ltd, All Rights Reserved 8th™ is a trademark of Aaron High-T...
13 downloads 0 Views 1004KB Size
The 8th™ Programming Environment Language Manual ver. 16.14

Copyright © Aaron High-Tech, Ltd, All Rights Reserved 8th™ is a trademark of Aaron High-Tech, Ltd

Table of Contents Chapter 1: Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.1 — Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6 1.2 — Installing 8th . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.3 — Starting and stopping 8th . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.4 — Running your programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.5 — Reporting bugs or other issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.6 — Updating 8th . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.7 — Differences between the 8th editions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Chapter 2: Introduction to 8th . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10 2.1 — Typographic conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10 2.2 — Terminological conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.3 — Some historical background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4 — Unique features of the 8th language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4.1 — Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4.2 — Interpreter or Compiler? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11 2.4.3 — Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.4.4 — Item types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.4.5 — Reference counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.4.6 — Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.5 — Getting help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.6 — About the name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 2.7 — Quick introduction for users of “mainstream” languages . . . . . . . . . . . . . . . . . . 13 Chapter 3: 8th’s syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.1 — Interpreter rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15 3.2 — Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16 3.3 — Special characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16 3.4 — Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.5 — Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.6 — Scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.7 — JSON Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 Chapter 4: Effective 8th . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.1 — Iterative refinement of code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.2 — Factoring code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.3 — Use the stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 4.4 — Faster code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21 Chapter 5: The data stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.1 — Basics of the stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.2 — Common stack words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.3 — Using the stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 5.4 — Extra stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Chapter 6: Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 6.1 — Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 6.2 — Survey of 8th data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 6.3 — Reference-counting and pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27 6.4 — Constant items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 6.5 — A note about data conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Chapter 7: Flow control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 7.1 — First things first! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 7.2 — Conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 7.3 — Repetition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

7.4 — Breaking up is easy to do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Chapter 8: Words, the interpreter and compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 8.1 — Named versus anonymous words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 8.2 — Deferred words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 8.3 — Word attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32 8.4 — Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Chapter 9: Numbers and math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33 9.1 — Big numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 9.2 — Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 9.3 — Manipulating numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 9.4 — Special numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 9.5 — Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35 Chapter 10: Text and strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 10.1 — What is a string? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36 10.2 — Manipulating a string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 10.3 — Internationalization and localization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37 10.4 — Search, replace and parameterized substitutions . . . . . . . . . . . . . . . . . . . . . . 37 10.5 — Strings vs. Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38 10.6 — Character encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 10.6.1 — macOS, IOS, Linux and Raspberry Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 10.6.2 — Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 10.6.3 — Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Chapter 11: Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .56 11.1 — Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 11.2 — Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 11.3 — Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 11.4 — Stacks, Queues and Heaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .57 Chapter 12: Files, databases, sockets, and various I/O . . . . . . . . . . . . . . . . . . . . . . . . . .58 12.1 — Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 12.2 — Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 12.3 — Sockets and network I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 12.4 — Serial I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60 12.5 — Bluetooth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Chapter 13: The 8th Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 13.1 — Editing keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 13.2 — TAB completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 13.3 — History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63 13.4 — The prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63 Chapter 14: Cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 14.1 — Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64 14.2 — Random data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 14.3 — Passwords and key generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 14.4 — Encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 14.4.1 — Public key encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 14.4.2 — Symmetric encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 14.4.3 — Diffie-Hellman and ECC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Chapter 15: Hardware query and control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 15.1 — General queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 15.2 — Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 15.2.1 — Raspberry Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 15.3 — Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 15.4 — GPIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67

15.5 — I2C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Chapter 16: FFI: Foreign Function Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 16.1 — Declaring and invoking FFI routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 16.2 — Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69 16.3 — Dealing with arbitrary data (“structs”, etc.) . . . . . . . . . . . . . . . . . . . . . . . . . . 69 16.4 — Custom libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 16.5 — Java interface (Android only) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 16.6 — Danger! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Chapter 17: Graphical User Interface: GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 17.1 — Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 17.2 — Defining a GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 17.3 — Overview of GUI items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 17.4 — GUI Attributes and events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 17.4.1 — Common attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 17.4.2 — Common events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 17.4.3 — Bounds expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 17.5 — GUI Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 17.5.1 — Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 17.5.2 — Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 17.5.3 — Code editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 17.5.4 — Color selector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 17.5.5 — Combo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 17.5.6 — Concertina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 17.5.7 — Edit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 17.5.8 — File browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82 17.5.9 — File name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 17.5.10 — Group box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 17.5.11 — HTML control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 17.5.12 — Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 17.5.13 — Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 17.5.14 — Lasso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .85 17.5.15 — List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 17.5.16 — Menu bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 17.5.17 — Preference panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 17.5.18 — Progress-bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 17.5.19 — Property panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .88 17.5.20 — Scroll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 17.5.21 — Slider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 17.5.22 — Splash screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 17.5.23 — Stack GUI container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 17.5.24 — System tray-icon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 17.5.25 — Tab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 17.5.26 — Table list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 17.5.27 — Toggle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94 17.5.28 — Toolbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 17.5.29 — Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 17.5.30 — View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .96 17.5.31 — Web browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97 17.5.32 — Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97 17.6 — Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 17.7 — Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98 17.8 — Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99

17.9 — Look and feel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104 Chapter 18: Tasks and parallelism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 18.1 — Introduction to tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 18.2 — Task stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 18.3 — Locking and unlocking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 18.4 — Using task queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 18.5 — Being a good citizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 18.6 — Parallelism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Chapter 19: Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109 19.1 — User-defined exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 19.2 — Built-in exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Chapter 20: Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 20.1 — Categories of problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 20.2 — Debugging techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Chapter 21: Standalone Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 21.1 — Application life-cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 21.2 — Setting up your application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 21.3 — Building the application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 21.3.1 — Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 21.3.2 — iOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 21.3.3 — macOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118 Chapter 22: Words by namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Chapter 23: Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 23.1 — crypto/root-certs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188 23.2 — crypto/totp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 23.3 — date/dst . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 23.4 — date/hebrew . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 23.5 — date/islamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189 23.6 — date/sunrise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189 23.7 — date/utils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 23.8 — geo/location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 23.9 — gui/skin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 23.10 — math/big . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 23.11 — math/comb-perm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 23.12 — math/complex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .191 23.13 — math/factorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 23.14 — math/gcd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192 23.15 — math/invmod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 23.16 — math/matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192 23.17 — net/basic-auth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192 23.18 — net/json-rpc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 23.19 — net/oath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 23.20 — net/soap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 23.21 — utils/os-names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .193 23.22 — utils/pdf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 23.23 — utils/settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194 Chapter 24: Error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 24.1 — Crypto error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .195 24.2 — SQLite error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 24.3 — File I/O and other POSIX error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197 24.4 — net: word error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

Chapter 1: Installation

1.1 Requirements 8th is known to run on the following systems: • Microsoft Windows XP, Windows 7/8/10 • macOS 10.7 and later • Linux - Ubuntu 12.04 and later, and derivatives or similar • Raspbian (Raspberry Pi version of Debian Linux; also works for similar embedded Linux systems) • Android 4.1 (API level 16, ARM devices) and later • iOS 7.0 and later The Raspberry Pi version may also run on other ARM-Linux based boards, and the Linux version may run on distributions other than Ubuntu derivatives; however, those are not specifically supported.

1.2 Installing 8th 8th is distributed in an all-inclusive “zip” file, which contains versions of 8th for all the platforms it supports. Your versions of 8th are licensed specifically to you. In order to use 8th, you will need to unpack the zip file into any folder which is accessible to you. There are a number of folders included in the zip: • bin

8th executables for all the supported platforms

• docs

The manual and tutorials in Adobe PDF format.

• libs

8th support libraries (8th code)

• samples Sample code to supplement the tutorials and manual. • keys The encryption keys for this version of 8th. Note: these keys are unique to each specific version of 8th you download, and they are important for the purpose of building deployable applications. Note that regardless of the platform on which you develop, you can produce applications for any platform supported by 8th. Once you have unpacked the zip file, you will need to take these steps: 1. On all platforms: open a terminal (command-window) and change directory to the 8th folder, just above bin. On Windows, run c:\windows\system32\cmd.exe or find the “command prompt” application and run it. Linux, macOS and RPI users simply open a terminal (bash shell, etc.) —6—

The 8th Manual: Installation

2. Run the 8th binary suitable to your platform and tell it to run the bin/inst.8th script. This script will copy the 8th distribution files to an OS and 8th version-specific folder. 3. Optionally update the PATH variable on your system (Windows users: the “inst” script can do this for you. Afterwards, you’ll need to close the terminal window and open a new one for the change to take effect) To run the bin/inst.8th script on 64-bit Linux for instance, type bin/lin64/8th bin/inst.8th

It is very important to run the “inst.8th” script every time you get a new release! If you do not, 8th will be unable to find its libraries or the help file, and it may be confusing when things don’t run as they should. The OS and 8th version-specific folder which the inst script wrote to can be determined by starting 8th and typing: app:8thdir . cr

This folder is for 8th’s exclusive use, and you should not remove or modify it as long as you are using that version of 8th on that computer.

1.3 Starting and stopping 8th The 8th command-line looks like this: 8th [options] [[-f] file...] [-e 'code'...]

Where the [-f] file option means “interpret the contents of the file”, and -e code means interpret the specific 8th code given. Both options may be given more than once on the command-line, and the effect is cumulative. In other words: 8th -f first.8th -f second.8th

will interpret the contents of the file first.8th and then interpret the contents of the file second.8th. Note that you do not need to say -f first.8th, you can instead just name the file; but only the first file on the command line will be run in that case, and only if no -f options were given. Here are the other options: -c -h -H -k -p -r -v

N N N ns N N

Set the maximum code size to N bytes Display help Set the console “history” size to N lines Set the data-stack size to N items Set the initial pool-size for namespace “ns” to N items Set the r-stack size to N items Print the 8th version and quit

In general you should not need to use the -c, -k -r or -p options, but they are provided in the event you find them useful. The code size is automatically grown if necessary, so the -c option is only needed if you want to avoid the necessity of 8th expanding code space. Similarly, pools are allocated when needed, so the -p option need only be used if you know that you will require more items simultaneously than the default pool size for that namespace (for example, if you will need 100000 numbers simultaneously, start 8th with the option -p n 100100 or something).

—7—

The 8th Manual: Installation

If you find you are using command-line switches often, you can simply use a “shell script” (on macOS or Linux), or a “batch file” (on Windows; also called a "“command file”) to start 8th with the options you prefer. Quitting out of 8th is simple enough. Do one of the following: • Type bye and hit ENTER. That will tell 8th to quit normally • Type 1 die and hit ENTER. That will tell 8th to quit abnormally and return the status-code 1 to the operating system • Press the key Ctrl+C twice in rapid succession. This tells 8th to quit immediately • In a GUI application, use g:quit to tell 8th to terminate the GUI event loop and quit the application • In a running application, invoking throw will cause an exception. If you were instead in the 8th console, you will be returned there; if running a file or a packaged application, a message will be printed and the app terminated.

1.4 Running your programs 8th can run your programs in several ways: • interactive: just start 8th and type in your code • script: put your code in a text file and run it using 8th mycode.8th (for example) • app: using the build script you can convert your code into an encrypted application, ready to deploy. The “trial version” produces time-limited applications so you can verify that your code runs on the target device. However, if you wish to deploy regular applications you will need one of the paid licenses. In the latter two scenarios, your code must be in a plain-text file (e.g. not a word-processing format). Any supporting files should be placed in the same folder as your code, or in a sub-folder of it. You can access those files in 8th by means of the app:asset word. An “app” is a standalone program which runs on its own and does not need to be run by 8th via the command-line. The contents are encrypted to help deter hackers. The details of producing standalone applications may be found in the section on using the “build” tool.

1.5 Reporting bugs or other issues When reporting a bug, please give as much detail as possible in the description. That will make it easier for us to understand the issue, reproduce, and address it. If you want us to contact you regarding the issue, please say so and tell us how. Please report bugs online in the bug-tracker: http://bugs.8th-dev.com/bugs.sh/home. If you must report confidential or proprietary information in your bug report, please send it via email to [email protected].

—8—

The 8th Manual: Installation

1.6 Updating 8th You can check to see if a new release of 8th is available by running the latest command like this: 8th bin/latest

If a newer release is available, it will ask if you want to download it. If you do, it will fetch the new version for you. Once you’ve got the new release (whether using this tool or in any other way), simply unpack the ZIP file in the same location as your current version. If you want to keep multiple versions of 8th, then you should unpack the ZIP in a different location. Afterwards, re-run the inst command as mentioned above: 8th bin/inst.8th

1.7 Differences between the 8th editions There are several distinct versions (SKUs) of 8th, which differ in their built-in functionality. For your reference, this is the current list of SKUs and their differentiating features: SKUs Feature: Free Hobby/Student Pro Enterprise Create regular binary X X X X Serial I/O X X X Sound support X X X Bluetooth support X X Custom look-and-feel X X Create encrypted binary X X MySQL and ODBC support X X Additional libraries X Priority support X In other words, the “Free” SKU will produce a regular (non-encrypted) binary, but does not support any of the other features listed above. You may upgrade from a less capable SKU to a more capable one by visiting the 8th upgrade page and following the instructions there. If you have difficulties using the upgrade page, or if you have special needs, please contact us at [email protected] and we will help you within two business days. Please note that all SKUs come with one year of free updates to the software. Once that year has completed, you will need to renew your update service by visiting the 8th update page and extending your service. Note further that if more than 90 days have elapsed since the end of your update year, you will have to purchase a full license again (rather than pay the substantially lower update fee). Updates are not required for you to continue using 8th or for your applications to continue to run. However, if you don’t update 8th you will miss out on bug fixes and new features.

—9—

Chapter 2: Introduction to 8th

8th is a secure cross-platform development language which lets you concentrate on your application’s logic instead of worrying about differences between platforms. It lets you write your code once, and simultaneously produce applications running on multiple platforms. Its built-in encryption helps protect your application from hackers. This manual covers all the features of the 8th language and product development environment. Its purpose is to explain in-depth all aspects of the product. If you note something missing or incorrect, please bring it to our attention.

2.1 Typographic conventions The following conventions are used in this manual: Code samples appear indented from the body text, in a monospace font: : sample "Code is monospace!" . ;

Built-in types like map are in a colored, monospace font. In stack-effect diagrams, a stack item in means that kind of item is read from the input-stream (either the 8th source code in a file or from the keyboard or standard-input if input is redirected). This symbol indicates items to which you should pay special attention!

2.2 Terminological conventions This manual uses some terms which are sometimes different from what you may be used to from other products. To make it clear what is meant, we present a short list of the possibly confusing terms: asset Anything packaged along with the code (fonts, graphics, etc) invoke “Execute”, “run” or “call” a word item Any of the data types known to 8th namespace A “vocabulary” of (usually) related words task The same as a “thread” or “co-routine” in other languages word The same as a “function” or “procedure” in other languages

2.3 Some historical background

— 10 —

The 8th Manual: Introduction to 8th

8th is based upon a much earlier language called Forth, which was initially designed in the early 1970s for controlling telescopes. Forth quickly found its niche in embedded systems because of its small size, low resource requirements, ease of porting to new hardware, and flexibility. Despite its many advantages Forth has remained a niche language, partly because of the lack of true standardization between versions. That lack led directly to the cynical observation, “if you’ve seen one Forth, you’ve seen one Forth”. 8th’s immediate ancestor is Reva Forth. Though 8th shares no source code with Reva, it was influenced by many of its ideas. Throughout this manual and the accompanying documentation, we refer to 8th as well as other implementations of the Forth language as “Forths”. Whether or not you are already familiar with Forths, you may benefit from working through the 8th tutorials, located in the tutorials sub-folder of the samples folder. 8th came about because Ron Aaron was looking for a development tool to help him write an application which he wanted to deploy on a variety of popular platforms. He searched far and wide for something appropriate. He tried a number of products, and found all of them lacking for his particular needs. So he started writing his own solution, basing it on ideas from his previous Reva Forth and from his decades of experience in the software field. The result is 8th. Though there is a Forth standard (actually, there are several), 8th does not adhere to it in any particulars, choosing instead to be inspired by Forth’s concepts while being more accessible to a wider audience. Most design decisions were made in the interest of keeping applications secure while providing freedom to accomplish normal programming tasks in a cross-platform and reasonable manner.

2.4 Unique features of the 8th language As a developer, you are probably familiar with a number of programming languages. Most of the ones in common use today are similar enough that one rarely has difficulty picking up the essentials. You may be intrigued, then, that 8th is different enough from what you are probably used to that you will need to pay close attention as you learn it. Take heart from the fact that it is not a difficult language. Here are some of the concepts which set 8th apart from most other languages: 2.4.1 Words The smallest unit of execution in most languages is a “function” or “procedure”. In Forths the equivalent is called a “word”. That is because Forths try to interpret any whitespace-delimited group of characters in the input. If that group of characters is a recognized “word”, a Forth will execute it. What that means will become clear in the next few sections. 2.4.2 Interpreter or Compiler? The most popular programming languages are either compiled (like C/C++) or interpreted (like JavaScript or PHP). Some languages (such as Java) are compiled in a two-phase process; first interpreting the source into an intermediate format which is then compiled “on-the-fly” at runtime (this is known as “JIT”, or “just-in-time” compilation). 8th operates in two modes: “interpretation” and “compilation”. When interpreting (by parsing words one by one and looking them up), it immediately executes the found code. When compiling, it produces native-code directly by compiling a call to the word. The precise details of 8th’s syntax and how its interpreter works may be found in the syntax reference. — 11 —

The 8th Manual: Introduction to 8th

Unlike most current languages, 8th does not perform any optimizations on your code, except for tail-call elimination. The reason is twofold. First, Ron’s experience is that optimizers often cause incorrect code; correctness and predictability of the application suffer as a consequence. Second, the best optimizer is between the ears of the programmer. The most significant performance gains are made by choosing an appropriate algorithm, rather than relying on a compiler to choose an optimum instruction sequence. Needless to say, there are those who disagree… 2.4.3 Stacks Like all other Forths, 8th is a “stack-based language”. This means that parameters to words as well as results from them are put onto a “stack”. In this manner, the output of one word is immediately available as input to the next word. This encourages what is often called a “concatenative” programming style, because words are “chained together”. This concatenative style can serve to make code much more readable, since the “noise” of naming parameters is eliminated. For example, a hypothetical dishwasher controller might look like: fill-water rinse-dishes drain-water dry-dishes

On the other hand, because the parameters are not named, code can also become less readable! Therefore it is important to make liberal use of comments, especially those regarding a word’s stack-effect. It is also very highly recommended to restrict the number of stack items a word uses to three or fewer, to make code easier to understand. 8th has several words dedicated to manipulating items on the stack. A full description can be found in the chapter on stacks. 2.4.4 Item types In 8th, all builtin data-types “know” what they are, and words can (and most do) check to ensure they are operating on the type of data they expect. For example, 123 is a numeric value just as in other Forths. However, it is not just a value on the stack. Rather, it is an item of the namespace number, and other words can determine that it is in fact a number and not, for example, a string by using a code snippet like >kind ns:n n:= if … then. The various builtin types known by 8th are listed in the chapter on data types, and detailed information about them is there and in subsequent chapters. 2.4.5 Reference counting 8th assumes you are not interested in the drudgery of keeping track of memory allocations and de-allocations. Not only that — it does not provide you any way to directly allocate memory! Most of the time you are not interested in the reference-counting mechanism either, you just care that it works! But in case you want more information, it can be found in the reference-counting section in the data-types chapter. 2.4.6 Exceptions Rather than let you do something illegal, 8th will throw an exception. There are a number of different exceptions which 8th knows about, and you can throw your own if you like.

— 12 —

The 8th Manual: Introduction to 8th

The default handler (called, unsurprisingly, handler) causes 8th to show a message and quit if an exception occurs. If you prefer to handle exceptions in a different way, you can override the default handler word using w:is. See the section about words for more information. Exceptions are thrown if you overflow or underflow the stack, if you pass an incorrect data type to (most) words and for many other situations. Generally, an exception in 8th is a fatal error, so the default behavior of quitting out is probably the best. Note that in interactive mode, e.g. when you start 8th and just start typing code, a thrown exception does not quit the interpreter. The reason for this is to make it easier for you to see what happened and take corrective steps. However, the exception is still a “fatal error”; and 8th may not be able to continue without crashing. This scenario does not happen when running from a file or an application, since in those situations 8th will quit (unless you overrode the handler word, in which case caveat programmer. Many words indicate an error condition by returning the value null, which can be checked using the phrase null? if (null processing goes here…) then

2.5 Getting help This manual, the tutorial and the sample code provided with 8th should be your first source of help if you have difficulties. If you cannot figure something out or if you just want to discuss the matter, you should join in the discussions on the forum: http://8th-dev.com/forum/. If you are typing code in the console and want some help, there are two helpful words at your disposal: help and apropos. The first lists all the words which match the text given after it, along with their documentation. The second does the same, but matches as well any help text which contains the text you type.

2.6 About the name As mentioned before, Ron had written a Forth-based language called “Reva Forth”. The word “reva” in Hebrew (‫ )רבע‬means “one-fourth” and Reva is also “one Forth”. Since we were working on a second-generation of Reva, so to speak, we multiplied the 4 by 2 giving 8. So instead of one-fourth we have one-eighth. Aren’t you glad you asked?

2.7 Quick introduction for users of “mainstream” languages If you’re coming from C or Java or most “mainstream” languages, you may find 8th a bit puzzling. To help set you on the right path, here are some of the primary differences between 8th and “the mainstream”, as well as some helpful hints: • There are no “local variables” in 8th! Instead, use the stacks (data-stack and r-stack) to save values and ensure your code is re-entrant. • As a consequence of the above and the way the interpreter looks up items, you must declare a var prior to its first use. • A var is a named container for other items. It is not the name of the item referred to! So var x may hold an array, but it would be incorrect to try to access x as if it were itself an array — and doing so will cause an exception to be thrown. — 13 —

The 8th Manual: Introduction to 8th

• Try to write your own words so that they can be chained together with other words. For example: the “file words” do some operation on a file, and leave the file handle on the stack (and perhaps other information) for the next word to work on. • Keep your words short. Comment them. Be sure, especially, to comment the stack-effect, and… • Test each word you write, ensuring it adheres to the stack-effect as documented. This will help you write bug-free code. • Consult the help and apropos words for details on the stack-effect and action of any word you aren’t sure of. • In 8th, an “exception” is generally a fatal error, and should cause the application to quit (which is the default behavior) • There is not a separate compiler and interpreter and linker. Instead, 8th is an engine which first interprets your code and if necessary compiles it at that time. Your code when running is generally native code for the platform.

— 14 —

Chapter 3: 8th’s syntax

As in other Forths, 8th plucks whitespace-delimited words from its input and tries to interpret them, one at a time. However, there are some special lead-in characters which make 8th interpret the characters which follow in a different manner, and the sequence of events in the interpreter is important. 8th’s syntax is quite minimal: it is completely described by the few rules listed below. As mentioned, there are two “modes” as in other Forths: “interpret mode” and “compile mode”. Interpret mode is the initial mode of 8th, where the text you enter is is interpreted immediately according to the rules listed below. Compile mode is initiated by the “:” or “(” words, and terminated by the “;” or “)” words, respectively. In compile mode, the words you enter are compiled into the new word, to be executed when that new word is invoked. 8th has no reserved words. This means you can override any of its built-in words. Please do be careful if you do so, since the “old” word is then no longer available to the interpreter, which may have Unusual Consequences™. Also bear in mind that with great power, comes great responsibility. Just because you can do something, does not mean you should.

3.1 Interpreter rules Here is what happens inside the 8th interpreter: 1. Parsing starts by picking up characters one-by-one from the input (which may be a file, an “eval” string, redirected standard input, or the keyboard), and collecting them into a word. Any “whitespace” stops the collection process. The term “whitespace” includes spaces, tabs and end-of-line-characters. 2. The parsed word is looked up using the equivalent of find: a. If only was issued, look only inside that namespace. Otherwise: b. Look in the namespace of the “current item”. In interpret mode, that’s the item on TOS (top of stack) if there is one. In compile mode, it’s the last item compiled. c. If not found, look in each namespace in the “with” list. By default, that list contains just the user namespace. d. If not found, see if it’s a “fully qualified” name, e.g. a name with a namespace-name, colon and word — such as n:+ — and then look in the specified namespace e. If the word is still not found, look in the G, or “global” namespace, with is thus always checked if the word was not found beforehand. 3. If not found, examine the first character of the word to see if it is a special item type (see the table below) 4. If none of the above succeeds, try to interpret as a number using the current base — 15 —

The 8th Manual: 8th’s syntax

5. When all else has failed, invoke the ??? word with a string containing the offending character sequence. If desired, you may override the ??? word to provide your own custom “last gasp” rule. The default behavior is to throw an exception “Unable to find: ”. Note how the interpretation rules allow you to override any word, since 8th first checks for existing words. You can, for example, override 8 to print “eight”: : 8 "eight" . ;

When an item has been successfully parsed, the interpreter pushes it on the stack (if in interpretmode), or compiles it into the current word (if it’s in compile-mode). This behavior is the usual case, but “immediate” words, and likewise use of p:, i: and l: modify this. Details are provided in the chapter on words.

3.2 Strings When interpreting a string, 8th follows the same string conventions used in the “C” language. First, a string is any sequence of characters delimited by double-quotes ("). Second, if a backslash character (\) is encountered, the following characters are interpreted specially: " a b f n r t v x u

double-quote, ASCII 34 alarm, ASCII 7 backspace, ASCII 8 formfeed, ASCII 12 newline, ASCII 10 carriage-return, ASCII 13 tab, ASCII 9 vertical tab, ASCII 11 The next two characters are hex digits (e.g. \x20 is the space character) The next four characters are hex digits (e.g. \u201c is the typographic “

Any other character following a backslash is inserted literally. Finally, the text in a string is terminated with ASCII “NUL”. Even though strings keep track of their own length, it proves useful to be able to pass strings to system routines without performing conversions. Note that strings are sequences of UTF-8 encoded characters, so they may contain any valid Unicode character (even if your font doesn’t display it properly). Note that 8th is not tolerant of malformed UTF-8. So if, for example, you have a buffer containing text in, say, CP-1255 encoding and then convert the buffer to a string, it is very likely that an exception will be thrown complaining about invalid UTF-8. Currently, 8th does not have any charset conversion routines, though you can hook “libiconv” or similar libraries using the FFI.

3.3 Special characters There are characters which have a special meaning when encountered during interpretation of the input. That is to say, when encountered as the first character of a new word parsed from the input, they cause 8th to interpret the remaining characters differently. The special characters are: / " [ {

regex, terminated by a matching / string, terminated by a matching " array following modified JSON syntax map, also following modified JSON syntax — 16 —

The 8th Manual: 8th’s syntax

3.4 Numbers numbers are interpreted with special rules. If the lead-in character is: + make number positive make number negative 0x or 0X or $ interpret number as hexadecimal (e.g. base 16), regardless of current base # interpret number as decimal (base 10), regardless of current base & same, but octal value (base 8) % same, but binary (base 2) ' The following single character is interpreted as an ASCII character value . Anywhere in the input, means number should use floating-point e or E If base is decimal, number is floating-point and following is the exponent

3.5 Regular Expressions The regular-expression syntax used in 8th is that of PCRE, with all its features and limitations. When entering a new regex, one may either use the slash notation, e.g. /(cat)|(dog)/

or one may choose to construct a regex from a string, using r:new: "(cat)|(dog)" r:new

In either case, a new regex item is created. However, the second version may be used to create a regex from any (appropriate) string, and the parsing rules for strings then also apply. Using slash-notation, the regular string parsing rules do not apply.

3.6 Scoping 8th is unlike most other languages you may be familiar with, in that it has very primitive “scoping rules”. For example, in the C++ language a variable declared inside curly-brackets is only “visible” to code that is also inside those brackets. 8th does not work that way. There are no local variables; rather, everything which can be looked-up with find is inside one or another namespace. If you take no other steps, words and variables you create will end up in the user namespace (ns:user). You can create new namespaces and use them to distinguish aspects of your application. However, you can easily change the scope of your words to another namespace in one of two ways. First, you can prefix the word with the namespace-name and colon; this will create it in the named namespace. Note that the namespace must already exist for this to create the new word there: : m:xxx 123 ;

That example created a (useless) word called xxx in the ns:m (map) namespace. You can also use the ns word to let 8th know that you want to create new words in that “namespace”, e.g. a namespace: ns:m ns : xxx 123 ; — 17 —

The 8th Manual: 8th’s syntax

This has the exact same effect as the previous example, but is much nicer if you have many words you wish to put into a particular namespace. You can create a namespace of your own in which you can put all your application’s words (or some subset of them) by simply doing: ns: mycode

This will create a new namespace mycode if it doesn’t already exist, and inform 8th that new words should be created there. It also makes mycode the first namespace searched for words. However, it does not affect the general search order. For that you need to use with: and ;with

3.7 JSON Rules 8th uses a modified form of the industry-standard JSON syntax for defining data items. While it understands standard JSON just fine, there are a few additions to the standard syntax which are geared to making it work more conveniently with 8th. Comments. When declaring an array or map, you may insert an 8th comment in between elements (or between a key and its value, for an map). So this is legal syntax: { "key" : \ this comment is perfectly legal (but not in standard JSON)! "some value" }

Just don’t forget that in 8th, comments run to the end of the line; so you cannot put a parenthetical comment inside the code. Also note that this only works with the single-backslash comment, it does not work with -- or any other comment words. Expressions. In an array or map declaration you may use the backtick character ` to bracket an expression to evaluate. That expression will be evaluated when the JSON is, and its value will be inserted where you expect the item to appear. This can (and must) leave any valid 8th item on TOS to be inserted — including stacks or anything else; thus the resultant array or map will not be convertible to standard JSON again! Additionally, the backtick cannot be used to evaluate a value for the key of an map, only the value for the key. Code snippet. You can also put an anonymous word in the item you’re declaring: [ ( 123 321 n:+ ) ]

This is different from the backtick-expression because it is compiled code, and the word is held in the item you declared (array or map). You can use w:exec to execute the word, or pass it on to some other word which requires it. Alternatively, use the tick word ' to find a word and insert it. Here’s an example with all the modifications to standard JSON which 8th knows: [ 123, \ a comment ' myword , ( myword ) , ` 200 300 n:+ ` , \ an evaluated expression "hi", \ an ignored final comma ]

— 18 —

Chapter 4: Effective 8th

For most programmers, 8th will be a bit unfamiliar. The paradigm shift can be difficult at times, but once you are comfortable with it, we believe 8th to be a more powerful and productive language than most. In this chapter we will try to help you become a more effective 8th programmer. See also the “Best Practices” document (bestpractice.pdf).

4.1 Iterative refinement of code If you come from other programming languages, you may be used to the “waterfall model”, where the coding happens after a great deal of thought went into the design, and once the design is established the coders write for a few weeks and then test the code. This last is a very bad approach for writing 8th programs. Why? Because small problems add up, and it can be very difficult to track down issues in large bodies of code. Therefore, the recommended approach is to write a word and then test the word immediately. Since you have access to a REPL, you can interactively test words as you write them. Or if you are working on a GUI based application, you can test via the application. In either case, the key is to iteratively refine your code. How? Start with the main code in pseudocode: : app:main initialize main-code clean-up bye ;

Establish the application’s high-level flow. Now implement each of the words you started with as a place-holder: : initialize "initialize" log ; : main-code "main-code" log ; : clean-up "clean-up" log ;

Verify that when you run your app, you see the appropriate log output. Then proceed to “fill in the blanks” for each word. As you write each word, document its stack-effect diagram, and then immediately test it to ensure that the word you wrote does have the stack-effect as well as any side effects it is supposed to have. You will find that spending the time to test while coding will pay off many-fold in reduced time debugging and lower blood-pressure.

4.2 Factoring code By the term factoring, we mean “break your code into smaller pieces”. Ideally those pieces will themselves be useful in their own right. A well-factored 8th program will consist of many small words instead of a few large ones.

— 19 —

The 8th Manual: Effective 8th

For example, let’s say your task is to write a word which returns the sum of the squares of two numbers. The word will get two numbers on the stack, and return a single number. So your first effort may look like this: : sum-of-squares \ a b -- a2+b2 dup n:* \ a b2 swap dup n:* \ b2 a2 n:+ ;

Nice and simple, and it also works and is documented sufficiently. Factoring really involves scanning the code and looking for repetitive phrases. In this example, we notice dup n:* is repeated, so we factor it out into its own word: : square dup n:* ;

\

a -- a2

: sum-of-squares \ a b -- a2+b2 square \ a b2 swap square \ b2 a2 n:+ ;

In this specific example, factoring out “square” may seem to give little benefit. But it serves more than one purpose. First, the factor “square” is useful in its own right, and is so simple that it is easy to see that it works. Second, by using “square” instead of “dup n:*” it is clear at a glance what we are trying to do inside the “sum-of-squares” word. Finally, by extracting that factor we have made it much less likely we will have an error caused by dropping a word (accidentally deleting the “dup” for example). Don’t be concerned about making “too many words”. The heavy cost of insufficiently factoring the code is much greater than the very small cost of adding more words. The benefit of more easily maintainable and more robust code, outweighs any other consideration. As an added benefit, factoring makes it easier to verify your code. In our example, you can simply type in some test cases in the console: 10 square . cr -2 square . cr

If you don’t see “100” and “4”, you’ll know something is amiss with the code. You can (and should) also verify that in fact the stack depth is the same before and after you invoked square. A common source of bugs, as we mentioned in the previous chapter, is losing control of the stack. “Avoiding complexity” is helped by proper factoring as well. By breaking your code into smaller factors, you help reduce the size of words, and make it easier for you to grasp at a glance what the code does.

4.3 Use the stack One of the most difficult habits to break for programmers coming from more traditional languages, is the reliance on “variables”. 8th is built around a stack, and data is passed back and forth on the stack — you get the stack for free, it makes sense to use it. In the example we gave before of sum of squares, someone with experience in C-type languages may very well write something like this: var sq1 var sq2 : sum-of-squares dup n:* sq1 ! dup n:* sq2 ! sq1 @ sq2 @ n:+ ;

\ \ \ \

a b -- a2+b2 b2 -> sq1 a2 -> sq2 get sq1 and sq2 and add them

— 20 —

The 8th Manual: Effective 8th

This code does work, but is inferior to the example we gave earlier on in a couple ways. First, moving data from the stack to a var and back again takes extra time and extra code. Second, the vars take up space. Third, the code is less clear because of all the “noise” of moving data back and forth. And finally, the code is larger than it should be by quite a bit. Obviously you may use variables in 8th, since they are part of the language! And there are indeed occasions where you must use them: for example, if you have global state you need to keep track of. However, the words you write should ideally get everything they need from the stack and put their results back on the stack. As mentioned, one reason for this is that moving data back and forth to variables is “expensive”. However, another reason is that using the stack makes your words re-entrant, while if you use variables your words will not be re-entrant. This may be important, particularly in GUI applications where callbacks may occur simultaneously (or nearly so). If you find yourself using variables to store intermediate results, you probably need to factor your code a bit more. Even if the factors don’t make sense as “standalone words”, they may vastly simplify the stack-picture in your code. In order to use the stack effectively, you should restrict your words to using no more than three items at a time from the stack, and attempt to factor to reduce “stack juggling”. In particular, if you find you must use pick very much, you probably need to factor the code some more.

4.4 Faster code If your goal is to produce the fastest code possible, you should consider the following: • Pick the fastest algorithm which matches your constraints • Avoid store and fetch from variables (or other containers) • Juggle the stack less • Use fewer words. Yes, this will make your code less readable and violates the principle of factoring. Each word invoked takes time. • Utilize the built-in data types rather than creating your own parallel versions • Increase the pool size(s) so you have enough for all concurrent items • Consider breaking your code into tasks which can be run in parallel, particularly if you are running on a multi-core machine • Consider using the FFI to offload CPU intensive work to an optimized library

— 21 —

Chapter 5: The data stack

In common with all Forths, 8th utilizes the “data stack” to pass data to words and to receive results from words. Because of its importance, programmers must become familiar with how to use it properly. This chapter will describe in detail the words 8th provides to manipulate the stack. When we say “the stack” we are referring to the default data stack.

5.1 Basics of the stack Conceptually, “the stack” is similar to a stack of pancakes: the last pancake put on is the first one taken off. This is known as a “LIFO” data structure — last in, first out. Likewise with the items on the 8th stack. The act of putting something on the stack is called “pushing” and taking something off it is called “popping”. You push items on the stack, and the next action can pop items off and push new ones on. Of course, a word is not required to push or pop anything at all. ok> 123 .s 1 n: 00007fb2e9844a00 1

123

In this example, the number 123 was pushed onto the top of the stack (TOS) simply by typing it in. The 8th interpreter recognized a number, and allocated one and gave it the value “123”, and then placed it on TOS for further use. The .s word prints the top ten items on the stack (words beginning with “.” are commonly used to indicate “print something”). The stack has a limited size (the default is 512 items, which can be changed from the 8th command line or using stack-size). If you attempt to push onto the stack when it’s already full, or pop from it when it’s empty, 8th will throw an exception. When writing words, it is a very good idea to comment the word’s stack usage. This is called a “stack-effect diagram”, and is traditionally written like so: \

in1 in2 -- out1

In this case, the two parameters pushed on the stack were in1 and in2, where in2 is on TOS. The word is documented to consume those two and leave out1 on TOS. When you’ve properly documented your words’ stack effects, you’ll be able to come back later and more easily understand what the word was intended to do. In 8th’s documentation, a stack item in means that kind of item is read from the input-stream (either the 8th source code in a file or from the keyboard or standard-input if input is redirected).

5.2 Common stack words The principal words you’ll use for stack manipulation are: dup drop swap over nip

x x x x x

– – y y y

x x – y x – x y x – y

duplicate TOS remove the item in TOS exchange the item in TOS with the second item duplicate the second item and put it in TOS remove the second item — 22 —

The 8th Manual: The data stack

tuck rot -rot 2dup 2drop 2over pick

x x x x x x b n

y y y y y y x –

– z z – – a y m

y – – x

x y z y

y z x x y x y

b – x y a

duplicate TOS and put it in the third position rotate the top three items, making the third TOS rotate the top three items, making the second TOS duplicate the top two items on the stack drop the top two items on the stack duplicate the third and fourth items on the stack “pick up” the item at position “n” on the stack. 0 pick is the same as dup

5.3 Using the stack 8th words take their parameters from the stack, and push any results back onto the stack. Thus, the “stack-effect diagram” mentioned above is important documentation for any word you write, as well as for the words built-in to 8th. Because a word’s parameters are not named as in most other languages, but simply reside on the stack, it is recommended to avoid using very large parameter lists. Generally speaking, if you have more than four parameters to a word, you should look at refactoring to break the list into something more manageable. In particular, use of the word pick probably indicates your parameter list is too big, and you should give thought to reorganizing your code. Of course, pick is provided because you do need long parameter lists, sometimes.

5.4 Extra stacks The words >r r> and r@ provide access to an additional stack, which is intended to be used to store temporary values. If you are familiar with other Forths, you need to be aware that this is not the “return stack”. 8th does not provide access to the return-stack. Instead, you use these words to stash a value away temporarily. The “r-stack” is as big as the data-stack, by default 512 items deep. But you will usually only need to use one or two items at a time on it. If you do find yourself needing to access arbitrary locations on the r-stack, you can use rpick. You can also create any number of other stacks of any size using st:new and the other stack words. You can push, pop, peek and pick just like you can with the data-stack and r-stack; however, you do not have access to the full complement of stack-words which operate on the default data-stack.

— 23 —

Chapter 6: Data types

8th has many built-in data types — some are almost self-explanatory, while others are less familiar. This chapter will acquaint you with the types and what they are used for in general. Further chapters will expand on specific data types. All data types used in 8th are self-contained, and occupy only one cell on the stack (or in a variable).

6.1 Namespaces An 8th namespace is a combination of “data type” and the “vocabulary” which operates on items of that type. The built-in namespaces usually have short names of one or two characters, to save typing and compress the source. So for example, the namespace s contains the string words, and an item which has a namespace identifier of ns:s is a string. The word >kind is used to determine what namespace an item belongs to. It places the numeric value of the item on TOS, where you may then compare it with the value of the namespace identifier. For example: : isnumber? \ x -- true|false >kind ns:n n:= ;

This example converts TOS to the numeric value of its namespace using >kind, and then compares that value with the numeric value of ns:n, the namespace identifier of numbers. It then does a numeric compare (note the n:=, which means use the word = in the namespace n). You may find the notation n:= a bit confusing, but it’s there for a good reason: many other namespaces also have a word named = (for example, strings may be compared with an equals sign), but the only real connection between the various equals is that they do a compare of their data types. Because it is convenient to use a similar symbol or word for a similar action, 8th has no problem letting you have a string and a numeric equals. But since they are after all completely different, they are in separate namespaces. If you find yourself using n: (say) very often, you may wish to use the word with:, which lets 8th know it should check for the word you type in those namespaces first. If you do use with:, you will want to use ;with when you are done, to remove the namespaces from the impromptu search order. To check on what has been put in the “with-list”, type .with . The above example could also have been written: with: ns:n : isnumber? >kind ns:n = ;

There are two namespaces which are special: ns: and I:. The ns: namespace contains the names of all the namespaces, and invoking any of the names therein puts the numeric namespace identifier on TOS, as seen above. The I: namespace contains internal factors of 8th words which are useful in various places within 8th, but not sufficiently useful to be documented. They are put in a separate namespace to reduce clutter in G:.

— 24 —

The 8th Manual: Data types

6.2 Survey of 8th data types Many data types come into being by declaration, and others can be created using some form of the word new. If the namespaces has its own new, that will be described. The types (namespaces) which are built-in to 8th are: app.

In the app namespace. Global state of the application.

array. In the a namespace. An array is a container which allows indexed access to any of the items it holds. Unlike arrays in most other languages, an array can hold any data type, including other arrays. Just like strings, arrays manage their own memory and resize as needed. An array can be defined using JSON, with 8th’s enhanced JSON syntax. An empty one can be created using ns:a new bluetooth.

In the bt namespace. Encapsulates access to Bluetooth devices.

boolean.

In the T namespace. There are exactly two booleans, true and false. The word if tests to see if TOS is true or a non-zero number, which is also considered to be “true” for the purpose of flow-control. buffer. In the b namespace. A buffer is simply a chunk of memory which knows how big it is. The f:slurp word, for instance, takes a string and reads the entire contents of the file with that name into a buffer. Unlike strings, a buffer cannot be resized. context.

In the ctx namespace. An internal namespace used to keep track of the state of the

8th system. control. In the C namespace. An internal namespace used to keep track of the state of controlflow words such as if and while crypto.

In the cr namespace. A crypto keeps track of the state of the cryptological and hashing

words. database.

In the db namespace. Represents a SQLite or MySQL database.

date. In the d namespace. A date contains the date and time, and may be created using d:new, which will initialize the date to the current date/time. Alternatively, one may invoke d:parse on a suitable string, for example "2001-10-05" d:parse. date values may be accurate to a millisecond, and may represent any date you are likely to encounter. file.

In the f namespace. This may represent a disk file or a zip-file.

font.

In the font namespace. Font description and manipulation.

global. In the G namespace. There is only one item of this data type in the system, null — which represents “no value”, and is often returned if a value doesn’t exist or some other failure occurred. Check for it using null?. This namespace contains most of the “general” words. The find word will search here after it has exhausted other possibilities (as mentioned in the syntax chapter) gui.

In the g namespace. A gui is the interface used to control the graphical-user-interface components. For example, buttons and windows. A gui is created using g:new, which takes a map which describes all the components of the desired gui. The words in this namespace are used for manipulating the gui elements of an 8th program. — 25 —

The 8th Manual: Data types

hardware.

In the hw namespace. A hardware is the interface used to control certain physical devices, for example the GPS or camera. heap. In the h namespace. A heap is an ordered collection, where you provide the comparator. The h:new word takes a word to use for comparing items you push onto the heap, so they are in

order when you pop them. image.

In the img namespace. Image (JPEG, etc) handling.

map.

In the m namespace. A map is a container which allows keyed access to any of the items it holds. It is the rough equivalent of a “dictionary” or “hash-table” in some other languages. Keys to maps are strings, and the value of the key can be any 8th data type, including other maps. As with arrays, a map may be defined using JSON. matrix. In the mat namespace. Matrices, which are essentially multi-dimensional arrays of numbers. They are fixed in size at creation time. namespace. In the ns namespace. This is the namespace which maps namespace names into numeric identifiers. net.

In the net namespace. Represents a network socket, or an internet connection.

number.

In the n namespace. A number is a numeric value which may be an integer or a “floating point” number. You don’t have to be concerned with the internal representation of the number, it will resize and convert as needed to conveniently give you the most accurate value. Numbers may grow as large as needed, with the limitation that large integers do have a maximum size. query.

In the sql namespace. A predefined SQL query to be used with a db.

queue.

In the q namespace. A queue is a serially ordered collection. Where a Stack is FILO (or LIFO; first-in, last-out), a queue is FIFO (first-in, first-out). The q:new word takes a number which determines the size of the queue. regex. In the r namespace. This is a PCRE regular-expression, and follows the syntax-rules of PCRE. It may be used for searching inside other strings, among other things. The r:new word takes a string to create a new regex. Alternatively, one may simply use forward-slashes to delimit a regex string. For example: "ca?t" r:new and /ca?t/ are equivalent. serial. sound.

In the sio namespace. Encapsulates serial I/O. In the snd namespace. Audio playback (not yet recording).

stack.

In the st namespace. If you want a separate stack from the built-in data-stack, you can create one yourself. The st:new word takes the size of the new stack. string. In the s namespace. A string is a sequence of UTF-8 encoded characters, and follows the C family of languages’ syntax. That is, it is a double-quote delimited run of characters. strings are only limited in size by the amount of available memory; they resize as needed. The C style escape characters are supported, and strings are also NUL terminated. var.

In the v namespace. A var is a container which can hold just one item (of any type) at a

time. word.

In the w namespace. A word is the equivalent of a “function” or “procedure” in other languages. It is the smallest unit of execution. A word may be defined in one of two ways: using — 26 —

The 8th Manual: Data types

the sequence : name code… ; to produce a word named name, or by using the parentheses ( code… ) to produce an anonymous word. X. In the X namespace. This represents opaque items which can only be used internally by 8th’s words, but which may need to be passed to the user to hold onto for later use. xml.

In the xml namespace. This encapsulates XML and HTML parsing and processing.

6.3 Reference-counting and pools Each item in 8th comes from a preallocated “pool” of similar items. The size of that pool is predetermined at startup, and more pools of that size for that namespace may be created if necessary. The pool size may be changed using the -p command-line option to 8th, or within your application by invoking pool-size prior to app:main or early in it. Each item has a “reference count” (refcount), which determines whether or not it is available. If the refcount is zero, the item is available and may be reused, in which case the refcount is set to 1 and the item is put in TOS. The refcount is incremented every time another item holds the item (for example, if it is duplicated on the stack or is put in a var or other container). The refcount is decremented whenever a hold on the item is released (for example, if it is popped off the stack, or another item is put into the var, etc.). When the reference count is about to transition back to zero, 8th performs whatever cleanup is necessary for that item (e.g. closing files, releasing memory) so that the soon-to-be-available item will be ready to be used and not leak memory or other resources. Because memory allocations do not happen for every new item, the memory usage and performance characteristics of 8th programs are favorable to small devices.

6.4 Constant items Generally speaking, all items in 8th are mutable. The exception to that rule is items defined within a word. Such items are flagged as “constant”, meaning that they cannot be modified, and if you do attempt to modify them, the item you receive will be a clone of the constant item. You can flag an item (outside of a word) to be constant using const, if you need it to be immutable. Similarly, you can flag an item inside a word with !const to allow it to be modified.

6.5 A note about data conversion Ron has long been of the opinion that implicit data conversions are a major source of subtle bugs. Anyone familiar with Perl or JavaScript is aware of this. Therefore, 8th will never* convert data from one type to another, relying instead on the programmer to tell it when a conversion is desired. This is also why 8th words almost always return the value null for error conditions, because null is not usually a valid value, and it is unique. * Well, almost never. The only case in which implicit conversions appear to happen is when testing for the equivalent of “truth”, for example with if. In that case any non-zero number is considered the same as true, and numeric zero as well as null and any other data types are considered the same as false.

— 27 —

Chapter 7: Flow control

8th has a number of flow-control statements; some are familiar and some are unique to 8th.

7.1 First things first! When 8th runs your code from a file, it interprets and compiles or runs it as it goes along, if necessary. When it is done reading your code, it looks for a word app:main, and invokes it if it is found. Otherwise, it will wait for your input. If the file ended with a word invocation, it is invoked.

7.2 Conditionals The standard Forth conditional words if… else… then are implemented in 8th. Unlike Reva, there are no specialty versions of if. Note: the conditional words if else then may only be used in “compile mode”. 8th will complain if you try to run them outside a word definition. The word if looks at TOS, and if it evaluates “true”, that is if it is true or a non-zero number, it continues to the word following the if. Otherwise, it will skip to the enclosing then or the enclosed else. For example: : test

if "yes!" . else "no, sorry" . then ;

In this case, true test will print “yes!” while false test will print “no, sorry”. You may also “nest” conditionals: : test if some-condition if "yes!" . then else "no, sorry" . then ;

The nesting may be as deep as you like; but if you find yourself writing code with more than a few nested if statements, you should seriously rethink your code’s design! Another set of conditional words is caseof, when and when!. They operate differently (and more elegantly) than nested if… then or the switch statement in C and the like. The caseof word accepts a container, either an array or a map, and a value which is either a number (if an array was given) or a string (if a map was given). It then looks up the value in the container; and if that item exists, it is either executed (if it is a word) or put on TOS. For example: [ ' first , ' second , ' third 1 caseof

]

The caseof will take the 1 as an index into the array, and find the word second and execute it. If the array had contained anything other than words, those items would be put in TOS. Note that the word ' inside JSON requires whitespace after the name of the word it parses! — 28 —

The 8th Manual: Flow control

The when word takes an array consisting of pairs of words. It iterates over the array, evaluating the first word of each pair. As soon as it finds a word which returns true, it evaluates the second word of that pair and stops searching. The when! word is the same, except that it does not stop searching. In other words, it will iterate the entire array, executing the second pair of words whenever the first returns true. [ ' test1 , ' action1 , ' test2 , ' action2 , ' test3 , ' action3 when

]

Assuming test2 is the first one which returns true, then when will execute action2 and stop.

7.3 Repetition There are several ways to repeat yourself in 8th. The more familiar words are repeat again while. Just like if then else, they may only be used inside a word definition. The phrase repeat… again is an “infinite loop”, which will repeatedly do whatever is between the repeat and again. The phrase repeat… while will conditionally repeat until TOS evaluates to false. Unlike standard Forths, the 8th version of while does not consume TOS. If you want a “consuming while” you can use while! instead. : ra \ infinite loop repeat "Hi" . cr again ;

This will repeat “Hi” endlessly, because when again is encountered it jumps back to the previous repeat. In order to leave you need to invoke break, ;; or similar. : rw \ repeat while a condition is true 100 \ give an initial value repeat dup . space n:1\ the item on TOS is not removed… while drop ;

This repeats 100 times, because TOS starts at 100 and the while peeks at TOS and returns to the repeat if TOS doesn’t evaluate to false. So until TOS is 0, it repeats. The while doesn’t remove the item from TOS when it falls through, either; thus the drop is required. You may do a counted repetition in one of three ways: times loop loop-. The times word takes a word to execute and a repetition count. It executes the word as many times as indicated: : a "hi" . cr ; ' a 10 times

That will print hi on a line of its own, ten times. The loop and loop- words are identical, except for the direction of the looping. loop counts up while loop- counts down. Just like times, they take a word to execute; but they also take a “low” and “high” value, which are the beginning and ending values for which to execute the loop. For example: : a . cr ; ' a 10 13 loop

This will print out 10 11 12 13, in order. loop- would print them in reverse order. The loop index is passed on TOS to the word being executed, which must consume that number unless you intend to leave the items on the stack. One way to get an array of sequential numbers is to use loop: ' noop 10 19 loop 10 a:close — 29 —

The 8th Manual: Flow control

That tidbit gives you an array of 10 sequential numbers, from 10 through 19. Be careful if you use this kind of trick, since the stack is only 512 deep by default — there are better ways to accomplish the same idea. Besides those methods, you may also iterate a known number of times by invoking a:each on an array, or m:each on a map. Those will iterate the contents of the containers they were given, allowing you to do something for each item contained. [1,20,300] ( . space drop ) a:each

That will print 1 20 300. The drop is there because you aren’t interested in the index value, and you do want to keep the stack clean. The array remains on the stack after a:each (and likewise, the map remains after m:each.

7.4 Breaking up is easy to do The various repetition words can be stopped by using break, which signals 8th to terminate the loop at the next repetition (not immediately!). You can test for it in your own loops using break?. The break word will also terminate iterations in s:eachline, f:eachline, a:each and m:each as well as db:exec-cb and repeat… again.

— 30 —

Chapter 8: Words, the interpreter and compilation

Previously we said, “A word is the equivalent of a ‘function’ or ‘procedure’ in other languages. It is the smallest unit of execution”. So how do you go about creating a new one? The word : (ASCII 58, the colon character) tells 8th it should create a new word whose name will be the following sequence of non-whitespace characters. For example: : newword 1 n:+ ;

This creates a new word called newword. The initial “:”, is the word-creator; it looks at the next bit of text and creates a word with that name. Knowing that white-space is treated as insignificant, scan for the next words: 1 and n:+ are compiled into newword. The final “;” (ASCII 59, the semicolon character) tells 8th to terminate the new word and resume interpretation mode. At this point, executing the following: 2 newword

will result in the number 3 on TOS. This is because the 2 pushed that number to TOS, and newword was then invoked, which itself pushes 1 and then invokes n:+ to perform a numeric addition. The result is, as expected, 3 in TOS. Of course, the name newword is a poor choice, since it is completely uninformative about the nature of the new word. You are encouraged to use meaningful names for the words you create, especially since you can use any UTF-8 sequence whatsoever as long as it doesn’t contain white-space! As mentioned in the chapter on syntax, 8th interprets words one at a time and either executes them or compiles them into new words, depending on the state 8th is in at the time.

8.1 Named versus anonymous words words created using : have a name, which is the whitespace-delimited run of characters after the colon. But sometimes you don’t need or want to name a word, you just want the action itself to be available. Such a word may be useful as a callback or in an iterator. You can create such a word using the ( and ) words, like this: ( 1 n:+ )

Be aware that an anonymous word still takes space in your application! It does not get cleaned-up and removed as you might be used to with JavaScript or some other languages. Moreover, it cannot be “found”, so if you lose your reference to it, it is permanently “lost” even though the code still exists. If you don’t need to access it by name you will have saved a little bit of space (and will also have avoided using up useful names for other words).

8.2 Deferred words A “deferred word” is a special kind of word, whose code can be modified at run-time. That is, the word is declared using defer:, and the action it performs is assigned later using the word w:is. For example: — 31 —

The 8th Manual: Words, the interpreter and compilation

defer: some-word : some-action ... ; \ later on: ' some-action w:is some-word

There are two main uses for deferred words. First, you may need to use the word before you can define it. That is, you are compiling word A which uses word B, but you cannot yet define word B. The deferred word facility allows you to make a “forward declaration” of B so that 8th can compile A, and you can then fill in B’s code later on. A second reason to use a deferred word is that you may want the ability to change the effect a word has at run-time. For example, you may wish to redirect the normal output words to write to a string instead of to the screen. Since the words putc and puts are deferred, you can reassign them to do whatever you like. Of course, you will want to be careful if you do this. The deferred words built into 8th are: ??? conflict getc gets handler prompt putc puts putslim (say) app:resumed app:suspended app:sysquit dbg:prompt . You may override any of these using w:is — but you must be careful to follow the stack-effect of each of the words you thus override, or the effects can be unfortunate! The assignment of an action to a deferred-word can be undone, using w:undo. Each deferredword can have one level of undo. That is, invoking w:undo twice will remove all assigned actions, leaving the word inert.

8.3 Word attributes A word may be “immediate”, which means that it is executed immediately when interpreted, even in compilation mode. For example, if is immediate because it compiles the action of the “if” into the word currently being compiled. Most words aren’t immediate, which means that when you put them between : and ; they get compiled in. In “interpret mode”, all words are immediately executed. If you want a non-immediate word to behave as if it were immediate for the moment, you can invoke i: before it, which means “treat the next word as immediate”. Likewise, p: “postpones” the action of the otherwise immediate word which follows it. In addition, you can flag the word you are creating as an immediate word itself, by terminating it with i; rather than ; — this is the rough equivalent of using IMMEDIATE in ANS Forths. In addition to p: and i:, there is l:, which makes the next word be “late-bound”. That means that the name of the word is looked up at run-time instead of interpret-time, so that if the word isn’t known at when 8th first sees it, it will still compile. Use it with care, since it is slower (because the lookup happens every time it is invoked), and can give seemingly random results (because the word found may not be what you expect).

8.4 Recursion The term “recursion” is used to mean when a word invokes itself. This is possible in two ways: first, by invoking the name of the word being defined. This, however, is deprecated, meaning that it may not be supported in future versions of 8th. The second method is to invoke recurse, which will work inside anonymous words as well.

— 32 —

Chapter 9: Numbers and math

The syntax section described how 8th knows what a number is. 8th gives you a great deal of flexibility in how you enter numbers, and it keeps you from having to worry about what “kind” of number you are working with. It tries to just “do the right thing”. numbers can be entered in most any base you like, but 8th provides shortcuts for certain bases. A

simple prefix character (as detailed in the syntax section) can tell 8th you intend on hexadecimal or octal numbers. For instance, assuming the current base is 10, the following all represent the same number, decimal “16”: 16

#16

$10

&20

%10000

You can change the base currently being used at any time by use of the word base. Any base may be specified, but only bases up to 36 are actually useful. numbers will automatically use a representation which is at least as big as required. So if you type in 100, an “integer” will be used to hold that value. If you type in 100.1, a “floating-point”

number will be used instead. This is internal to 8th, which will convert between representations as needed; you will only rarely need to be aware of this. You can tell the internal representation used by invoking .s — any number which is a regular float with have a f indicator, a big-float will have F and a big-integer will have B. However, knowing the representation will become important to you if you are trying to compare numbers, and you think that the following should be true : 3.14159 100000 * 314159 =

This would be exactly equal if you were doing the math by hand, but 8th is doing the math, and it has to rely on the computer’s processor. The floating-point number you end up with at the end of the multiplication is not precisely the same as the integer number, so the comparison may fail. This is just something you need to keep in mind if you use floating-point numbers in calculations. An appropriate solution is to check for equality within some tolerance using n:~=, for example.

9.1 Big numbers Sometimes you need to calculate with values which are bigger than the native capacity of even 64bit machines to handle (for reference, the upper limit on a 64-bit CPU is 9,223,372,036,854,775,807). 8th has no problems handling really large integers. You could, for example, calculate 30! (30 factorial, or 30 times 29 times 28…), which is an eye-watering 265,252,859,812,191,058,636,308,480,000,000. When 8th determines that an math calculation will exceed the native CPU’s capacity, it converts the numbers (internally) to a “big number” format, which is mostly unlimited precision (not for integers: they are limited to just a ridiculously large number, about 28400 (on 64-bit systems, smaller on 32-bit); big-floating point numbers can be as large as your machine’s memory can handle). This does come at a price: big integers are slower to work with than native ones, and they require more system resources to process. However, the designer of 8th feels the — 33 —

The 8th Manual: Numbers and math

convenience outweighs the penalties, since you the user don’t have to be concerned with the internal format of the numbers you are using. Most of the time, anyway… 8th can also use “big floating-point” to represent high-precision floating point values. The default will use regular floating point unless the number exceeds the capacity of a regular float, or if you use the word bfloat to convert it to a “big-float”. That’s also useful if you need to calculate numbers beyond the capacity of the “big-integer”. Along those lines, you can force a number to use a different representation using one of these words: • int — convert to a native integer. This will also truncate a floating-point number • bint — convert to a big integer. Also truncates a FP number. • float — convert to a native floating-point number. • bfloat — convert to a big floating-point number.

9.2 Matrices A matrix is a fixed-size numeric container, having two or more dimensions. You create one like this: [1,2,3,4] [2,2] m:new

This snippet creates a new 2 column by 2 row matrix, and sets its initial values to those in the array. So the row 0 consists of the numbers 1 and 2, and the row 1 consists of 3 and 4. Column 0 consists of 1 and 3. A matrix may contain only numbers, but no other types (unlike arrays for example, which may hold any type). The dimensions given to m:new are in the order of columns, then rows (and analogously for higher dimensions). The words provided have special-cases for two-dimensional matrices, since those are the most commonly used. A note of caution: 8th does not implement “sparse matrices”, which means that you can quickly run out of memory if you use high dimensions with even modest sizes. For example, a matrix of just 10 dimensions with only 4 entries per dimension will use up over 40 megabytes on a 64-bit system! So think over whether you really want a super-high-dimension matrix or not.

9.3 Manipulating numbers 8th has a number of words which can be used for manipulating numbers. Besides the usual arithmetic ones, there are some specialties such as the scaling word */ which performs a multiplyand-divide at once, providing more accuracy than separate multiply, then divide. Or /mod which returns the quotient and remainder at the same time. A full list appears at the end of this manual.

9.4 Special numbers In addition to regular numbers, there are three special values, NaN, Inf and -Inf. NaN is an illegal numeric value; you may see it, for example, if you try dividing 0 by 0. Inf and -Inf are positive and negative infinity. They are likewise not actual numbers, but indicate extremely large positive or negative values. Rather than experience a crash when dividing 1 by 0, you will get Inf instead.

— 34 —

The 8th Manual: Numbers and math

9.5 Limitations As mentioned, “big integers” actually do have an upper limit. That limit is reached by calculating 985! (985 factorial; that is, 985 times 984 times 983…), which is a really big number. The reason that big integers are limited in this way is because it makes them relatively efficient to use, since 8th doesn’t have to continually check to see if it needs to resize the number and allocate more memory. It also caps the memory usage for a big integer. The “big floating-point” numbers are not limited in this way, but they are therefore not nearly as fast or efficient to use, being several times slower than “big integers”. Note that the above restriction is somewhat relaxed on 64-bit CPUs to approximately 1004!, but an upper limit does exist nevertheless. The decision to use very large, though limited, big integers is a trade-off between runtime efficiency and user-convenience. We trust that in most cases, you will not find the upper limit of the “big integer” too constraining; if you do, you can use “big floats” instead. In normal usage, 8th will promote “big integers” to “big floats” when there is a danger of exceeding the limits of big integers. However, in order for the accuracy of calculations to keep pace with the enlarging numbers, you must invoke n# with the number of digits of accuracy you require. Otherwise, only 32 digits will be retained in “big float” mode. This is in order to save memory at runtime.

— 35 —

Chapter 10: Text and strings

8th has many words which make working with text easy. Unlike most Forths, a string in 8th is: • dynamic: automatically allocates space for added text • single: a string contains its own length; you do not need to pass the length separately • UTF-8 encoded: may contain any character from any of the spoken languages on Earth • C-syntax: If you know C or C++ or Java, etc., you already know how to declare a string • NUL-terminated: Just as in C, a string ends with a terminating ASCII NUL. But since the length is also maintained, 8th’s strings are more efficient to work on than C’s version

10.1 What is a string? At the simplest conceptual level, a string is a sequence of characters. As mentioned above, any Unicode character may be part of a string. To create a new string, you simply declare it as you would in C: "cat\n"

Typing that sequence will put the four characters c, a, t and ASCII 10 into the newly-formed string. The syntax chapter has much more detail on the actual characters allowed in a string (unlike C, the NUL character may appear inside a string).

10.2 Manipulating a string string words operate on sequences of characters rather than sequences of bytes. This is an important distinction, because a string contains UTF-8 encoded characters, each of which may require multiple bytes to express. If one were to modify an arbitrary byte in a string, an invalid UTF-8 character sequence could result.

Unlike Java strings, an 8th string is not immutable. You can add to it or remove from it and modify individual characters. To concatenate two strings you use the s:+ word: "cats and"

" dogs" s:+

This results in the string cats and dogs. Remove characters from the string using s:-: "cats" 1 2 s:–

This leaves you with the string cs. There are quite a few string manipulation words; a few examples: s:/ s x – a Split the string on “x”. That could be a number, to split at a location in the string, or a string or regex to split on matches s:= s1 s2 – f Compares two strings for textual equality s:lc s – s1 Convert string to all lowercase (s:uc converts to uppercase) — 36 —

The 8th Manual: Text and strings

10.3 Internationalization and localization 8th supports localization of text using the s:lang and s:intl words. The manner in which they are used is straightforward. First you need to create an asset directory called “lang”, and you further create a separate asset for each language you wish to support. For example, if you want to have English and Spanish in your application, you would (at least) create a “lang/es” asset. The asset contains the text to use for long and short day-names and month-names, as well as a simple JSON map, whose keys are the original (e.g. “default”) text, and whose values are the translated text. For example: [ "Ene", "Feb"… ] short-months ! … { "hi" : "¡Hola, mundo!", "bye" : "Hasta la vista...", }

To utilize this asset, two steps are required. First, you must tell 8th to use the Spanish language asset: "es" s:lang. Second, you need to tell 8th that you want to translate a string: "hi" s:intl. This latter phrase will produce the string ¡Hola, mundo!. You can support as many languages as you wish, and as many strings as you like. The clear JSON syntax makes the translator’s work easier, we hope you’ll agree! The arrays of strings for the localized names of weekdays and months must be loaded by the asset, and the vars to load into are called short-days, short-months, long-days and longmonths. If you switch back to English, you should reset those to the same named item suffixed by -en. For example, short-days-en.

10.4 Search, replace and parameterized substitutions 8th lets you search and replace in strings in several ways, and you are encouraged to look in the comprehensive word-list at the end of this manual for all the details. However, a few notes are in order: First, searching and replacing can be done with either a string or a regex. The regularexpression syntax is that of PCRE, and sub-matches are supported. That is to say, one may search using a regular-expression such as /(c\S+) and (d\S+/) against the string "cat and dog" using s:search, and it will say it found the expression at position 0 (the start of the text). Of course one could also search for a literal string. Using the same regex and string but with r:match instead, one gets the result “3”, meaning there are three matches. Match “0” is the entire matched expression, and other matches correspond to capturing parentheses. In this example, giving the regex and saying 1 r:@ will give the result cat. Just like in Perl or other similar tools. Substitution is done using s:replace (to replace just once) and s:replace! (to replace all occurrences). The pattern may be either a string or a regex, but the replacement must be a string. 8th also has something called “templated substitution”, using the word s:tsub. This is a very powerful substitution mechanism which allows you to replace parameters in the template by position or by name. For example: — 37 —

The 8th Manual: Text and strings

"Hi there, %name%!"

{ "name" : "Mary" } s:tsub

This will produce the string "Hi there, Mary". While this specific example could also trivially be accomplished using s:+, the templated substitution can do much more. Localized sentences often have different word order; the s:tsub approach to building localized strings is flexible enough to handle that and many other similar problems. In addition, 8th can do “printf”-style substitutions. For example: 123 "Joe" "%s owes me $%d" s:strfmt

will result in the string "Joe owes me $123". You can either put the substitutions on the stack or in an array, and there are quite a few formatting options. See the sample “strfmt.8th” for more details.

10.5 Strings vs. Buffers 8th treats strings and buffers similarly in many respects. In particular, it is possible to ask for the “n’th” character of a string, or the “n’th” byte of a buffer. Though the syntax is similar, there are big differences between the two. As mentioned above, strings in 8th are encoded using “UTF-8”, which is a variable-length encoding designed to allow every Unicode character to be represented, while requiring only one byte to encode “Latin-1” (e.g. most European language characters). This has important ramifications. First is that accessing an arbitrary character of a string requires traversing the entire string up to that character. It is not possible to know where a particular character will begin until it has been encountered. Thus, due to the use of UTF-8, the words s:@ and s:! are slow — especially so as the length of the string grows. An optimization is in place to make random-character access fast if (and only if) all characters in the string have the same length in terms of their UTF-8 encoding. Secondly, arbitrary data should not be stuck into a string. Since it will be interpreted as UTF-8, unpleasant side-effects will probably occur. buffers do not suffer from these issues, since a buffer is nothing more than a container for a specific number of bytes. Accessing any byte is extremely fast. However, a buffer makes no assumptions as to its contents' meaning, so one may not assume the “n’th” byte is the “n’th” character (unless it can be assumed a Latin-1 or similar encoding was used on the data).

Besides all the above, buffers are fixed in size, while strings are dynamic. Both types accept the set-wipe word, which tells 8th that the data in this item is sensitive and should be zeroed out before releasing it back to its pool. This is important when hardening an application for security reasons.

10.6 Character encoding As mentioned before, 8th encodes strings using UTF-8. However, the real world contains text in a wide variety of encodings, and you may need to read or write in an encoding other than UTF8. 8th provides the word b:conv to perform these conversions. It is in the buffer namespace because strings are always UTF-8 encoded. Linux and Raspberry Pi users take note: this functionality is only available if you have installed the libiconv library. You must download, build and install it before b:conv will work! If you wish to distribute an application for Linux or RPI, note that this is a runtime requirement. — 38 —

The 8th Manual: Text and strings

You convert a buffer from one named encoding to another named encoding using b:conv, which will return a buffer with the converted text, or null followed by a numeric error code. The error code will be one of: 1. The “libiconv” library is not installed (Linux or RPI only) 2. The character encoding given was not recognized 3. The text could not be converted between the character encodings given The encodings available differ between operating systems, which is a bit of a complication for you the programmer. Here is a list of encodings available by OS: 10.6.1 macOS, IOS, Linux and Raspberry Pi The encodings are those provided by libiconv on the system, and there may be others available to you on a specific system. However, as of now the list of values you can pass to b:conv follows (items on the same line are aliases for the same encoding): • 850 CP850 IBM850 CSPC850MULTILINGUAL • 862 CP862 IBM862 CSPC862LATINHEBREW • 866 CP866 IBM866 CSIBM866 • ANSI X3.4-1968 ANSI X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO 646.IRV:1991 US US-ASCII CSASCII • ARABIC ASMO-708 ECMA-114 ISO-8859-6 ISO-IR-127 ISO8859-6 ISO 8859-6 ISO 88596:1987 CSISOLATINARABIC • ARMSCII-8 • BIG-5 BIG-FIVE BIG5 BIGFIVE CN-BIG5 CSBIG5 • BIG5-HKSCS BIG5-HKSCS:2008 BIG5HKSCS • BIG5-HKSCS:1999 • BIG5-HKSCS:2001 • BIG5-HKSCS:2004 • C99 • CHINESE GB 2312-80 ISO-IR-58 CSISO58GB231280 • CN GB 1988-80 ISO-IR-57 ISO646-CN CSISO57GB1988 • CN-GB EUC-CN EUCCN GB2312 CSGB2312 • CN-GB-ISOIR165 ISO-IR-165 • CP1131 • CP1133 IBM-CP1133 • CP1250 MS-EE WINDOWS-1250 • CP1251 MS-CYRL WINDOWS-1251 • CP1252 MS-ANSI WINDOWS-1252 — 39 —

The 8th Manual: Text and strings

• CP1253 MS-GREEK WINDOWS-1253 • CP1254 MS-TURK WINDOWS-1254 • CP1255 MS-HEBR WINDOWS-1255 • CP1256 MS-ARAB WINDOWS-1256 • CP1257 WINBALTRIM WINDOWS-1257 • CP1258 WINDOWS-1258 • CP1361 JOHAB • CP154 CYRILLIC-ASIAN PT154 PTCP154 CSPTCP154 • CP819 IBM819 ISO-8859-1 ISO-IR-100 ISO8859-1 ISO 8859-1 ISO 8859-1:1987 L1 LATIN1 CSISOLATIN1 • CP874 WINDOWS-874 • CP932 • CP936 MS936 WINDOWS-936 • CP949 UHC • CP950 • CYRILLIC ISO-8859-5 ISO-IR-144 ISO8859-5 ISO 8859-5 ISO 8859-5:1988 CSISOLATINCYRILLIC • ECMA-118 ELOT 928 GREEK GREEK8 ISO-8859-7 ISO-IR-126 ISO8859-7 ISO 8859-7 ISO 88597:1987 ISO 8859-7:2003 CSISOLATINGREEK • EUC-JP EUCJP EXTENDED UNIX CODE PACKED FORMAT FOR JAPANESE CSEUCPKDFMTJAPANESE • EUC-KR EUCKR CSEUCKR • EUC-TW EUCTW CSEUCTW • GB18030 • GBK • GEORGIAN-ACADEMY • GEORGIAN-PS • HEBREW ISO-8859-8 ISO-IR-138 ISO8859-8 ISO 8859-8 ISO 8859-8:1988 CSISOLATINHEBREW • HP-ROMAN8 R8 ROMAN8 CSHPROMAN8 • HZ HZ-GB-2312 • ISO-10646-UCS-2 UCS-2 CSUNICODE • ISO-10646-UCS-4 UCS-4 CSUCS4 • ISO-2022-CN CSISO2022CN • ISO-2022-CN-EXT — 40 —

The 8th Manual: Text and strings

• ISO-2022-JP CSISO2022JP • ISO-2022-JP-1 • ISO-2022-JP-2 CSISO2022JP2 • ISO-2022-KR CSISO2022KR • ISO-8859-10 ISO-IR-157 ISO8859-10 ISO 8859-10 ISO 8859-10:1992 L6 LATIN6 CSISOLATIN6 • ISO-8859-11 ISO8859-11 ISO 8859-11 • ISO-8859-13 ISO-IR-179 ISO8859-13 ISO 8859-13 L7 LATIN7 • ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO 8859-14 ISO 8859-14:1998 L8 LATIN8 • ISO-8859-15 ISO-IR-203 ISO8859-15 ISO 8859-15 ISO 8859-15:1998 LATIN-9 • ISO-8859-16 ISO-IR-226 ISO8859-16 ISO 8859-16 ISO 8859-16:2001 L10 LATIN10 • ISO-8859-2 ISO-IR-101 ISO8859-2 ISO 8859-2 ISO 8859-2:1987 L2 LATIN2 CSISOLATIN2 • ISO-8859-3 ISO-IR-109 ISO8859-3 ISO 8859-3 ISO 8859-3:1988 L3 LATIN3 CSISOLATIN3 • ISO-8859-4 ISO-IR-110 ISO8859-4 ISO 8859-4 ISO 8859-4:1988 L4 LATIN4 CSISOLATIN4 • ISO-8859-9 ISO-IR-148 ISO8859-9 ISO 8859-9 ISO 8859-9:1989 L5 LATIN5 CSISOLATIN5 • ISO-IR-14 ISO646-JP JIS C6220-1969-RO JP CSISO14JISC6220RO • ISO-IR-149 KOREAN KSC 5601 KS C 5601-1987 KS C 5601-1989 CSKSC56011987 • ISO-IR-159 JIS X0212 JIS X0212-1990 JIS X0212.1990-0 X0212 CSISO159JISX02121990 • ISO-IR-166 TIS-620 TIS620 TIS620-0 TIS620.2529-1 TIS620.2533-0 TIS620.2533-1 • ISO-IR-87 JIS0208 JIS C6226-1983 JIS X0208 JIS X0208-1983 JIS X0208-1990 X0208 CSISO87JISX0208 • JAVA • JISX0201-1976 JIS X0201 X0201 CSHALFWIDTHKATAKANA • KOI8-R CSKOI8R • KOI8-RU • KOI8-T • KOI8-U • KZ-1048 RK1048 STRK1048-2002 CSKZ1048 • MAC MACINTOSH MACROMAN CSMACINTOSH • MACARABIC • MACCENTRALEUROPE • MACCROATIAN • MACCYRILLIC • MACGREEK • MACHEBREW — 41 —

The 8th Manual: Text and strings

• MACICELAND • MACROMANIA • MACTHAI • MACTURKISH • MACUKRAINE • MS KANJI SHIFT-JIS SHIFT JIS SJIS CSSHIFTJIS • MULELAO-1 • NEXTSTEP • TCVN TCVN-5712 TCVN5712-1 TCVN5712-1:1993 • UCS-2-INTERNAL • UCS-2-SWAPPED • UCS-2BE UNICODE-1-1 UNICODEBIG CSUNICODE11 • UCS-2LE UNICODELITTLE • UCS-4-INTERNAL • UCS-4-SWAPPED • UCS-4BE • UCS-4LE • UNICODE-1-1-UTF-7 UTF-7 CSUNICODE11UTF7 • UTF-16 • UTF-16BE • UTF-16LE • UTF-32 • UTF-32BE • UTF-32LE • UTF-8 • VISCII VISCII1.1-1 CSVISCII 10.6.2 Windows These encodings utilize Windows native conversion routines. Items on the same line are aliases for the same encoding: • 437 CP437 CSPC8CODEPAGE437 IBM437 • 850 CP850 CSPC850MULTILINGUAL IBM850 • 852 CP852 CSPCP852 IBM852 • 855 CP855 CSIBM855 IBM855 — 42 —

The 8th Manual: Text and strings

• 857 CP857 CSIBM857 IBM857 • 860 CP860 CSIBM860 IBM860 • 861 CP861 CSIBM861 IBM861 • 862 CP862 CSPC862LATINHEBREW DOS-862 IBM862 • 863 CP863 CSIBM863 IBM863 • 865 CP865 CSIBM865 IBM865 • 866 CP866 CSIBM866 IBM866 • 869 CP869 CSIBM869 IBM869 • ANSI X3.4-1968 ANSI X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO 646.IRV:1991 US US-ASCII CSASCII • ASMO-708 ISO-8859-6 ISO 8859-6 ISO 8859 6 • BIG5 • BIG5-HKSCS BIG5HKSCS • CP-GR • CP-IS • CP1025 • CP1125 • CP1133 IBM-CP1133 • CP1200 • CP12000 • CP12001 • CP1201 • CP1250 MS-EE WINDOWS-1250 • CP1251 MS-CYRL WINDOWS-1251 • CP1252 MS-ANSI WINDOWS-1252 • CP1253 MS-GREEK WINDOWS-1253 • CP1254 MS-TURK WINDOWS-1254 • CP1255 MS-HEBR WINDOWS-1255 • CP1256 MS-ARAB WINDOWS-1256 • CP1257 WINBALTRIM WINDOWS-1257 • CP1258 WINDOWS-1258 • CP1361 JOHAB • CP154 CYRILLIC-ASIAN PT154 CSPTCP154 PTCP154 • CP50221 — 43 —

The 8th Manual: Text and strings

• CP51932 • CP65001 • CP737 • CP775 • CP819 IBM819 ISO-8859-1 ISO-IR-100 ISO8859-1 ISO 8859-1 ISO 8859 1 ISO 8859-1:1987 L1 LATIN1 CSISOLATIN1 • CP853 • CP858 • CP864 CSIBM864 IBM864 • CP874 WINDOWS-874 • CP875 • CP932 • CP936 MS936 WINDOWS-936 • CP949 UHC • CP950 • CSISO2022JP ISO-2022-JP • CSPC775BALTIC • CSWINDOWS31J • DOS-720 • EUC-CN • EUC-JP • EUC-KR • GB18030 • GB2312 • GBK • HZ-GB-2312 • IBM-THAI • IBM00858 • IBM00924 • IBM01047 • IBM01140 • IBM01141 • IBM01142 • IBM01143 — 44 —

The 8th Manual: Text and strings

• IBM01144 • IBM01145 • IBM01146 • IBM01147 • IBM01148 • IBM01149 • IBM037 • IBM1026 • IBM273 • IBM277 • IBM278 • IBM280 • IBM284 • IBM285 • IBM290 • IBM297 • IBM420 • IBM423 • IBM424 • IBM500 • IBM737 • IBM775 • IBM870 • IBM871 • IBM880 • IBM905 • ISO-2022-JP-MS • ISO-2022-KR • ISO-8859-13 ISO8859-13 ISO 8859-13 ISO 8859 13 • ISO-8859-15 ISO8859-15 ISO 8859-15 ISO 8859 15 • ISO-8859-2 ISO8859-2 ISO 8859-2 ISO 8859 2 • ISO-8859-3 ISO8859-3 ISO 8859-3 ISO 8859 3 • ISO-8859-4 ISO8859-4 ISO 8859-4 ISO 8859 4 — 45 —

The 8th Manual: Text and strings

• ISO-8859-5 ISO8859-5 ISO 8859-5 ISO 8859 5 • ISO-8859-7 ISO8859-7 ISO 8859-7 ISO 8859 7 • ISO-8859-8 ISO8859-8 ISO 8859-8 ISO 8859 8 • ISO-8859-8-I ISO8859-8-I ISO 8859-8-I ISO 8859 8-I • ISO-8859-9 ISO8859-9 ISO 8859-9 ISO 8859 9 • ISO2022-JP • ISO2022-JP-MS • ISO2022-KR • ISO8859-6 • KOI8-R • KOI8-U • KS C 5601-1987 • MACINTOSH • MS50221 • MS51932 • MS932 • SHIFT JIS SHIFT-JIS SHIFT JIS SJIS • SHIFT JIS-MS SJIS-MS SJIS-WIN SJIS-OPEN • UCS-2 UCS2 • UCS-2BE UCS2BE • UCS2LE UCS-2LE • UCS-4 UCS4 • UCS-4BE UCS4BE • UCS-4LE UCS4LE • UNICODEFFFE • UTF-16 UTF16 • UTF-16BE UTF16BE • UTF16LE UTF-16LE • UTF-32 UTF32 • UTF-32BE UTF32BE • UTF32LE UTF-32LE • UTF-8 UTF8 • WINDOWS-31J — 46 —

The 8th Manual: Text and strings

• WINDOWS-50221 • WINDOWS-51932 • WINDOWS-932 • X-CHINESE CNS • X-CP20001 • X-CP20003 • X-CP20004 • X-CP20005 • X-CP20261 • X-CP20269 • X-CP20936 • X-CP20949 • X-CP50227 • X-EBCDIC-KOREANEXTENDED • X-EUROPA • X-IA5 • X-IA5-GERMAN • X-IA5-NORWEGIAN • X-IA5-SWEDISH • X-ISCII-AS • X-ISCII-BE • X-ISCII-DE • X-ISCII-GU • X-ISCII-KA • X-ISCII-MA • X-ISCII-OR • X-ISCII-PA • X-ISCII-TA • X-ISCII-TE • X-MAC-ARABIC • X-MAC-CE • X-MAC-CHINESESIMP • X-MAC-CHINESETRAD — 47 —

The 8th Manual: Text and strings

• X-MAC-CROATIAN • X-MAC-CYRILLIC • X-MAC-GREEK • X-MAC-HEBREW • X-MAC-ICELANDIC • X-MAC-JAPANESE • X-MAC-KOREAN • X-MAC-ROMANIAN • X-MAC-THAI • X-MAC-TURKISH • X-MAC-UKRAINIAN • X CHINESE-ETEN

10.6.3 Android These are the encodings available on at least one Android system. Some may not be available, or other may — it depends on the specific system: • Adobe-Standard-Encoding • Big5 • Big5-HKSCS • BOCU-1 • CESU-8 • cp1363 • cp851 • cp864 • EUC-JP • EUC-KR • GB18030 • GBK • hp-roman8 • HZ-GB-2312 • IBM-Thai • IBM00858 • IBM01140

— 48 —

The 8th Manual: Text and strings

• IBM01141 • IBM01142 • IBM01143 • IBM01144 • IBM01145 • IBM01146 • IBM01147 • IBM01148 • IBM01149 • IBM037 • IBM1026 • IBM1047 • IBM273 • IBM277 • IBM278 • IBM280 • IBM284 • IBM285 • IBM290 • IBM297 • IBM420 • IBM424 • IBM437 • IBM500 • IBM775 • IBM850 • IBM852 • IBM855 • IBM857 • IBM860 • IBM861 • IBM862 • IBM863 — 49 —

The 8th Manual: Text and strings

• IBM865 • IBM866 • IBM868 • IBM869 • IBM870 • IBM871 • IBM918 • ISO-2022-CN • ISO-2022-CN-EXT • ISO-2022-JP • ISO-2022-JP-1 • ISO-2022-JP-2 • ISO-2022-KR • ISO-8859-1 • ISO-8859-10 • ISO-8859-13 • ISO-8859-14 • ISO-8859-15 • ISO-8859-2 • ISO-8859-3 • ISO-8859-4 • ISO-8859-5 • ISO-8859-6 • ISO-8859-7 • ISO-8859-8 • ISO-8859-9 • KOI8-R • KOI8-U • macintosh • SCSU • Shift JIS • TIS-620 • US-ASCII — 50 —

The 8th Manual: Text and strings

• UTF-16 • UTF-16BE • UTF-16LE • UTF-32 • UTF-32BE • UTF-32LE • UTF-7 • UTF-8 • windows-1250 • windows-1251 • windows-1252 • windows-1253 • windows-1254 • windows-1255 • windows-1256 • windows-1257 • windows-1258 • x-compound-text • x-ebcdic-xml-us • x-gsm-03.38-2000 • x-ibm-1047-s390 • x-ibm-1125 P100-1997 • x-ibm-1129 P100-1997 • x-ibm-1130 P100-1997 • x-ibm-1131 P100-1997 • x-ibm-1132 P100-1998 • x-ibm-1133 P100-1997 • x-ibm-1137 P100-1999 • x-ibm-1140-s390 • x-ibm-1141-s390 • x-ibm-1142-s390 • x-ibm-1143-s390 • x-ibm-1144-s390 — 51 —

The 8th Manual: Text and strings

• x-ibm-1145-s390 • x-ibm-1146-s390 • x-ibm-1147-s390 • x-ibm-1148-s390 • x-ibm-1149-s390 • x-ibm-1153-s390 • x-ibm-1154 P100-1999 • x-ibm-1155 P100-1999 • x-ibm-1156 P100-1999 • x-ibm-1157 P100-1999 • x-ibm-1158 P100-1999 • x-ibm-1160 P100-1999 • x-ibm-1162 P100-1999 • x-ibm-1164 P100-1999 • x-ibm-1250 P100-1995 • x-ibm-1251 P100-1995 • x-ibm-1252 P100-2000 • x-ibm-1253 P100-1995 • x-ibm-1254 P100-1995 • x-ibm-1255 P100-1995 • x-ibm-1256 P110-1997 • x-ibm-1257 P100-1995 • x-ibm-1258 P100-1997 • x-ibm-12712-s390 • x-ibm-12712 P100-1998 • x-ibm-1373 P100-2002 • x-ibm-1383 P110-1999 • x-ibm-1386 P100-2001 • x-ibm-16684 P110-2003 • x-ibm-16804-s390 • x-ibm-16804 X110-1999 • x-ibm-25546 • x-ibm-33722 P12A P12A-2009 U2 — 52 —

The 8th Manual: Text and strings

• x-ibm-37-s390 • x-ibm-4517 P100-2005 • x-ibm-4899 P100-1998 • x-ibm-4909 P100-1999 • x-ibm-4971 P100-1999 • x-ibm-5123 P100-1999 • x-ibm-5351 P100-1998 • x-ibm-5352 P100-1998 • x-ibm-5353 P100-1998 • x-ibm-5478 P100-1995 • x-ibm-803 P100-1999 • x-ibm-813 P100-1995 • x-ibm-8482 P100-1999 • x-ibm-901 P100-1999 • x-ibm-902 P100-1999 • x-ibm-9067 X100-2005 • x-ibm-916 P100-1995 • x-IBM1006 • x-IBM1025 • x-IBM1097 • x-IBM1098 • x-IBM1112 • x-IBM1122 • x-IBM1123 • x-IBM1124 • x-IBM1153 • x-IBM1363 • x-IBM1364 • x-IBM1371 • x-IBM1388 • x-IBM1390 • x-IBM1399 • x-IBM33722 — 53 —

The 8th Manual: Text and strings

• x-IBM720 • x-IBM737 • x-IBM856 • x-IBM867 • x-IBM875 • x-IBM922 • x-IBM930 • x-IBM933 • x-IBM935 • x-IBM937 • x-IBM939 • x-IBM942 • x-IBM943 • x-IBM949 • x-IBM949C • x-IBM950 • x-IBM954 • x-IBM964 • x-IBM970 • x-IBM971 • x-IMAP-mailbox-name • x-iscii-be • x-iscii-gu • x-iscii-ka • x-iscii-ma • x-iscii-or • x-iscii-pa • x-iscii-ta • x-iscii-te • x-ISCII91 • x-ISO-2022-CN-CNS • x-iso-8859-11 • x-JavaUnicode — 54 —

The 8th Manual: Text and strings

• x-JavaUnicode2 • x-JIS7 • x-JIS8 • x-LMBCS-1 • x-mac-centraleurroman • x-mac-cyrillic • x-mac-greek • x-mac-turkish • x-MS950-HKSCS • x-UnicodeBig • x-UTF-16LE-BOM • x-UTF16 OppositeEndian • x-UTF16 PlatformEndian • x-UTF32 OppositeEndian • x-UTF32 PlatformEndian

— 55 —

Chapter 11: Containers

8th has several built-in container namespaces, meaning items which contain other items. All the containers in 8th can contain any kind of item: • var — a single-item at a time container • array — random access by number index • map — random access by string key • stack — LIFO access via push and pop • queue — FIFO access via push and pop • heap — sorted access via push and pop

11.1 Variables A var (a “variable” in other languages) is a single-item container. That is to say, it can contain only one thing at a time, though that “thing” can be to any 8th data type. You declare a var using either var or var, — the difference being that the first initializes the variable to the number 0, while the latter initializes the variable to whatever was on TOS at the time of the declaration. For example: "A string" var, astr

This creates a new var named astr, and initializes its contents to the string "A string". To use the value inside the var, you use the “@” word astr

@ . cr

That will print the value currently held in astr. Change the value it holds using “!” 1024 astr !

After this, astr holds the number 1024. So maybe the name “astr” is a poor choice, but you hopefully get the idea. Please note that the name which you gave the var does not refer to the contents of the var! So this code will throw an exception complaining, “Expected Array but got Variable”: [] var, an-array an-array 100 a:push

What you probably intend in this case is this: [] var, an-array an-array @ 100 a:push

The first example throws an exception because you are using an array accessor but the item called “an-array” is a var! Remember to always dereference the var before using its contents.

— 56 —

The 8th Manual: Containers

11.2 Arrays An array is a container which can hold any number of items (limited only by the memory available), and whose items are accessed by numeric index. You declare an array using JSON or by using the phrase ns:a new [ 1,2,3 ] var, a1 ns:a new var, a2

After these, a1 contains an array with three elements, all numbers, while a2 contains an array with no elements. Arrays are accessed with a:@ and a:!, as well as with a number of other more specialized words. For example one may iterate over an array: [ "one","two","three" ] ( "Item " . swap . " is " . . cr ) a:each

This will print “Item 0 is one”, etc. for each item in the array. arrays are not “sparse”, so if you put an item at index 0 and another at index 10,000, 8th will comply — but the resultant array will have 9,999 empty spots in it and will take up a lot more

memory than you might have expected.

11.3 Maps A map is a container which can hold any number of items (again, subject to available memory), and whose items are accessed by a key which is a string. You declare an map using JSON or using ns:m new { "one" : 1, "two" : 2 } var, m1 ns:m new var, m2

After these, m1 will contain a map which has two elements, and m2 will be an empty map. Analogously to arrays, maps are accessed using m:@ and m:!, as well as with more specialized words (such as m:each). See the comprehensive word-list documentation at the end of the manual for details on all the built-in array and map words.

11.4 Stacks, Queues and Heaps You’re already familiar with “the stack”. The stack type is simply an independent stack which can be used in much the same way as the regular data-stack. By default, a stack will throw an exception if you push too much onto it or pop from it when it’s empty. You can change that behavior by using the st:throwing word to disable it for a particular stack. A queue is more or less the same as a stack, except that it forces access to the items placed in it to be first in, first out. It also has most of the same words as the stack. You can make a queue behave like a circular buffer using q:overwrite. Both stacks and queues are of fixed size, which is established when they are created. A heap is different in that it does not have a fixed size, and in that access depends on the items pushed into it. You provide a word to h:new which is then used to determine the order of the items pushed. They are then accessed in order based on the word you used to initialize the heap.

— 57 —

Chapter 12: Files, databases, sockets, and various I/O

There are plenty of words to help you perform all sorts of I/O. First one should mention the simple . and putc which let you write to the console (or to a string or other item if you’ve reassigned the low-level words).

12.1 Files Regular files are handled by the various words in the f: namespace. They include the usual f:open, f:create and f:close as you might expect. They also have the ability to easily write an entire string or buffer to the file using f:write. If you want to write only a number of bytes you can do that with f:writen. Similarly, you can read directly into a string or buffer (though you need to specify how much to read). Two special words are very useful for file processing: f:slurp and f:eachline. The first “slurps” an entire file into a buffer, allowing you to process it in memory. The second lets you process a (text) file line-by-line. For example: "data-file" f:open ' process-line f:eachline f:close

This snippet opens (the existing) file "data-file" and passes each of its lines one-by-one to the word process-line (which you’ve defined somewhere else). It also shows the concatenative nature of 8th, where the output of one word is passed to the next in line. If you want, you can write a sort of inverse of f:slurp, which takes a string or buffer and a file-name, and spits the item into the file: : f:spit \ item fname -f:create swap f:write drop f:close ;

A special set of file words deals with ZIP files. You can create them, iterate their directories and extract their contents.

12.2 Databases All versions of 8th include a built-in version of SQLite. You can create and use high-speed local encrypted or non-encrypted SQL databases using the ns:db words. Additionally, “Professional” and “Enterprise” versions also support remote (or local) MySQL databases, provided you have installed the MySQL C Connector. They also support ODBC connected databases, so almost any database is available to 8th. The ODBC support is native on Windows: Linux, Raspberry Pi and macOS platforms need to have unixodbc or iODBC installed. Mobile platforms do not currently have ODBC support. "my-database" db:open ' process-one-row "SELECT * FROM mytable WHERE id=1" — 58 —

The 8th Manual: Files, databases, sockets, and various I/O

db:exec-cb db:close

Note the similarity of operation between the database and file words. You can do parameterized queries as well as simple ones. To open a MySQL database, you provide db:open with a map which describes the specific settings needed. For example: { "kind" : "mysql", "host" : "db4free.net", "db" : "eighthdev", "user" : "user8th", "db" : "eighthdev", "pwd" : "password" } db:open

To open an ODBC database, you follow the same steps as for the MySQL example above, but change the “kind” from “mysql” to “odbc”. In addition, you need to add a “dsn” key which is a string containing the DSN connection string for your particular ODBC database connection. 8th lets you easily create completely encrypted databases using the db:key and db:rekey words. The first is used immediately after db:open, and sets the encryption key to use thereafter. It will not work if the database was not already encrypted (and with that same key). The second is used to either change the encryption key of the database, or to assign one when the database had not previously been encrypted. The encryption key needs to be either the result of cr:randkey (in which case you will need to save it somewhere safe, or the result of cr:genkey. The actual encryption of the database uses AES 256-bit, GCM. The entire database is encrypted, including all metadata, making it impossible for an attacker to glean any information from it or modify it. Needless to say, the encryption key is not stored in the database, and if you lose it you will not be able to access the data! The encrypted database support is solely for SQLite local databases. There is no support for encrypted MySQL databases in 8th! Both the file and database namespaces have a err? word, which returns the specific error code (if any) from the last operation. Robust code may want to check for a non-zero value.

12.3 Sockets and network I/O Sockets are fundamentally the same as files, but the words which deal with sockets have been placed in the net namespace. This helps clarify for example whether bind is the database or the net version. If you are familiar with the typical “Unix sockets” functionality, the 8th implementation is a thin layer over that, so it should be familiar. In addition to the low-level socket words, there are some high-level ones to help make your use of internet APIs easier. net:get and net:post perform HTTP GET and POST calls, respectively. They may be used as building-blocks for other operations, for example, the libs/net utility words for JSON-RPC or SOAP. Besides get and post, there are also delete, put, and head to help you interact with RESTful services. All the words mentioned in the previous paragraph accept a map with information for the call. Note that the libs/net words may require additional fields. The fields which may be used by these net words are: bufsize cookies

Set the size of the buffer used to read (default: 65536 bytes) An @array@ of @strings@ which are cookies to be sent to the server — 59 —

The 8th Manual: Files, databases, sockets, and various I/O

Check that the certificate has not expired (default: true) The data payload (for post or put; required for them) If true, retrieve the headers from the call as a map A map containing key,value pairs of additional headers If true, then put will write over the current item If present, a buffer containing the PEM encoded certificate which the server must present in order to validate the connection rawheaders If present along with “getheaders”, will return an additional key in the header map called rawheaders which contains the headers as received from the server readcb A word which (if present) is called-back after each chunk of data has been read. It receives the net item as well as the number of bytes received so far redirs A number which determines the maximum number of redirects which will be processed. The default is 5; setting it to 0 means you need to manually handle redirections rootcert If present, a buffer containing the PEM encoded root certificate which the server cert chain must match sni If false, do not do SNI request (default is true) sniname If present, a string which gives the hostname to use for SNI. Setting this key implies a “sni” value of true to If present, a number of seconds before the connection will time-out. The default is 15 seconds url The URL of the service to connect to (required) vchain whether or not to check the certificate's chain of validity (default: false) verify If false, do not verify the SSL connection. Default is true vhost If false, do not verify the hostname of the certificate in the SSL connection. Default is true vhostname If present, a string which sets the hostname for “vhost” to check. If present, implies “vhost” is true expire data getheaders headers overwrite pincert

The keys “checkexpire”, “pincert”, “rootcert”, “sni”, “sniname”, “vchain”, “verify”, “vhost” and “vhostname” are only applicable to SSL (e.g. “https”) connections. The get, delete and head words may take a string instead of a map, due to their simpler nature. All the words are executed synchronously, and return a true and perhaps data on success, or false and an error code on failure. If an error code is returned it will be either an HTTP code or a negative number. See the topic “net: word error codes” in the “Error codes” section at the end of this manual for details. Because of the synchronous nature of the calls and because network I/O can take a long time, you should run the query in separate thread, and use the synchronization primitives to handle results. The net words are proxy-aware, but you need to tell them what proxy to use. Do this using net:proxy!, which takes a map with proxy parameters.

12.4 Serial I/O The words in the sio namespace control “serial I/O”. The sio:open word is passed a string which is the name of the serial-port to open. This is an OS-specific value: for example, COM1 on Windows or /dev/ttyS0 on Linux. It is possible to query the system for valid names using sio:enum. That will return an array of names which are valid. — 60 —

The 8th Manual: Files, databases, sockets, and various I/O

So in order to successfully use sio:open you must pass it a valid port name; however, that’s not enough. That port must also be configured to be used, and on Linux at least, you must have read-write access to the “dev” file. If the name given to sio:open does not meet those conditions, the return value will be null; otherwise, it will be a sio which is then passed to the remaining serial I/O words. Before one can use the sio:read and sio:write words, the serial port must be configured to use the correct baud-rate and other settings. This is done using sio:opts!, which takes a map whose keys represent the values to be modified. You can read the current values with sio:opts@, which returns a map with all the values which can be set. Note that not all settings are applicable to all OS platforms, due to differences in the low-level handling of serial I/O on various platforms. The most common settings to modify are: • "baud", which must be a number between 50 and 230400 (on macOS) or 4000000 (other platforms) • "bytesize", a number one of 5,6,7 or 8 • "parity", either true or false. If true, then "paritybits" is used. • "paritybits", a number one of 0 (none), 1 (odd), 2 (even), 3 (mark), 4 (space). Note that 3 and 4 are invalid on Linux • "stopbits", a number one of 0 (one), 1 (1.5), 2 (two). Note that 1.5 is only valid on Windows

12.5 Bluetooth Support for Bluetooth Classic and BLE is present in the Professional and Enterprise versions of 8th. You are urged to consult the sample code in apps/bt/bt.8th, hw/ble.8th, and hw/bluetooth.8th. On Linux and RPI you must run as root (or set appropriate system permissions) in order for BLE to work. At present, BT and BLE only work (completely) properly on Android. We are continuing to improve the cross-platform availability of this important feature! This section is still mostly empty, relying on the sample code as documentation. We will be filling it in in future versions.

— 61 —

Chapter 13: The 8th Console

“Console” is another word for the “terminal” or “command shell”. 8th provides a number of words which let you do I/O with the console. Unsurprisingly, these words are in the con namespace. You may set text attributes using color-pairs, such as red onWhite. Note that “red” by itself will not work, the “onWhite” is required! You may set or get the current text position using gotoxy and getxy. You can also move about the screen with up, down, right and left. Look in the word list for the con namespace for the complete list of capabilities. If you want to grab keys one at a time you can use con:key, and you can query their availability using con:key?. The most interesting word, perhaps, is con:accept. It lets you input up to a given amount of text while taking advantage of the console editing keys. It has a sibling, con:accept-pwd, which does not display the entered text and which marks the returned text as requiring wipe on release.

13.1 Editing keys The 8th console gives you some editing capabilities which are similar to what you may be used to from shells like bash. Here is the exhaustive list of editing keys and their function: BKSP Delete character to the left Ctrl+A Move to beginning of line Ctrl+C Cancel the input Ctrl+E Move to end of line Ctrl+K Show help for the word immediately before the cursor Ctrl+L Clear the screen Ctrl+Left Move one word left Ctrl+Right Move one word right Ctrl+V Paste from the system clipboard Down Next item in history END Move to end of line ENTER Accept the input ESC Cancel the current input, restore the original HOME Move to beginning of line Left Move left one character Right Move right one character Up Previous item in history TAB Complete the named item immediately before the cursor SHIFT+TAB Insert a literal TAB character One last thing: if you start 8th into the console, a thrown exception will not quit 8th, unlike the behavior then 8th is executing a file or an application. This is intended to make it easier to deal with mistyped JSON (for example), which would cause an exception and dump you at the OS prompt. However, pressing Ctrl+C twice in rapid succession will quit 8th, with the same effect as typing bye. Likewise, if too many exceptions are thrown in a short time, 8th will quit. — 62 —

The 8th Manual: The 8th Console

13.2 TAB completion While in the console, pressing the “TAB” key will cause 8th to attempt to perform “word completion”. It does this by taking the text you entered so far (on the current line), and taking the last space-delimited part. For example, if you entered 123 n: and pressed TAB, the completion code would take the n: and attempt to complete it. It uses the words-like word to get a list of all named items which match the prefix you typed. It then filters that list so only items whose prefix matches what you typed are in the list. If there is only one item in the list, the completion is that item. If there are no items in the list, your original prefix remains. If there are multiple items, then those items are listed and your original prefix remains.

13.3 History By default, the console remembers up to 100 lines worth of your commands. You can access previous history items using the up and down arrows, and once accessed you can edit them. By default, 8th does not save your history, but you can change that behavior by using the word con:save-history, which will save your history by appending it to the named file. You can change the number of lines the history tracks by using the -H command-line option when starting 8th. You may likewise restore the history to some previously saved (or manually edited) set, by using con:load-history to read in a named file with one history item per line, and a flag which

indicates whether to overwrite or append to the current history.

13.4 The prompt The ubiquitous ok> prompt which 8th presents in the console is actually more complex than it appears. Firstly, you as the user may change the prompt shown, by assigning a different value to the “deferred” word prompt. Before you run off and do that, however, you should know what the default prompt shows. First of all, the ok> prompt is the “normal” state of affairs. It shows when 8th is awaiting new input to interpret in the REPL. If the prompt shows anything other than ok>, it is indicating a state of incompletion. If the prompt includes the " character, it means a string was being entered but has not yet been completed. If it includes the { character, it means a map was not completely defined. Similarly, if a char91 was entered, then an array was not completely defined. Finally, if a + is included in the prompt, a word was being defined but not fully. These indicators may be expected, for example, if you are entering a long bit of text at the console and are entering it on multiple lines. They may also indicate an error. For example, if you typed ". instead of " . to terminate a string and print it.

— 63 —

Chapter 14: Cryptography

8th has some built-in facilities for encryption, based upon the well-regarded LibTomCrypt library.

14.1 Hashing The default hashing algorithm used in 8th is BLAKE2s, which was one of the SHA-3 finalists. It is very fast and secure. However, you may need to use other hashes, in which case 8th lets you choose from a number of other hash algorithms. To choose another hash algorithm, use code like: "sha1" cr:hash!

The valid values which can be passed to the word cr:hash! vary from time to time as more are added. The currently supported strings which may be used are detailed in the documentation for cr:hash!. All of the hash functions may also be used with HMAC. After having set the hash, the chosen hash function remains in force until changed. The word cr:hash commences the computation of a hash, and likewise cr:hmac commences an HMAC-hash. Further data to be hashed are passed to cr:hash+, and finally either cr:hash>s or cr:hash>b are invoked to finalize the hash and produce a result (a readable string in the first case, or a buffer with the hash data in the second).

14.2 Random data The word rand produces a cryptographically strong pseudo-random number using the “Fortuna” PRNG. The PRNG is seeded at 8th startup from the system’s entropy pool. cr:randbuf returns a buffer containing a given number of bytes of (pseudo) random data using Fortuna. rand is relatively slow. If you need higher speed and are ok with non-cryptographically secure numbers, then rand-pcg is a much better choice. It uses the PCG Random Number Generator,

which has excellent characteristics. A random “seed” is used on startup, so if you want repeatable sequences you need to initialize it using rand-pcg-seed.

14.3 Passwords and key generation There are several methods for producing an encryption key in 8th. The simplest is cr:randkey, which simply produces a buffer filled with 32-bytes of random data. One could just as easily use cr:randbuf which takes the number of bytes and returns a buffer with that many random bytes, though the key returned by cr:randkey is set to “auto-wipe”. If you want to take a user-provided password and convert it to a key, you can use cr:genkey, which implements the PBKDF2 algorithm. You provide it the user’s key, a salt string and the number of iterations, and it will return a 32-byte buffer to use as a key. To input the password,

— 64 —

The 8th Manual: Cryptography

you can use con:accept-pwd in a console-based application, or use an “edit” control in a GUI, setting “password-char” to whatever you like ('* is typical). For RSA encryption you will want to generate a key-pair using cr:rsagenkey, which takes the size of the key (1024, 2048 or 4096) and returns a pair of keys to be used with the RSA encryption words. At present there is no facility for importing RSA keys from third-party systems.

14.4 Encryption 14.4.1 Public key encryption PK encryption is done with cr:rsa encrypt, which takes an RSA public key and data to encrypt, returning an encrypted buffer. PK decryption reverses that process using cr:rsa decrypt which takes the RSA private key corresponding to the public key used to encrypt and the encrypted buffer. It returns a decrypted buffer. The SHA256 hash function is used during the RSA encryption or decryption. It is also possible to sign using cr:rsa sign, which takes the hash of a message and a private RSA key and produces a buffer which is the signature. Then one may verify that signature using cr:rsa verify, which takes the hash of the message, the public RSA key and the signature, and produces a true or false response. 14.4.2 Symmetric encryption There are several ciphers available for symmetric encryption: AES (also known as Rijndael), Twofish, Camellia, Blowfish, CAST5, DES and 3DES. The default cipher used is AES, and the key size is 256 bits. There are currently two modes available: GCM and CTR. The GCM mode authenticates the data upon decryption, so that any modification of the encrypted data renders decryption impossible. This is good, in that if decryption succeeds, you are guaranteed that the plain-text is the original. CTR mode may be used if authentication is not needed, or if it is important that even garbled plain--text be able to be retrieved. GCM encryption is accomplished with cr:>encrypt which takes data and a key and returns a crypto for further processing. That may be the addition of more data to encrypt using cr:encrypt+ or the finalization of the encryption using cr:encrypt>. As mentioned, the default cipher is AES 256-bit, GCM mode. You may also use Twofish or Camellia with the GCM encryption words. Decryption is done with the corresponding cr:>decrypt, cr:decrypt+ and cr:decrypt>. If decryption fails, TOS will contain null to indicate a problem; otherwise it will contain the decrypted data. CTR encryption is done using cr:encrypt-ctr and cr:decrypt-ctr. These are less flexible than the GCM words, in that they can only encrypt or decrypt one string or buffer at a time. Also, unlike the GCM words they require an “IV” — an “initialization vector” — which must be the same for a specific encryption-decryption to work. 14.4.3 Diffie-Hellman and ECC There are a number of words available for Diffie-Helman or ECC key-exchange, signatures and verification. Simply use the dh-genkey or ecc-genkey etc. words. Currently, the ECC routines use the NIST standard curves, even though doubts have been cast on their security. Future releases of 8th will improve the ECC routines and provide a wider variety of them. — 65 —

Chapter 15: Hardware query and control

The hardware interfacing abilities of 8th are currently relatively simple, though each new release improves them. The three major areas handled by 8th are general queries, camera control and sensors.

15.1 General queries There are a number of words whose purpose is to determine the physical nature of the device 8th is running on, for example the amount of installed RAM. They are all in the hw namespace, and amply described in the words documentation. The device’s operating system is given by os.

15.2 Camera To use a camera, first query the hardware using hw:camera? which returns null if no cameras are present, or an array of maps, one per camera. If there are cameras present, you may request the use of one with hw:camera, passing it one of the maps returned from the hw:camera? query. If the camera is available, a hw is returned which is used in subsequent camera invocations. Otherwise, null is returned. If a valid hw was returned, you may then request a picture to be taken using hw:camera-img which will invoke the callback word you gave it when a picture has been taken. This process takes varying amounts of time depending on the specific hardware in use. The callback is given an image which contains the latest picture taken, and must return true to continue taking pictures, or false to stop taking them. A “preview window” for the camera may be done by adding a gui with the kind of “preview”, and passing that gui to hw:camera-preview. 15.2.1 Raspberry Pi In order to use the camera on a Raspberry Pi, you need to first of all enable the camera with the raspi-config utility, and select “Enable Camera”. Then you need to load the appropriate kernel module: sudo modprobe bcm2835-v4l2 in order for 8th to talk to the camera.

15.3 Sensors 8th can read the following kinds of sensors: accel compass gps gyro

The accelerometer, which measures linear acceleration The compass, which measures magnetic fields The GPS or other location service The gyroscope, which measures rotational acceleration — 66 —

The 8th Manual: Hardware query and control

In order to use one of them, the steps are the same: 1. Ask for the sensor, passing a string to hw:sensor 2. If that returned a hw and not null, start the sensor using hw:start 3. Periodically ask for data using hw:poll 4. When done, relinquish the sensor using hw:close The string to pass to hw:sensor is any of the ones on the left-side of the above table. If the sensor does not exist of is unavailable, null will be returned. The data returned by hw:poll is a map whose keys are specific to the kind of sensor and are listed in the documentation for hw:poll. It is your responsibility to poll the hardware, and the polling should ideally be done in a task so as not to block the main UI.

15.4 GPIO On platforms which support “GPIO”, you may access that hardware using the words hw:gpio@, hw:gpio!, hw:gpio-cfg and hw:gpio-set. Currently only Linux, Android, and Raspberry Pi support GPIO access. These words require “root access”. So you need to have done sudo -s or the equivalent in order to take advantage of the GPIO words. Furthermore, the physical pin layout corresponding to the GPIO registers may vary between devices, and so you must know what those values are, in order to safely use these words!

15.5 I2C On platforms which support “I2C” communications with a peripheral device, you may use hw:i2c, hw:i2c@ and hw:i2c! to perform that communication. Currently only Linux and Raspberry Pi support I2C. Just as with GPIO, “root access” is required. And just as with GPIO, it is important to know the details of the hardware device with which you are communicating, since improper access may destroy the peripheral or otherwise cause damage. In addition, you must run raspi-config and enable the I2C interface, and also run modprobe i2c-dev prior to using I2C functionality. NOTE: 8th and Aaron High-Tech, Ltd. are not liable for, and take absolutely no responsibility for any damage or financial loss caused by use of these low-level hardware accessors! Please be careful to check and double-check any hardware connections and the corresponding pin numbers or registers before you use the GPIO or I2C words.

— 67 —

Chapter 16: FFI: Foreign Function Interface

The FFI, or “Foreign Function Interface” is how an 8th program communicates with third-party libraries — whether built-in to the operating system, or from a vendor or other party. Because 8th’s built-in data types do not map directly onto those used by external libraries (usually based on C types), the FFI must hook up some “plumbing” to make the data flow correctly between the 8th and the external code, and back again. Fortunately for you, doing this is reasonably simple.

16.1 Declaring and invoking FFI routines In order to access an external routine, 8th must know first of all what library that routine is in. To do that, one declares the library like so: "user32.dll" lib u32

This declaration creates a new word called u32, which when invoked will put the identifier of the external library named user32.dll on TOS. It also makes that library the one which will be used in subsequent FFI function declarations. The identifier will be 0 if the library was not located or could not be located, which may be used to perhaps choose a different library at runtime. Windows users already have k32 declared (kernel32.dll), and Linux, RPI and macOS users already have libc declared (libc.so or libc.dylib). Note: the name passed to lib may be an OS-specific one, as in the above example: user32.dll. It may also be just the base name, user32. In this latter case, the library will be searched for as follows: 1. Using the name given, user32 2. Then with the OS-specific suffix, user32.dll 3. Finally, with the “lib” prefix, libuser32.dll This allows you to write code which uses a common shared-library across platforms without worrying about the OS naming details. Functions within that library are then declared as follows: u32 drop "NNN" "SetClipboardData" func: setClipData

The first line tells 8th that subsequent FFI declarations will use the library loaded by u32. Each declaration consists of a parameter list, the exported name of the routine in the library, and the name of the new word which 8th will use to access that routine.

— 68 —

The 8th Manual: FFI: Foreign Function Interface

16.2 Parameters The parameter list mentioned in the previous section is simply a string, where each letter indicates the type of the item passed or received. 8th takes care of translating between its internal data representations and those of the external library, based upon this list. The first character in the parameter list is the return value. That may be one of: D F N P V Z

“double”, an 8-byte IEEE floating-point value “float”, a 4-byte IEEE floating-point value number, the system default integer type (4 byte for 32-bit, 8 byte for 64-bit) “pointer”, the return value is a pointer (will be returned as a number “void”, or “no return value” string

Any other value will result in an “out of bounds” exception being thrown. The rest of the parameter list is the type of each parameter, as expected by the receiving external function. Conversions from 8th types to these will be performed at run-time. Valid types are: B D F L N P S W Z 8 4 2 1 ?

Buffer with count (C “unsigned char *” then “int” with buffer length) Double floating-point (C “double”) Floating-point (C “float”) System-default long number (32 or 64-bit integer, C “long” type) System-default number (32 or 64-bit integer, C “int” type) Pointer (C “void *”, etc) String with count (C “char *” then “int” with string length) Word (C function pointer, e.g. “void (*)()”) String (C “char *”) The numeric type (including length for B and S types) is 8 bytes The numeric type “” is 4 bytes long The numeric type “” is 2 “” The numeric type “” is 1 “” The numeric type “” is as big as a “size_t”

If the parameter is lower-case, it indicates that the value is a pointer to that type. In that case, if the value is numeric then the original number will be modified (if the called function modifies the pointed-to value). If a numeric modifier is given, it must appear after the item it modifies. For example, “N8” means the item is a number which is 8-bytes long. Similarly, “B?” means to treat the buffer as a pointer to the contents, followed by a length which is as big as a “size_t”. The parameter list describes what the external function expects. At run-time, the FFI verifies it can convert between the item on the stack and its corresponding parameter type. If it cannot, an “out of bounds” exception is thrown. If you incorrectly describe the FFI signature of the external function, the likelihood is that 8th will crash. If null is given as a parameter, it will be considered the equivalent of a NULL pointer.

16.3 Dealing with arbitrary data (“structs”, etc.) Because the 8th data types do not map directly to external types, you may need to do further remapping. Specifically, if an external routine returns a C “struct”, you will have to split it apart — 69 —

The 8th Manual: FFI: Foreign Function Interface

in order to get at the data you need. This is easily done using the pack and unpack words, something like this: \ Routine returns struct with four 32-bit int values "iiii" unpack

After this, there will be a number on TOS with the value 16 (the number of bytes processed), and an array under it containing four integers, corresponding to the format string passed to unpack. The format could also have been specified as "4i". Similarly, if you need to pass a “struct” from 8th to an FFI routine, you will need to create a buf with appropriate data, using pack to convert an array with the struct’s fields. You would then tell the FFI that the function took a pointer, and 8th’s FFI would convert the buf appropriately. The format string for pack and unpack words has the syntax: {[0-9]*x}+. That means that each element may have a “count”, which is an integer saying how many times to repeat the element, followed by “x” which is the element specifier. This “count, element” group may be repeated as many times as necessary to complete the layout, and there must be at least one such group (and the “count” if omitted defaults to “1”). Valid element specifiers, their meanings and the types they become with unpack are: b B c d f h i I l L p s w W x *

byte byte char eight-byte IEEE float four-byte IEEE float unpack only: reverse hex-dump four-byte integer four-byte integer, big-endian eight-byte integer eight-byte integer, big-endian pointer (to buffer or string) size bytes (for next specifier; count is number of size bytes) two-byte integer two-byte integer, big-endian ignore byte use entire item size (if a string or buffer)

buf number string number number number number number number number X number number

If the “s” or “S” size-byte specifiers are used, the preceding count, if any, is the number of bytes in that size (defaults to one byte). If a “b” or “c” specifier is used, then the number format becomes x:y, where “x” is the repeat count, and “y” is the number of bytes. If “y” is *, then the entire buffer or string is used. In that case, it is recommended to make sure the item is the correct size desired.

16.4 Custom libraries One use of the FFI interface is to utilize code you’ve written in C in order to do some processing which might be otherwise cumbersome to do in 8th alone. An example might be image processing. When designing your own custom libraries to work with 8th, take into account the fact that 8th can parse JSON efficiently. Thus, if you wish to transfer a “struct” from C to 8th, it may be worthwhile to convert that to a JSON representation first, in your C code, and then return the JSON string. — 70 —

The 8th Manual: FFI: Foreign Function Interface

16.5 Java interface (Android only) It is possible to access arbitrary Java code from within 8th, using the Java FFI words jclass, jmethod and jcall. These follow the JNI conventions, so you should be familiar with those before trying to use them. As an example, to call the Thread.sleep method, you could do this: \ First get the class on the stack: "java/lang/Thread" jclass \ And now make a method item: "sleep" "(J)V" jmethod \ And finally, invoke the method: [ 200 ] swap jcall

This is particularly useful if you want to enhance your Android application using any APIs which 8th doesn’t expose. Simply write a Java class which performs whatever you need done, modify the manifest file accordingly if necessary, and include an appropriate Java invocation in your code to run the Java code. Take advantage of the easy JSON interfaces in both Android and 8th to make passing complex results back to 8th.

16.6 Danger! Passing data across the FFI must be done with care. You have no guarantee that the external routine will behave nicely, so data returned to you should be checked to ensure you have been given something reasonable. Certainly you should not pass a returned string to eval, as that allows the external library direct access to your application’s internals! As a rule you will also want to check that the library you desire to load was in fact loaded. A wise precaution would be to also check that the version of the library is what you expected (if the external library provides a routine to give that information). If an FFI word is invoked and either the library is not loaded, or the function cannot be found, 8th will throw an exception. Furthermore, you must be careful when defining the string used to declare the parameters for the FFI function. An incorrect parameter declaration can cause 8th to crash.

— 71 —

Chapter 17: Graphical User Interface: GUI

17.1 Overview A gui is the foundation of writing a GUI (graphical user interface) in 8th. However, the words in the g: namespace are useful outside of guis. In general, those g: words which draw may also be used for image output as well. Drawing within a gui needs to be done within a draw or draw-all event. Those events are passed the gui on which to draw, and the drawing words are effective then. If you attempt to draw on a gui outside of one of these events, you will find your drawing does not take effect. The correct technique is to keep track of what you want to draw, and then perform the drawing in one of the draw events (possibly forcing them by invoking g:invalidate on the gui in question.

17.2 Defining a GUI A gui item is declared in your code as a map, something like this: { "kind" : "win" , "top" : 10 , … [ { "kind" : "btn" , "bounds" : "0, 0, parent.width, parent.height" , … } ] } var, gui-object gui-object is a variable which holds an map; it is not yet a gui. You could also, if you want, construct the map manually in code, though that is more complex and slower than using the JSON notation. When you want the gui, you use g:new gui-object @ g:new var, gui

At this point you have a gui in the “gui” variable, and you can manipulate it (show or hide it, interact with it etc.). Building a GUI in this manner is extremely flexible, but somewhat tedious. So we have added a “GUI Builder” application for your use. You run it like this: 8th bin/guibuilder.8th

It is still under development, so don’t expect it to work as smoothly as you might like. However, it does let you position GUI elements on a canvas and save them to a file, which you can then incorporate into your own program. You can set various properties of the GUI elements, including making one element the child of another (requires you type the name of the parent in an edit box). It currently handles one GUI page at a time.

— 72 —

The 8th Manual: Graphical User Interface: GUI

17.3 Overview of GUI items These are the gui items you can create in the current version of 8th. You create them by setting the "kind" key in the map to one of the following values (note: case is significant): box

An empty box (panel) in which you may place other items

btn

A push-button with a text label

codeeditor

A control which lets you edit code (or other text)

color combo

A color-chooser control A combo-box; has an edit field and a drop-down list of items

concertina

Panel with expandable sections

edit

An edit-box, which may be multi-line

filebrowser

File-browser lets you select files or directories

filename group

Contains a file-name A “group-box”, visually groups items together

html

A very lightweight HTML displayer

image

A control which can show various kinds of graphics

label

A label, usually intended to label another item

lasso

A control which lets you select multiple other controls

list

A list-box; has a scrollable list of items

menubar preferences

A menu bar A control which lets you create a preference panel in the style of macOS

progressbar

Shows a progress bar

property

A panel that holds a list of propertycomponent objects

scroll

A scroll-bar; use it to control some other item

slider

A slider control for changing a value

splash

Splash screen

stack

A stacked-GUI component, which lets you push and pop GUIs with transitions System-level tray icon, where supported

systemtrayicon

table

Tabbed item A table-style list control

toggle

Toggle switch, like a radio-button

toolbar

A bar containing icons which are buttons

tree

A “tree-view”, used for showing hierarchical data

view

A viewport, which lets you view a portion of a bigger component

web

Web browser Top-level window

tab

win

— 73 —

The 8th Manual: Graphical User Interface: GUI

17.4 GUI Attributes and events The various attributes of each gui item are set in the gui map, using the familiar JSON syntax of "key" : value,. There are a number of attributes which are common to all gui items, and many which are specific to a particular gui. An “event” is when “something happens” to your gui item. For example, the user pushes a button or resizes the window. Just as with attributes, there are some events which are common to all guis and some which are specific. You may define the event callback to use in one of three ways: 1. A string, which is the name of a word which will be looked up when the gui is created 2. Encapsulated code in ( … ) to create an anonymous typeword. 3. Use ' to take the value of an existing word. In this case you must be careful to leave whitespace after the name of the word All event callbacks are passed the gui of the item which received the event as the first parameter — that is, it is always the “bottom-most” item on the stack of the callback. The stack the callback uses is private to that callback, and will not affect any other stacks. The default size of the stacks used for callbacks is 128 items. This can be changed on the command line (-r option). However, it is not recommended to change this. Rather, it is prudent to do as little processing and stack manipulation as possible during an event callback. Consider using a task or g:do to move processing from a callback to another thread of execution. 17.4.1 Common attributes alpha

A number from 0 (completely transparent) to 1 (normal)

bg

The “background color” for this item. You can learn how to specify colors here An expression which is evaluated as the boundaries of the item, relative to its parent. The expression has four elements separated by commas, “left,top,right,bottom”. Note that the dimensions are not “width,height” but “right, bottom”. See the section below for a detailed discussion

bounds

center

If true, positions this item in the center of its parent (the screen if this is a window)

cursor

Sets the mouse cursor of the component to one of the shapes listed in g:setcursor

draggable

If true, then this item may be dragged with the mouse; default is false

effect

If present, one of "glow" or "shadow"

enabled

Is the item enabled or disabled. A disabled item cannot be interacted with, and usually shows as greyed-out

fg

The “foreground color” for this item

font

The font to use for this item. See the section on fonts for details — 74 —

The 8th Manual: Graphical User Interface: GUI

fullscreen

Attempt to make this item occupy the entire screen

high

The height of the item, in pixels

laf

A number from 1 to 3 indicating the look-and-feel to apply. You can set the default look-and-feel for all items by using g:laf!, and you can create your own

left

The left-edge of the item, in pixels

max-high

Maximum height in pixels

max-wide

Maximum width in pixels

min-high

Minimum height in pixels

min-wide

Minimum width in pixels

multi

For “edit”, “list” and “tree” items, sets “multi-line” mode

name

A name by which you may refer to this item, either in a bounds expression or using child

ontop

A true value makes this item “top-most”, e.g. it will try to remain above other components

opaque

If true, tells the painting system this component covers its entire background with solid color. The default is false

resize-border

If not zero, a “resize-border” that many pixels wide will be put around the entire item so it can be resized If not zero, a “resize-corner” that number of pixels wide and high will be put in the lower-right corner of the item so it can be resized

resize-corner resize-edge

An array of strings telling where to put a “resizing-edge”. Values may be any combination of left, right, top or bottom

text-color

For “treeview”, “button”, “codeeditor”, “combo”, “group”, “label”, “list”, “slider”, “tab”, “edit”, “toolbar”, “toggle” sets the color of the text

timer-period

Number of milliseconds between timer callbacks (by default 0, no callbacks)

tooltip

Text to show when the mouse hovers over this item for a short period

top

The top-edge of the item, in pixels

visible wants-kbd

Should this item be shown If this is true, will allow that item to receive keyboard focus

wide

The width of the item, in pixels

17.4.2 Common events Each event’s name and stack-effect diagram are given, followed by the description of the event: click

gui x y

--

For btn or toggle: gui

--

For toolbar buttons: gui itemID — 75 —

--

The 8th Manual: Graphical User Interface: GUI

Happens when the item is clicked. For a toolbar the itemID of the menu item is also passed. draw

gui

--

When the item is to be drawn. You can use the drawing words in the gui namespace draw-all

gui

--

Same as draw, but allows drawing over child items as well front

gui

--

Item was brought to the front init

gui

--

Item finished initializing its GUI; issued after first draw key-pressed

gui keycode keycharacter --

A key was pressed long-click

gui x y

--

Mouse pressed more than 200 msec mouse-dbl-click

gui x y --

The mouse button was double-clicked inside this item mouse-down

gui x y --

The mouse button was pressed inside this item mouse-drag

gui x y --

The mouse button was pressed and then dragged inside this item mouse-enter

gui --

The mouse entered this item mouse-exit

gui --

The mouse exited this item mouse-moved

gui x y --

The mouse was moved inside this item mouse-up

gui x y --

The mouse button was released inside this item mouse-wheel

gui x y --

The mouse wheel was moved inside this item moved

gui top left --

Item was moved pinch

gui x y dir --

Item was “pinched”. Passed the direction of the pinch: 0=in,1=out size

gui width height --

Item’s size has changed swipe

gui dir

--

— 76 —

The 8th Manual: Graphical User Interface: GUI

Mouse swiped. Is passed direction of the swipe: 0=left, 1=right, 2=up and 3=down

17.4.3 Bounds expressions The bounds attribute takes a string expression which is evaluated by the JUCE library (not by 8th!), and can be used to position and size the component in either a relative or absolute way. The string is of the general form "left,top,right,bottom". Those values may be absolute numbers of pixels or relative to some other component. To position relative to another component, use its name (as taken from the name attribute. The name of the item must be unique in any particular gui, otherwise the positioning will not work as you expect. The special name parent refers to the item which is the parent of this one, that is to say, the one in whose children array this item may be found. You may refer to the following parts of any named component (omitting a name means refer to this item): left, right, top, bottom, width, height. To refer to a component named “joe” simply prefix the name and a period: joe.left for example. Finally, you can use simple mathematical expressions to modify the value. For example parent.width/2 to set some dimension to half the width of the parent. Note also that coordinates are relative to the parent, so 0,0,200,100 is an absolute size, starting at the top,left corner of the parent component and extending to 200 pixels right of it and 100 pixels down. You can also use mathematical functions, for example max(a.left,b.left) If you give an invalid expression, 8th will throw an exception. One may use either bounds or the specific top, etc.; combining them only leads to confusion, as the bounds attribute will override the others. If the gui does not have a bounds expression, and also does not have a wide or high — then it is assumed that the programmer wanted the item to fill its parent. This is a convenience, but could cause confusion if you are unaware of this behavior.

17.5 GUI Components The components listed in this section are ones you can use in your own GUI creations, by appropriately setting the “kind” key in the map from which you create the gui. 17.5.1 Box Kind: "box". It is just an empty box (panel) which can be used to position other components. It has no special attributes.

— 77 —

The 8th Manual: Graphical User Interface: GUI

Events: item-drag-enter

gui dragged --

Another item was dragged onto this item item-dropped

gui dragged --

Item was dropped onto this item focus-gained

gui

--

This item gained keyboard/mouse focus focus-lost

gui

--

This item lost keyboard/mouse focus

17.5.2 Button Kind: "btn". A regular push-button, with a text label. Attributes: adjustwidth

If true, adjusts the width of the button based on the width of the label

autotoggle

Should the button auto-toggle on click

fit-text

If true, adjust the font size so the text all fits

group

The number of the “group” this button belongs to

img

what image to show in the button (default: none)

initial-delay

how long to wait in msec after the mouse is pressed before triggering the next click. If this is zero, auto-repeat is disabled

label

Text to show as the label of the button if this is greater than 0, the auto-repeat speed will get faster, the longer the button is held down, up to the minimum interval specified here

min-delay on

Toggle the button to the “on” state. If it is in a group, the other buttons in the group will be turned off

repeat-delay

how frequently subsequent repeated clicks should be triggered

scale

should any image be scaled (default: false)

trig-mouse-down

if true, the “click” event will happen as soon as the mouse button is depressed

Events: click

gui

--

When the item is clicked focus-gained

gui

--

This item gained keyboard/mouse focus — 78 —

The 8th Manual: Graphical User Interface: GUI

focus-lost

gui

--

This item lost keyboard/mouse focus

17.5.3 Code editor Kind: "codeeditor". A text-editor designed for code editing Attributes: line-numbers

Show line numbers or not. false by default

ro

If true, the editor is read-only

sb-thick

The number of pixels thick the scroll-bar should be when shown

text

Initial text content; no content by default

17.5.4 Color selector Kind: "color". A color-selection widget Attributes: color

Initial color shown in the widget

Events: changed

gui clr

--

Called whenever the user changes the color shown

17.5.5 Combo Kind: "combo". A combo-box, which is an edit field with an associated drop-down list of items. Attributes: editable

If true, the label is directly editable (as opposed to requiring a choice from the list)

empty-text

If present, the text to show if the combo-edit is empty

items

An array of strings, which are the items in the list. If an item begins and ends with a ‘-’ character, it is considered a “heading” and will be displayed differently

justify

How the text should be justified. An array of strings containing any combination of left, right, hcenter, vcenter, top, bottom and justified. The default is left — 79 —

The 8th Manual: Graphical User Interface: GUI

label

The text appearing in the label of the combo

no-choices

The text to show if there are no items in the list Let user use the mouse wheel to move list items The item which is selected on startup (default: nothing selected)

scroll-enabled selected

Events: changed

gui id text

--

The item selection or text has changed colour-changed

gui

--

The color of the item was changed enabled-changed

gui isenabled

--

The item was enabled or disabled focus-gained

gui

--

This item gained keyboard/mouse focus focus-lost

gui

--

This item lost keyboard/mouse focus text-changed

gui

--

The text of this item has changed value-changed

gui value

--

The value of this item has changed

17.5.6 Concertina Kind: "concertina". A panel which holds a vertical stack of components which can be expanded and contracted. Attributes: panels

An array of maps describing the panels to add to the concertina. Each of those may contain special keys in addition to the usual: header - Text to show on that panel’s title bar headerclr - Color of that panel’s title bar headersize - Pixel height of that panel’s title bar panelmaxsize - Maximum size (in pixels) for this panel item panelsize - Initial size (in pixels) for this panel item

17.5.7 Edit Kind: "edit". A text edit-box, possibly containing multiple lines of text. — 80 —

The 8th Manual: Graphical User Interface: GUI

Attributes: allowed-chars

If not empty, only these characters are allowed

auto-scroll

If false, will not scroll the text to where the caret is

border

Changes the size of border left around the edge

caret

If false, the edit-caret will not be visible

empty-color

If present, the color to use for empty text

empty-text

If present, the text to show if the edit is empty

esc-ret-consumed

This can be used to change whether escape and return key-press events are propagated up to the parent component

indent-left

How far text is indented from the left; default: 4 pixels

indent-top

How far text is indented from the top; default: 4 pixels

kbd

Gives the preference for the kind of keyboard input. May be one of "text", "num", "url", "email" or "phone"

max-text

If not zero, maximum number of characters allowed

multi

If true, the edit will handle multiple lines of text. Note that if “returnnewline” is not true, you won’t be able to enter multiple lines of text using the keyboard!

password-char

If set and not 0 or an empty string, sets the password-char to the ASCII character of the numeric value given, or the first character in the string

popup-enabled

If enabled, a pop-up menu may appear on right-click

return-newline ro

If true, pressing “return” starts a new line; otherwise, it is inserted in the text If true, the edit is read-only

sb-thick

Thickness of the scroll-bars, in pixels

scroll-visible

If true, the scroll bars will be shown. Default is true

select-all

If enabled, select all text when focused

tab-is-char

If true, the TAB key is treated like a regular character; otherwise, it tabs to the next item Initial text for the edit If true, the edit will wrap words at end of line

text wrap

Events: enabled-changed

gui isenabled --

The item was enabled or disabled escape-pressed

gui

--

f

The escape-key was pressed. If the default behavior should happen, return true otherwise return false focus-gained

gui -— 81 —

The 8th Manual: Graphical User Interface: GUI

This item gained keyboard/mouse focus focus-lost

gui --

This item lost keyboard/mouse focus return-pressed

gui

--

f

The return-key was pressed. If the default behavior should happen, return true otherwise return false text-changed

gui

--

The text of this item has changed

17.5.8 File browser Kind: "filebrowser". A file-browser control which lets you pick a file or set of files or directories to open or save to Attributes: filter

String of “;” delimited values, each one a file specification

flags

array of strings indicating options for this component. May be any combination of "open", "save", "file" (allow file selection), "dir" (allow dir selection), "multi" (allow multiple selections), "tree", "ro" and "warn" (warn if file exists, when using “save” option)

label

The text to put at the left of the file edit box

root

File or directory to start from

Events: changed

When the selected files change if "multi" flags is set

click

User clicked a file

escape-pressed

gui

--

f

The escape-key was pressed. If the default behavior should happen, return true otherwise return false focus-gained

gui

--

This item has gained the keyboard/mouse focus focus-lost

gui

--

This item has lost the keyboard/mouse focus list-dblclicked

User double-clicked a file

return-pressed

gui

root-changed

The return-key was pressed. If the default behavior should happen, return true otherwise return false User changed the root item in the control

--

f

— 82 —

The 8th Manual: Graphical User Interface: GUI

text-changed

gui

--

The text of this item has changed

17.5.9 File name Kind: "filename". An edit control which contains a file-name, lets the user select a file via a browser or using history or editing the name. Attributes: cwd

This will be used as the base directory

dir

If true, the file will be treated as a directory, and an appropriate directory browser used The text to show if no file has been chosen

empty-text

filter

Name of the initial file to show Semicolon-delimited string of file wild-cards; if empty, “*” is assumed

native

If false, do not use the native file browser

ro

If true, the user cannot edit the file name, but must select

save

If true, the file browser will allow non-existent files to be picked, as the file is assumed to be used for saving rather than loading

suffix max-recent

If not empty, ensure this suffix is added to all entered or chosen file names Set maximum number of recent files to show (default: 10)

browse-text

Text to show in the browse button (default: "…")

file

Events: changed

gui s

--

Called when the chosen file name changes file-drag-enter

gui a of filenames --

A file was dragged onto this item file-drag-exit

gui a of filenames -file is being moved off this item

files-dropped

gui a of filenames -files have been dropped on this item

17.5.10 Group box Kind: "group". A “group-box”, which visually groups items together. — 83 —

The 8th Manual: Graphical User Interface: GUI

Attributes: justify

Set position of the label text; see combo for details

label

Text label of the group box; default is empty

Events: colour-changed

gui

--

Informs that the color of the item was changed enabled-changed

gui isenabled --

The item was enabled or disabled

17.5.11 HTML control Kind: "html". A very lightweight HTML display. It is intended mainly for embedded HTML, and it works on all platforms equally well (or poorly…). Attributes: bg

Background color (default: neutral gray)

html

Set the HTML to be displayed

sbt

Thickness of the scrollbar (default: 24 pixels)

url

Load the HTML from the given URL

17.5.12 Image Kind: "image". A control which can show various kinds of graphics Attributes: img

Name of the image file or asset to load

Events: click

gui x y

--

If the user clicks on this image

17.5.13 Label Kind: "label". A label, usually meant to describe another item. — 84 —

The 8th Manual: Graphical User Interface: GUI

Attributes: border

Changes the size of border left around the edge

discard-on-lost

Discards edits if focus lost (and edit-single or edit-double is true)

edit-double edit-single

Edits the label if double-clicked Edits the label if single-clicked

fit-text

If true, adjust the font size so the text all fits

justify

How the text of the label should be justified. See combo for details

label

The text appearing in the label

Events: colour-changed

gui

--

Informs that the color of the item was changed enabled-changed

gui isenabled --

The item was enabled or disabled escape-pressed

gui

--

f

The escape-key was pressed. If the default behavior should happen, return true otherwise return false focus-gained

gui

--

This item has gained the keyboard/mouse focus focus-lost

gui

--

This item has lost the keyboard/mouse focus return-pressed

gui

--

f

The return-key was pressed. If the default behavior should happen, return true otherwise return false text-changed

gui

--

The text of this item has changed text-edited

gui

--

The text of this item was edited value-changed

gui value

--

Informs the value of the item was changed

17.5.14 Lasso Kind: "lasso". A “lasso” used to select other items. It has no special events or attributes. 17.5.15 List

— 85 —

The 8th Manual: Graphical User Interface: GUI

Kind: "list". A list-box containing a scrollable list of items. It is a “dynamic list” if the contents are determined at run-time (e.g. from a database or some other source). If that is not needed, all the contents can be set using the “items” attribute. Attributes: fg

The color to use when drawing the text of a list item

items

multi

An array of items (typically strings), which are the initial items in the list An array of strings controlling the justification of the text in the list. See combo for details Changes the width of the rows in the list. This can be used to make the list's row components wider than the list itself - the width of the rows will be either the width of the list or this value, whichever is greater, and if the rows become wider than the list, a horizontal scrollbar will appear. The default value for this is 0, which means that the rows will always be the same width as the list Makes the list react to mouse moves by selecting the row that the mouse is over Permit multiple item selection

outline-thickness

Sets the thickness in pixels of the outline drawn around the list

row-height

Height of rows in pixels; default is 22

justify min-width

mouse-select

Events: colour-changed

gui

--

Informs that the color of the item was changed cursor-row

gui row --

Sets the cursor to use for the given row delete-pressed

gui

--

The delete-key was pressed list-clicked

gui rownum

--

Item in the list was clicked list-dblclicked

gui rownum

--

Item in the list was double-clicked list-get-item

gui row

--

x

Return the item for the indicated row. Needed for a dynamic list. list-row-count

gui

--

n

Return the number of items in this list. Needed for a dynamic list. paint-list-item

gui rownum wide high isselect

Paint the list item return-pressed

gui

--

f — 86 —

--

The 8th Manual: Graphical User Interface: GUI

The return-key was pressed. If the default behavior should happen, return true otherwise return false tooltip-row

gui row --

Sets the tooltip to use for the given row visibility-changed gui isvisible

--

The item was shown or hidden

17.5.16 Menu bar Kind: "menubar". A menu bar, typically shown on the top of an application’s window. Attributes: menu

An array of items describing the menu to display. Each item is an array, consisting of a string which is displayed, and a number which is the command value. If the value is 0, the item is a header. If the text is null instead of a string, a separator is added

Events: menu-changed

gui

--

When the menu item is changed menu-invoked

gui command

--

If the menu was invoked (e.g. in code) menu-selected

gui index value

--

When the user selects the menu item

17.5.17 Preference panel Kind: "preferences". A component with a set of buttons at the top for changing between pages of preferences. This is just a handy way of writing a Mac-style preferences panel where you have a row of buttons along the top for the different preference categories, each button having an icon above its name. Clicking these will show an appropriate prefs page below it. Attributes: buttonsize

How big the buttons are, in pixels. Default is 32

pages

An array of maps describing each page of the preference-panel. The page must have, in addition to whatever attributes it would otherwise have: preficon - The icon to use to represent this page title - A string with unique text to put next to the icon

— 87 —

The 8th Manual: Graphical User Interface: GUI

17.5.18 Progress-bar Kind: "progressbar". Shows a progress-bar Attributes: show-pct

If true, will show the percentage as well as a bar

text

If present, will show this text inside the bar. Using it will disable the percentage display

Events: colour-changed

gui

--

Informs that the color of the item was changed enabled-changed

gui isenabled

--

The item was enabled or disabled

17.5.19 Property panel Kind: "property". A panel that shows a list of “properties” items, in collapsible sections. Attributes: items

An array of maps describing the items to put in the section

index

A number which determines which section number this is The name of the section

title

Item attributes itemkind

One of "edit", "bool", "choice", "button", "slider" or "section"

propname

The name by which this property editor is known; used when accessing the value Initial value of the item, type depends on itemkind

value

Edit property attributes maxchars

Maximum number of characters allowed; default is unlimited

multi

Allow multiple lines, if true Bool property attributes

label

Label for the button Choice property attributes

items

An array of choices Button property attributes — 88 —

The 8th Manual: Graphical User Interface: GUI

click

The callback to make when the user clicks the button Slider property attributes

rangemax

How much the slider moves at once The largest permitted value of the slider

rangemin

The lowest permitted value of the slider

skewfactor

See the documentation for the “slider” The initial value of the slider

interval

value

Events: focus-gained

gui

--

This item gained keyboard/mouse focus focus-lost

gui

--

This item lost keyboard/mouse focus

17.5.20 Scroll Kind: "scroll". A scroll-bar which you can use to control another item. Attributes: auto-hide

If true, the scroll will become invisible if it is not needed. Default is true

cur

Current position; default is 0

init-delay

How long before the up/down starts to repeat; default 100 (msec)

max

Highest allowable value of the scroll; default is 100

min

Lowest allowable value of the scroll; default is 0

rept-delay

How long between repeats of the up/down; default 50 (msec)

step

How much the arrows move the thumb; default is 1

vertical

If false, the scroll will be horizontal; otherwise, vertical. Default is true

Events: scrollbar-moved

gui n

--

When scroll has moved, gives the new start position

17.5.21 Slider Kind: "slider". A slider control for changing a value.

— 89 —

The 8th Manual: Graphical User Interface: GUI

Attributes: editable

Makes the text-box editable (for sliders with a text box)

interval

Steps in which the value is permitted to increase (default: 10)

key-swaps

if true, then the user can hold down the CTRL or command key to toggle velocity-sensitive mode

max

Maximum value the slider can have (default: 100)

menu-enabled

If this is set to true, then right-clicking on the slider will pop-up a menu to let the user change the way it works

mid-value

This allows you to specify the slider value that should appear in the centre of the slider's visible range

min

Minimum value the slider can have (default: 0)

mouse-drag-dist

Sets the distance the mouse has to move to drag the slider across the full extent of its range. This only applies when in modes like RotaryHorizontalDrag, where it's using relative mouse movements to adjust the slider values greater than 0.0 increase the minimum speed that will be used when the threshold is reached If true, gives the slider a pop-up bubble which appears while the slider is being dragged

offset popup-display ro

If true, the text-box is read-only

sensitivity

higher values than 1.0 increase the range of acceleration used

skew

Sets up a skew factor to alter the way values are distributed. You may want to use a range of values on the slider where more accuracy is required towards one end of the range, so this will logarithmically spread the values across the length of the slider. If the factor is < 1.0, the lower end of the range will fill more of the slider's length; if the factor is > 1.0, the upper end of the range will be expanded instead. A factor of 1.0 doesn't skew it at all. For “radial” sliders: start angle in degrees, starting at the top going clockwise For “radial” sliders: stop angle in degrees, starting at the top going clockwise. Must be greater than start-angle

start-angle stop-angle stop-at-end

For “radial” sliders: does the slider stop at the end or keep turning

— 90 —

The 8th Manual: Graphical User Interface: GUI

style

Determines the specific kind of slider. Valid values are: LinearHorizontal: A traditional horizontal slider, this is the default. LinearVertical: A traditional vertical slider. LinearBar: A horizontal bar slider with the text label drawn on top of it. LinearBarVertical: Same as LinearBar, but vertical. Rotary: A rotary control that you move by dragging the mouse in a circular motion, like a knob. RotaryHorizontalDrag: A rotary control that you move by dragging the mouse left-to-right. RotaryVerticalDrag: A rotary control that you move by dragging the mouse up-and-down. RotaryHorizontalVerticalDrag: A rotary control that you move by dragging the mouse up-and-down or left-to-right. IncDecButtons: A pair of buttons that increment or decrement the slider's value by the increment set in setrange. TwoValueHorizontal: A horizontal slider that has two thumbs instead of one, so it can show a minimum and maximum value. TwoValueVertical: A vertical slider that has two thumbs instead of one, so it can show a minimum and maximum value. ThreeValueHorizontal: A horizontal slider that has three thumbs instead of one, so it can show a minimum and maximum value, with the current value being somewhere between them. ThreeValueVertical: A vertical slider that has three thumbs instead of one, so it can show a minimum and maximum value, with the current value being somewhere between them.

text-high

Height of the text-box, in pixels, including slider

text-pos

Set position of text-box, if any. “0” means no text box; “1” is left of the slider, “2” is right of the slider, “3” is above and “4” is below

text-wide

Width of the text-box, in pixels, including slider

threshold

the minimum number of pixels that the mouse needs to move for it to be treated as a movement Starting value of the slider (default: 50)

value velocity-based

If true, this will turn on velocity-sensitive dragging, so that the faster the mouse moves, the bigger the movement to the slider. This helps when making accurate adjustments if the slider's range is quite large. If false, the slider will just try to snap to wherever the mouse is.

Events: colour-changed

gui

--

Informs that the color of the item was changed enabled-changed

gui isenabled

--

The item was enabled or disabled value-changed

gui value

--

The value of the item was changed

— 91 —

The 8th Manual: Graphical User Interface: GUI

17.5.22 Splash screen Kind: "splash". A splash screen which displays for a period of time or until clicked, and then disappears. Attributes: title

The name for the splash screen (not displayed)

img

An image (file name or asset) to display

delay

Seconds (including fractional seconds) to show the splash screen. The default is 3 seconds. The time is counted from the moment this gui is created, so take that into account

shadow

If true, show a shadow around the window

17.5.23 Stack GUI container Kind: "stack". It is a container for other GUI elements, similar to a “tab” but which overlays one gui on another, with transitions between. Attributes: animator

One of “slide”, “shutter” or “fade”. If not present, a default animator is used which just transitions without effects

dir

Direction of the slide animation effect: 0 = left►right, 1 = top►bottom, 2=right►left and 3=bottom►top

stack

An array of child guis to be managed by this control

transition

An array of numbers, where item 0 is the overall duration of the animation, item 1 is the start speed of the transition and item 2 is the end speed of the transition

17.5.24 System tray-icon Kind: "systemtrayicon". System-level tray icon, where supported (not on Android or iOS) Attributes: img

Icon to use

highlight

Highlight icon (if OS supports)

bubble

Text to show in bubble over icon (if OS supports)

title

Text to show as bubble title (if OS supports)

— 92 —

The 8th Manual: Graphical User Interface: GUI

17.5.25 Tab Kind: "tab". Tabbed panel. Controls a set of sub-panels, allowing you to organize them in separate tabbed areas. Attributes: bg

The “background color” for this tab

indent

Number of pixels to indent tab content (default: 0)

orientation

Orientation of tabs: one of "top", "left", "bottom" or "right". Default is "top"

outline

If > 0, the number of pixels thick the outline around the tab contents will be Number of pixels “deep” the tab-bar is; if orientation is top or bottom, this is the height of the bar; if it is left or right, it is the width

tab-depth tabs

An array of maps describing the content of each tab, which may have: label - the text to show on its tab

Events: tab-changed

gui ix name

--

When tab is changed, gets the index of the new tab and its name

17.5.26 Table list Kind: "table". Table list. Same as a list, but in a grid with columns. Attributes: fg

The color to use to draw the rows

header

An array of maps describing the table’s header. Each item may have: flags - Same allowed values as “hflags”, but on a per-header-item basis max-width - The widest, in pixels, the column may be min-width - The narrowest, in pixels, the column may be name - The name/label to show in the header width - How wide, in pixels, the column should be

hflags

An array of strings containing at least one of: "visible", "resizable", "draggable", "onmenu", "sortable", "forward" or "backward"

items

An array of items to be shown in the table, typically an array-of-arraysof-items

— 93 —

The 8th Manual: Graphical User Interface: GUI

Events: click

gui

--

If the user clicked outside any row list-autosize-col

gui ix

--

n

Return the size in pixels which column “ix” should be list-clicked

gui col row

--

If the specified cell was clicked list-dblclicked

gui col row

--

If the specified cell was double-clicked list-get-item

gui col row

--

n

Return the item to be shown in the specified cell list-row-count

gui

--

n

Return the number of rows of data list-sort-change

gui ix fwd

--

User clicked the header to change sort-order. ‘ix’ is the column id, and fwd is true for sort in ascending order

17.5.27 Toggle Kind: "toggle". Toggle switch, like a radio-button. Attributes: adjustwidth

If true, automatically resize to fit text. Default is true

label

Text to show as the label of the toggle

group

If present, determines which group of toggles this one is in

on

Should the toggle state be “on” or not

autotoggle

If true, the toggle should change state automatically when clicked. Default is true how long to wait in msec after the mouse is pressed before triggering the next click. If this is zero, auto-repeat is disabled

initial-delay min-delay

if this is greater than 0, the auto-repeat speed will get faster, the longer the button is held down, up to the minimum interval specified here

repeat-delay

how frequently subsequent repeated clicks should be triggered

square

if true, makes a “checkbox” instead of a “radio-button”

trig-mouse-down

if true, the “click” event will happen as soon as the mouse button is depressed

— 94 —

The 8th Manual: Graphical User Interface: GUI

Events: click

gui

--

When the item is clicked

17.5.28 Toolbar Kind: "toolbar". A bar containing icons which are buttons. Attributes: editable

If true, the user may rearrange the items in the toolbar. Default is false

items

An array of items to show in the toolbar. The item may have: id - number of the command-code when this item is clicked img - the icon to show (if the style shows icons) label - string of the text to show (if the style shows text)

style

A number indicating the style of the toolbar. 0 = just icons, 1 = icons+text, 2= just text. Default is 0

vertical

If true the toolbar will be vertically oriented; default is false

Events: click

gui id

--

Passed the command-id of the toolbar item which was clicked item-drag-enter

gui dragged --

Another item was dragged onto this item

17.5.29 Tree Kind: "tree". A “tree-view”, used for showing hierarchical data. Attributes: default-open

Should the tree be open by default

draw-lines

Should the tree draw lines between sub-items number of pixels to indent each new level of the tree

indent-size items

An array of items to be shown in the tree. The equivalent of >s is used to convert the item to a string for display in the tree, if the item is not a string. Sub-items are denoted by an array containing other items.

multi-select

Permit multiple item selection — 95 —

The 8th Manual: Graphical User Interface: GUI

open-close-visible Is the open-close button visible root

a string displayed as the root of the tree. By default it is “/”

root-visible

Should the root-node be visible (default true)

Events: colour-changed

gui

--

Informs that the color of the item was changed enabled-changed

gui isenabled --

The item was enabled or disabled file-drag-enter

gui a of filenames --

A file was dragged onto this item file-drag-exit

gui a of filenames -file is being moved off this item

file-drag-move

gui a of filenames -file is being moved on this item

files-dropped

gui a of filenames -files have been dropped on this item

item-drag-enter

gui dragged --

Another item was dragged onto this item item-drag-exit

gui dragged --

Item was dragged off this item item-drag-move

gui dragged --

Another item was moved on this item item-dropped

gui dragged --

Item was dropped onto this item

17.5.30 View Kind: "view". A control which allows you to view a portion of a larger component. Attributes: hallow

If true, allow horizontal scrolling without scrollbar. Default is false

hscroll

If true, show a horizontal scrollbar if necessary. Default is true

pct-x

The left position within viewed component (in percentage from 0 - 1.0) to show The top position within viewed component (in percentage from 0 - 1.0) to show

pct-y

— 96 —

The 8th Manual: Graphical User Interface: GUI

pos-x

The left position within viewed component (in pixels) to show

pos-y

The top position within viewed component (in pixels) to show

sb-thick

The number of pixels thick the scroll-bar should be when shown

stepX

Number of pixels the horizontal scrollbar will move the view

stepY

Number of pixels the vertical scrollbar will move the view

vallow

If true, allow vertical scrolling without scrollbar. Default is false

view

A string which is the "name" of the gui to view

vscroll

If true, show a vertical scrollbar if necessary. Default is true

Events: scrollbar-moved

gui n

--

When scroll has moved, gives the new start position

17.5.31 Web browser Kind: "web". An embedded web-browser control (currently not available on Linux) Attributes: url

The initial url to navigate to

Events: page-load-done

gui url

--

Invoked after a page has finished loading page-load

gui url

--

f

Invoked when a page is about to load; Return true to permit the load, or false to prevent it visibility-changed gui isvisible

--

The item was shown or hidden

17.5.32 Window Kind: "win". Top-level window.

— 97 —

The 8th Manual: Graphical User Interface: GUI

Attributes: buttons-left

If true, position the buttons on the left of the title bar

icon

The name of a graphic (PNG, JPEG or GIF) to use as the window’s icon in the title-bar A combination of any of 1 (minimize), 2 (maximize), or 4 (close)

buttons

title-centered

The title shown on the window’s titlebar If true, display the title bar text centered

titleBarHeight

number of pixels high the window’s title-bar should be

title

Events: close

When the win is to be closed. The default behavior is to close the application

17.6 Fonts Despite our best efforts to make 8th completely OS-independent and cross-platform, fonts are quite OS-specific. 8th lets you get around this problem by permitting you to easily embed a font in your application. A font may be declared as part of a gui map, be set using g:setfont, or created using font:new. In any case, the string describing the font has the same syntax. It may be any of these: "Arial 10" "Arial" "10" "Arial 10, bold italic"

The “face name” is the font name (Arial, etc) when it has been listed. The number following is the font size in pixels (or in points if the number is negative). If there is a comma, then any of the following modifiers may be listed: “italic”, “bold” or “underlined”; they may also be combined, e.g. “bold italic”. If a face name is omitted, the default font (for that platform) will be used; if the size is omitted, the default size will be used. If the face name begins with an asterisk "*", then the font name is considered to be a font which is an “asset”; that is to say, embedded with the application. In that case, the name should be the asset name rather than the actual font’s face name. Note: currently, only TTF fonts work completely cross-platform. OTF fonts work on all except for Windows. The font created using font:new may be manipulated in a number of ways using the words from the font: namespace. You can change the size of the font as well as its bold, italic and underlined state. You can determine how wide a string would be if rendered using that font. You can extract and manipulate glyphs from the font and draw using them.

17.7 Paths

— 98 —

The 8th Manual: Graphical User Interface: GUI

A “path” is simply a sequence of lines and curves which may be “filled” or “stroked”. Generally, you use paths behind the scenes when drawing. But sometimes you need to use paths directly. One example is if you want to draw text at an angle or on a curve. In that case you would need to get the glyphs for each character, as paths, and then draw the paths as desired. Another example might be if you wish to draw the same thing more than once. In that case you could take the path and replicate it (resizing and rotating if desired).

17.8 Colors Many of the gui components understand the fg and bg color options. You may also sometimes specify a color to draw with; for example, to fill a rectangle. It is possible to specify a color in several ways. First, you can use a name, such as blue. The list of names 8th understands follows later. Second, you may use an RGBA value, such as 0xFF00FF00 for (100% opaque) green. Note that you must also specify an “alpha”, or transparency, value! If you give a color name, then following it with a colon and a number from 0–100 will give you that color with the indicated transparency. For example, blue:50 is a 50% transparent blue. If you don’t, it is assumed you want 100% opaque. Finally, you may give an array of numbers representing an RGBA value, where the first element is red, etc. The values must be in the range of 0 to 1, e.g. a percentage value. So the value [ 1,1,1,1 ]

is opaque white. The following color names are recognized by 8th: aliceblue

antiquewhite

antiquewhite1

antiquewhite2

antiquewhite3

antiquewhite4

aquamarine

aquamarine1

aquamarine2

aquamarine3

aquamarine4

azure

azure1

azure2 beige

azure3 bisque

bisque2

bisque3

bisque4

black

blanchedalmond

blue

blue1

blue2

blue3

blue4

blueviolet

brown

brown1

brown2

brown3

brown4

burlywood

burlywood1

burlywood2

burlywood3

burlywood4

cadetblue

cadetblue1

cadetblue2

cadetblue3

cadetblue4

chartreuse

chartreuse1

chartreuse2

azure4 bisque1

— 99 —

The 8th Manual: Graphical User Interface: GUI

chartreuse3

chartreuse4

chocolate

chocolate1

chocolate2

chocolate3

chocolate4

coral

coral1

coral2

coral3

coral4

cornflowerblue

cornsilk

cornsilk1

cornsilk2

cornsilk3

cornsilk4

cyan

cyan1

cyan3 darkcyan

cyan4 darkgoldenrod

cyan2 darkblue

darkgoldenrod2

darkgoldenrod3

darkgoldenrod4

darkgray

darkgreen

darkkhaki

darkmagenta

darkolivegreen

darkolivegreen1

darkolivegreen2

darkolivegreen3

darkolivegreen4

darkorange

darkorange1

darkorange2

darkorange3

darkorange4

darkorchid

darkorchid1

darkorchid2

darkorchid3

darkorchid4

darkred

darksalmon

darkseagreen

darkseagreen1

darkseagreen2

darkseagreen3

darkseagreen4

darkslateblue

darkslategray

darkslategray1

darkslategray2

darkslategray3

darkslategray4

darkturquoise

darkviolet

debianred

deeppink

deeppink1

deeppink2

deeppink3

deeppink4

deepskyblue

deepskyblue1

deepskyblue2

deepskyblue3

deepskyblue4

dimgray

dodgerblue

dodgerblue1

dodgerblue2

dodgerblue3

dodgerblue4

firebrick

firebrick1

firebrick2

firebrick3

firebrick4

floralwhite

forestgreen

gainsboro

ghostwhite

gold

gold1

gold2

gold3

gold4

goldenrod

goldenrod1

goldenrod2

goldenrod3

goldenrod4

gray

gray0

gray1

gray10

gray100

— 100 —

darkgoldenrod1

The 8th Manual: Graphical User Interface: GUI

gray11

gray12

gray14 gray17

gray15 gray18

gray2

gray20

gray21

gray22

gray23 gray26

gray24

gray29

gray3

gray30

gray31

gray32

gray33 gray36

gray34 gray37

gray35 gray38

gray39

gray4

gray40

gray41

gray42

gray44 gray47

gray45 gray48

gray43 gray46

gray5

gray50

gray51

gray52

gray53 gray56

gray54

gray25 gray28

gray55 gray58

gray13 gray16 gray19

gray27

gray49

gray57 gray6

gray60

gray59 gray61

gray63

gray64

gray65

gray66

gray67

gray68

gray69

gray7

gray70

gray71

gray72

gray74

gray75 gray78

gray73 gray76

gray62

gray80

gray79 gray81

gray82

gray83

gray84

gray85

gray86

gray87

gray88

gray89

gray9

gray90

gray91

gray92

gray93 gray96

gray94 gray97

gray95 gray98

gray99

green

green1

green2 greenyellow

green3 honeydew

green4 honeydew1

gray77 gray8

— 101 —

The 8th Manual: Graphical User Interface: GUI

honeydew2

honeydew3

honeydew4

hotpink

hotpink1

hotpink2

hotpink3

hotpink4

indianred

indianred1

indianred2

indianred3

indianred4

ivory

ivory1

ivory2

ivory3

ivory4

khaki

khaki1

khaki2

khaki3

khaki4

lavender

lavenderblush

lavenderblush1

lavenderblush2

lavenderblush3

lavenderblush4

lawngreen

lemonchiffon

lemonchiffon1

lemonchiffon2

lemonchiffon3

lemonchiffon4

lightblue

lightblue1

lightblue2

lightblue3

lightblue4

lightcoral

lightcyan

lightcyan1

lightcyan2

lightcyan3

lightcyan4

lightgoldenrod

lightgoldenrod1

lightgoldenrod2

lightgoldenrod3

lightgoldenrod4

lightgoldenrodyellow

lightgray

lightgreen

lightpink

lightpink1

lightpink2

lightpink3

lightpink4

lightsalmon

lightsalmon1

lightsalmon2

lightsalmon3

lightsalmon4

lightseagreen

lightskyblue

lightskyblue1

lightskyblue2

lightskyblue3

lightskyblue4

lightslateblue

lightslategray

lightsteelblue

lightsteelblue1

lightsteelblue2

lightsteelblue3

lightsteelblue4

lightyellow

lightyellow1

lightyellow2

lightyellow3

lightyellow4

limegreen

linen

magenta

magenta1

magenta2

magenta3

magenta4

maroon

maroon1

maroon2 mediumaquamarine

maroon3 mediumblue

mediumorchid1

mediumorchid2

mediumorchid3

mediumorchid4

mediumpurple

mediumpurple1

mediumpurple2

mediumpurple3

maroon4 mediumorchid

— 102 —

The 8th Manual: Graphical User Interface: GUI

mediumpurple4

mediumseagreen

mediumslateblue

mediumspringgreen

mediumturquoise

mediumvioletred

midnightblue

mintcream

mistyrose

mistyrose1

mistyrose2

mistyrose3

mistyrose4

moccasin

navajowhite

navajowhite1

navajowhite2

navajowhite3

navajowhite4

navyblue

oldlace

navy olivedrab

olivedrab2

olivedrab3

olivedrab4

orange

orange1

orange3 orangered1

orange4 orangered2

orange2 orangered

orangered4

orchid

orchid1

orchid2

orchid3

orchid4

palegoldenrod

palegreen

palegreen1

palegreen2

palegreen3

palegreen4

paleturquoise

paleturquoise1

paleturquoise2

paleturquoise3

paleturquoise4

palevioletred

palevioletred1

palevioletred2

palevioletred3

palevioletred4

papayawhip

peachpuff

peachpuff1

peachpuff2

peachpuff3

peachpuff4

pink

pink1

peru pink2

pink4

plum

plum1

plum2

plum3

plum4

powderblue

purple

purple1

purple2

purple3

purple4

red

red1

red2

red3

red4

rosybrown

rosybrown1

rosybrown2

rosybrown3

rosybrown4

royalblue

royalblue1

royalblue2

royalblue3

royalblue4

saddlebrown

salmon

salmon1

salmon2

salmon3

salmon4

sandybrown

seagreen

seagreen1

— 103 —

olivedrab1

orangered3

pink3

The 8th Manual: Graphical User Interface: GUI

seagreen2 seashell

seagreen3 seashell1

seagreen4 seashell2

seashell3

seashell4

sienna

sienna1

sienna2

sienna3

sienna4

skyblue

skyblue1

skyblue2

skyblue3

skyblue4

slateblue

slateblue1

slateblue2

slateblue3

slateblue4

slategray

slategray1

slategray2

slategray3

slategray4

snow

snow1

snow2 springgreen

snow3 springgreen1

snow4 springgreen2

springgreen3

springgreen4

steelblue

steelblue1

steelblue2

steelblue3

steelblue4

tan

tan1

tan2 thistle

tan3 thistle1

tan4 thistle2

thistle3

thistle4

tomato

tomato1

tomato2

tomato3

tomato4

turquoise

turquoise1

turquoise2

turquoise3

turquoise4

violet

violetred

violetred1

violetred2

violetred3

violetred4

wheat

wheat1

wheat2

wheat3

wheat4

white

whitesmoke

yellow

yellow1

yellow2

yellow3

yellow4

yellowgreen

17.9 Look and feel A “look and feel”, or “laf” for short, is collection of code and attributes which make a gui look a certain way. The default laf for 8th is the JUCE library’s default — known by 8th as laf #3. There are three built-in lafs to choose from, and if you wish you can experiment to see what the differences between them are. You may also create your own laf using g:new-laf. That word takes a map with keys describing the new laf, and returns a number which is what you would give to g:laf or g:laf! or inside a gui for the "laf" key. — 104 —

The 8th Manual: Graphical User Interface: GUI

The keys you define are the names of words you created to handle those aspects of the laf which you would like to do differently than the default. Here is a list of the keys and the stack-effect those callbacks will have when invoked by 8th. Note: not all of them are available yet, we’re still working on the implementation. Note also that you can consult the JUCE LookAndFeel documentation for more details. areLinesDrawnForTreeView areScrollbarButtonsVisible changeToggleButtonWidthToFitText createAlertWindow createCaretComponent createComboBoxTextBox createDocumentWindowButton createFileBrowserGoUpButton createFileChooserHeaderText createFilenameComponentBrowseButton createSliderButton createSliderTextBox drawAlertBox drawBubble drawButtonBackground drawButtonText drawComboBox drawConcertinaPanelHeader drawCornerResizer drawDocumentWindowTitleBar drawDrawableButton drawFileBrowserRow drawKeymapChangeButton drawLabel drawLasso drawLinearSlider drawLinearSliderBackground drawLinearSliderThumb drawMenuBarBackground drawMenuBarItem drawPopupMenuBackground drawPopupMenuItem drawPopupMenuSectionHeader drawPopupMenuUpDownArrow drawProgressBar drawResizableFrame drawResizableWindowBorder drawRotarySlider drawScrollbar

\ gui -\ -- f (true if buttons should be visible) \ gui --

not implemented not implemented The cb must return a “label” to use for the combo \ n -- btn Gets a numeric button-type and returns a “btn” \ -- btn Return a “btn” \ title instructions -- str From the given strings return another to use \ gui -- lbl

\ gui -- btn \ gui incr -- btn \ gui -- label \ gui rect -\ gui arrtip arrbody -\ gui clr isover isdown -\ gui isover isdown -\ box wide high isdown buttonx buttony buttonwide buttonhigh -\ gui panelgui area isover isdown -\ gui w h isover isdragging --

not implemented \ gui isover isdown --

not implemented \ gui w h desc -\ gui -\ gui -\ gui x y wide high pos style -\ gui x y wide hiegh pos style -\ gui x y wide hiegh pos style -\ gui wide high b -\ gui wide high ix text isoverbar -\ gui wide high --

minpos maxpos minpos maxpos minpos maxpos

isover isopen

not implemented \ gui area section -\ gui wide high isscrollup -\ gui wide high progress text -\ gui wide high abordersize -\ gui wide high abordersize -\ gui x y wide high pos startangle endangle -\ gui x y wide high isvertical pos thsize isover isdown -— 105 —

The 8th Manual: Graphical User Interface: GUI

drawScrollbarButton drawSpinningWaitAnimation drawStretchableLayoutResizerBar drawTabAreaBehindFrontButton drawTabButton drawTableHeaderBackground drawTableHeaderColumn drawTextEditorOutline drawTickBox drawToggleButton drawTooltip drawTreeviewPlusMinusBox fillResizableWindowBackground fillTextEditorBackground getAlertBoxWindowFlags getAlertWindowButtonHeight getAlertWindowFont getAlertWindowMessageFont getAlertWindowTitleFont getComboBoxFont getCrossShape getDefaultDocumentFileImage getDefaultFolderImage getDefaultMenuBarHeight getDefaultScrollbarWidth getIdealPopupMenuItemSize getLabelFont getMenuBarFont getMenuBarItemWidth getMenuWindowFlags getMinimumScrollbarThumbSize getPopupMenuFont getScrollbarButtonSize getScrollbarEffect getSliderEffect getSliderLayout getSliderPopupFont getSliderPopupPlacement getSliderThumbRadius getTabButtonOverlap getTabButtonSpaceAroundImage getTextButtonFont getTickShape getTooltipBounds getTreeViewIndentSize getTypefaceForFont layoutFileBrowserComponent layoutFilenameComponent positionComboBoxText

\ gui wide high direction isvertical isover isdown -\ gui color x y wide high -\ gui wide high isvertical isover isdrag -\ gui wide high -\ gui isover isdown -\ gui -\ gui name id wide high isover isdown flags -\ gui wide high -\ gui x y wide high ticked enabled isover isdown -\ gui isover isdown -\ gui text wide high -\ gui area clr isopen isover -\ gui wide high asize -\ gui wide high -\ -- flags \ -- high \ -- font \ -- font \ -- font \ gui -- font

not implemented not implemented not implemented \ -- high \ -- wide \ text issep stdhigh idealwide idealhigh -- high \ gui -- font \ gui index text -- font \ gui index text -- font \ -- flags \ gui -- size \ -- font \ gui -- size

not implemented not implemented not implemented \ \ \ \ \ \

gui -- font gui -- placement gui -- radius depth -- overlap -- space gui high -- font

not implemented not implemented \ gui -- size

not implemented not implemented \ gui guibox guibutton -\ gui guilabel -— 106 —

Chapter 18: Tasks and parallelism

18.1 Introduction to tasks A “task” in 8th is effectively the same as a “thread” or “co-routine” in other languages. You create one using either t:task or t:task-n — the first simply runs the word it is given on a separate task, while the second transfers the top “N” items from the current stack to that of the new task. : the-task-word ... does something ... ; ' the-task-word t:task

A task will run as long as the word you gave as its starting point continues to run. When that word terminates, the task is complete; if there are no references to it, it cleans-up after itself and disappears. If you do hold a reference to it, you can retrieve the last value on its TOS using t:result (which will be null if there was no result). Using this facility, you can place long-running tasks in the “background” so they don’t interfere with your foreground GUI (or console). You can also split tasks into smaller pieces which can be run independently of each other, and perhaps gain a speedup. If you have a multi-core system, you will be more likely to experience a speedup than if you don’t. However, placing “blocking” or long-running tasks in a background task will make your user’s subjective experience better.

18.2 Task stacks Each task receives its own set of stacks (data and r-). This allows you the freedom to do whatever you need to on the task’s stack without being concerned you might mess up the main stack. The default size of a task stack is 256 items (notably smaller than the main stack of 512 items!). This default value can be changed (and only affects subsequent new tasks) by using t:def-stack.

18.3 Locking and unlocking 8th does not lock by default! That means that if you have an array which you access from two different tasks, you may end up with bugs which are difficult to diagnose, up to and including random crashes. 8th doesn’t lock by default because in the usual case of a single-threaded application, there is no need to, and locking would cause a slowdown. But it is sometimes necessary in a multi-threaded (multi-task) application in order to prevent data corruption. Example: 0 var, counter : task-word counter lock 1 n:+! counter unlock drop ; ' task-word t:task drop ' task-word t:task drop

— 107 —

The 8th Manual: Tasks and parallelism

This shows how task-word may safely increment the global variable counter even though it is running in two different tasks. By using the lock and unlock words judiciously, you will avoid data corruption problems. Be careful that you don’t create a “deadlock” situation when locking, where one task has locked an item but did not unlock it before another task needed it. The queue data type does do locking, since it is generally intended to be used from various tasks. You do not (and should not) use locking on that data type!

18.4 Using task queues A task may include a queue. That queue will be created on the first use of t:push, and it will have a size determined by t:def-queue (the default is 8 items). To push an item onto another task’s queue, use t:push. You need to have the task-item as created by t:new in order to do that. You can also push onto the main task’s queue by using t:main as the identifier. 8th always creates one task, the main one. Inside the recipient task, you use t:pop to retrieve any items which have been pushed to it. You can also determine how many items are in that queue using t:qlen.

18.5 Being a good citizen It is good practice to make your task do its work in short bursts. The precise amount of work depends on a great many things — but if your task never sleeps, you will lose overall system performance and your users will not be happy. So you will probably want to work in a loop where you do a 0.1 sleep (or whatever is appropriate to your application) between bursts of processing.

18.6 Parallelism If your processing can be profitably broken into chunks which can be worked on independently, then you can leverage tasks to do your bidding. For example: 0 100 2 ' process t:task-n drop 100 100 2 ' process t:task-n drop 200 100 2 ' process t:task-n drop

This sample partitions the processing into three chunks: one which works from 0 to 99, one from 100 to 199 and one from 200 to 299. To see a fully-worked example of parallel processing, look at the sample misc/parallel.8th

— 108 —

Chapter 19: Exceptions

Exceptions in 8th are generally considered “fatal errors”. That is, a thrown exception indicates a condition which cannot be addressed by the programmer at runtime. This is in contrast to languages like Java and C++, where a block of code may be surrounded by a try...catch construct. 8th does not have that, since 8th exceptions indicate a programmer error. That said, one may intercept thrown exceptions by installing a new word for handler, like so: : my-handler ... figure out if we should handle this ... true ; ' my-handler w:is G:handler

The true return value means your handler word decided 8th should continue. The default behavior is to quit the application after having displayed a message. Execution will continue (if true was returned) from the place where the exception was thrown, so your code needs to know how to repair the stack or take other corrective measures as needed. Your own code can choose to throw a string (which is what 8th always does) or to throw some other data type which may convey more information which your handler code can then act upon. In “console mode”, exceptions thrown will return to the console rather than quitting 8th. This is so in order that you may interactively debug the issue or re-enter mis-typed text. Be aware: the stack may contain “garbage” on it because of the throw. So it’s a good idea to invoke .s after an exception in the console, so you can be certain it contains what you intend. Also note that on a “stack full” exception, 8th invokes reset before returning control to the console: this is unlike all other exceptions, and it is done so any handling which requires the stack can succeed.

19.1 User-defined exceptions As mentioned above, you may choose to throw a simple string, which will then be displayed. Any other type you throw will be converted to a string for display. If you choose to throw a number, then you should be careful to use one greater or equal to 1,000 — anything between 0 and 1,000 is reserved for 8th’s internal use.

19.2 Built-in exceptions 8th has a number of built-in exceptions it can throw. Here is a list of all of them. The “%” character indicates a place where a “sprintf” insertion will be made at runtime: • %s needs root privileges: This functionality requires “root” access • %s out of bounds access: Trying to access beyond the valid bounds of a buffer or stack, etc. • %s requires %s: Variety of situations; details are shown • %s requires a string or a buffer: Variety of situations; details are shown — 109 —

The 8th Manual: Exceptions

• %s requires a string or a map: Variety of situations; details are shown • application corrupted — The application cannot run because it has been corrupted • application expired: The application was built with the “Trial Edition” of 8th, and its 3-day run has expired • bad UTF-8: %s: The UTF-8 string contained a sequence which was invalid • bad key size %d for %s: The key passed was the wrong size. • can't clone a %s: That item type is one of the kinds which cannot be cloned • can't find:: The given word could not be looked-up • can't get crypto provider: Can’t initialize the Windows crypto provider • can't parse regex: Tried to parse a regular-expression beginning with “/” and failed • can't use G:new for this ns: The namespace identifier does not allow G:new • couldn't include:: The given string did not result in a file-name which could be included • couldn't initialize WINSOCK: Windows: the WINSOCK library could not be initialized • couldn't load image for splash: The image file for the “splash” GUI was not found or could not be loaded • don't know how to convert MySQL type %d: db:exec does not know what to do with the returned MySQL type shown • don't know how to send item of ns %s to MySQL: db:bind does not know how to send the type indicated to MySQL • error initializing HMAC: There was an error trying to initialize an HMAC hash • eval! does not understand the type — eval! could not evaluate the value it was given • expected %s, but got %s: The item type expected was not the one the word was actually given • expected a camera: You gave something other than a camera hw • expected hex digits: The string escapes \x or \u expect two (or four) hexadecimal digits and didn’t get them • failed crypto %d: A crypto routine failed; the libtomcrypt error is shown • ffi can't load: %s: The FFI could not load the given function • ffi doesn't handle s: The FFI doesn’t know how to handle the type given • ffi expected %c type but got %s: The FFI was told to expect one data type, and the incompatible type listed was given • ffi retval %c invalid: The FFI doesn’t know what the given return type is • format spec %s requires a %s: The s:strfmt specification given requires the type given • fp overflow: Convert a bigfloat or biginteger to a float overflowed the float • got item of unknown ns %d, expected %d: The word expected one type, you gave it a different type — 110 —

The 8th Manual: Exceptions

• invalid JSON %s: An invalid JSON array or map was parsed • invalid %s keys (%d,%d): The kind of key passed was invalid. The error results from libtomcrypt are shown. • invalid bounds: %s: A “bounds” string was incorrectly formatted • invalid item: A item on the stack had a reference count of zero. This is not ever supposed to occur • invalid regex %s at %d: The given regular-expression is invalid, beginning at that offset in the expression • jni %s expects %d parameters, %d provided: Android: the JNI call requires a certain number of parameters, which is not what was given • jni can't find %s with parameters %s: Android: JNI was unable to find a function with the given signature • may only be used in compile mode: The word may not be used in interpret mode, only in compile mode • mismatched flow-control: %s: A flow-control word was not correctly matched up • mysql bind requires parameters in an array: db:bind for MySQL databases requires the parameters be in an array • needed system libraries not found: %s: A required system library was not found • no GUI is available: No GUI is available, probably because X-Windows is not available • number too big: Conversion of a big integer will overflow the native type • only Android: The Java interface words are only available on Android • out of memory: The system cannot allocate any more memory • propval! can't handle a %s: The propval GUI doesn’t know what to do with the type it was given • queue empty: The queue is empty • queue full: The queue is full • s:tsub expected an array or map!: s:tsub requires an array or map with parameters to insert in the template string • stack empty: The data stack or rstack was empty • stack full: The data stack or rstack was full • too few dimensions given: mat:! was given too few dimensions • too few format params were given: The s:strfmt word requires more parameters than were given • unable to parse a word header: The header for a word cannot be parsed from the input • unknown %s: %s: Various reasons; the specifics are shown • unknown word in JSON: When parsing the JSON, a word was encountered which was not found in the namespace search — 111 —

The 8th Manual: Exceptions

• use the specific 'new' word for the ns: You are using G:new for a type which has a different method of creation

— 112 —

Chapter 20: Debugging

Unlike many other languages and development environments, 8th does not have a dedicated “debugger”. Instead, it gives you tools to help you find problems in your code interactively.

20.1 Categories of problems There are several kinds of problems you might encounter while writing 8th code. They are, in decreasing order of severity: crashes A system-level crash, e.g. “SIGSEGV” or “Access error” or something like that. You should not normally see this, but if you do it is a serious bug which needs to be reported to us. Please use the bug reporting application to let us know about this kind of problem. However: if the crash is subsequent to a thrown exception in interactive mode, it is not a bug in 8th security If you have found a way to subvert 8th’s security model (e.g. modify an encrypted application so it runs without complaint), that is also a serious bug we would like reported to us refcount This is yet another serious bug: if the refcnt of an item is 0 (or is some largish number) then unless you were using -ref or +ref, you should report this as a bug exception If you get an “Exception” message (either in the console or in a message box), this is an error being reported by 8th. In the 8th model, an exception is a condition which is not tolerable. However, it usually indicates an error in your code rather than a problem in 8th incorrect The code compiled without complaint, but it does not give correct results inconsistent The code does not act the same way from one run to the next

20.2 Debugging techniques While developing your application, you have a number of tools at your disposal for debugging problems. Since the most common cause of problems is losing control of the stack, your first line of defense is to keep your words short and comment the stack-picture! Shorter words are easier to understand, and comments which are accurate are extremely useful. Your next most important tool is the phrase .s cr, which you can make a little more fancy by putting it in a word of its own: : XX log .s cr ;

— 113 —

The 8th Manual: Debugging

This XX word would then be used like so: : some-word... "part 1" XX ... "part 2" XX ... ;

This would print “part 1” and the top ten items of the stack, then do something, then print “part 2” and the top ten items of the stack at that point. This gives you an annotated stack-dump, which can help you quickly pinpoint problems related to improper stack usage. Most of the time, the .s cr phrase is enough to track down and eliminate stack problems. The following hints may also help: • Make sure you are giving words the correct stack to use. A frequent problem is putting too many or too few items, or the wrong kinds of items on the stack. Check the documentation! • If you are using an iterator like a:each, make sure you consume the correct number of items from the stack. Again, check the documentation! • Factor your words into smaller pieces, and document their stack-effect. Then make sure you adhere to the documented effect for each factored word Another potential source of problems is using an “unqualified word”; that is, saying + instead of n:+ (for instance). In fact, you will generally see an exception in such a case, telling you (for example) that 8th expected a string but got a number. In interpret-mode, 8th will usually pick the correct word (though not always), while in compile-mode it will more often err. So avoid ambiguity and use qualified words. One further source of problems is related to “const”. In general, items are not “constant” unless they are embedded in a word. For example: 100 var, x : y 100 ;

The 100 stored in the var “x” is not constant; that actual item itself may be modified. In contrast, the word “y” will return the same actual number 100, which will not be modified by any code. This has the potential for unexpected side-effects, if you were to perform some operation on the 100 in “x” which modified the item itself, then the next time you accessed “x” you got a different value. You can debug this sort of issue with the .s cr phrase as well.

In addition to the techniques mentioned in this chapter, 8th provides some rudimentary debugging words in the “dbg” namespace. They are documented with the rest of the built-in words.

— 114 —

Chapter 21: Standalone Applications

A “standalone application” is one which may be run on its own, like any other native application on the target platform. 8th provides a simple method for producing standalone applications from a single set of source code. This functionality is available to all versions of 8th. However, producing encrypted standalone applications is only available to users of the “Professional” or “Enterprise” versions.

21.1 Application life-cycle An application is loaded by the 8th engine and then verified and decrypted (if it was encrypted) and the plain-text code is then interpreted. After that, assuming the code doesn’t invoke some other word as its last step, the 8th engine invokes app:main. So a typical application will have code resembling this, at the end of the code: : app:main initialize run-stuff shut-down ;

Android and iOS applications may handle the OS “suspend” and “resume” by hooking their own code instead of the default (do-nothing) app:suspended and app:resumed. Those will get invoked at the usual OS-specific times. You can use onexit to add words to be executed on program shutdown. The usual bye or die words will cause the “onexit” chain to be invoked.

21.2 Setting up your application Before you do anything else, please make sure that you have set up 8th as discussed in the chapter on installation. Once you have done that you can use the build tool. In order to produce a standalone application, build needs your code and associated resources to be in a folder of their own. It also needs a “project description” file, which is just a JSON map with information helpful to build. If you have not created such a file, the build tool will create a template version of it in the folder you named on the build command-line; it is up to you to ensure the contents are correct. For example, if your application is named test.8th, you might put it in a folder called test, along with the application icon test.png and other support files. Included in that folder you could also place test.proj, the project description file. You can either copy the sample ttt.proj in the demo/tictactoe folder, or use the build tool to create one for you.

— 115 —

The 8th Manual: Standalone Applications

21.3 Building the application To create the packaged application, run the build tool which is located in the bin folder. A typical command to run it would be: 8th bin/build demo/tictactoe/

Once invoked, the build tool presents a GUI which allows you to enter specific information about your application, and save the settings in the project description file. Note for macOS users: due to macOS limitations, you must run 8th from within the usual .app folder; otherwise, you will not be able to enter text! In the build GUI, you can select the platforms you wish to produce output for. You can select the program icon and permissions for iOS or Android applications (note: selecting the icon and/or permissions is currently inactive; it will be activated in a future release). When you are ready to produce the final executables, simply press the “Generate” button, and within a few seconds your application will be packaged for all the platforms you have selected. The output will appear in the out subdirectory of the project’s folder. Note for CLI users: if you prefer to use a command-line interface, or if you would like to do so for unattended builds, you can pass the -g flag before the directory name, like so: 8th bin/build -g demo/tictactoe/

That will take all its information about what to product from the JSON map, so make sure you’ve set the values there as you would like them to be. 21.3.1 Android The steps to create an Android application are currently not as simple as they are for other OSes. This will be changed in future releases of 8th, but for now please bear with us. 8th creates a binary which will run on your Android device, but it does not yet do the Androidspecific signing and packaging. So in order to create a proper “APK” file which can be installed on your Android device, please follow these steps: 1. Prerequisite: the Android SDK. You must have installed the Android SDK from Google, and you must also have set up a developer’s certificate with them, and you must also have the Android SDK tools available so you can access them from the command-line 2. Prerequisite: Apache Ant. While it’s not strictly required, you are on your own if you want to avoid using it to build the APK. 3. Using the build tool, click “Generate” for your application, after having chosen “Android” as an OS target. 4. Edit the out/android/AndroidManifest.xml file in your projects folder, ensuring you have set only those permissions your application requires. Also change the “package” and other parameters to those applicable to your application 5. You probably also want to copy your application’s logo files over the ones in the various out/android/res/drawable... folders Now you are ready to sign and package the application. To create a “debug” version which you can use to test, simply change to the out/android folder and type ant debug. This will create a

— 116 —

The 8th Manual: Standalone Applications

new APK file in the bin folder, which you can then deploy. If ant failed, try ant clean and retry the build. To create a release version suitable for uploading to the Google Play (or to give to third-parties), you simply type ant release instead of ant debug. However, you must have a signing certificate in order to create a release version. You can deploy to your Android device by using the command-line utility adb from the Android SDK or any other method you desire. 21.3.2 iOS Similar to the situation with Android, 8th does not sign and package your code in the iOS required manner. The steps are also similar, but much more finicky: 1. Prerequisite: A computer running macOS. Sorry, you cannot package or sign on anything but a Mac. 2. Prerequisite: An iOS Developer account. You must have the correct credentials from Apple, or you will be unable to create an application for an iOS device. 3. Prerequisite: XCode. You need the Apple XCode tool in order to propery sign and deploy your application 4. Prerequisite: Provisioning profile (create on in your iOS deveoper account online and download the file) 5. Unzip the ios.app.zip file from 8th to a temporary area. For example, myapp. After that, you should have a folder myapp/IOS.app. 6. Edit the Info.plist so it has the permissions you require 7. Copy your application logo.png over the IOS.app/logo.png 8. Copy your provisioning profile into IOS.app/embedded.mobileprovision 9. Copy the XCode iPhoneOS.sdk ResourceRules.plist into IOS.app/ResourceRules.plist (unless you have a different set of rules) 10. Create an appropriate “entitlements” file and save it outside the IOS.app folder 11. Using the build tool, click “Generate” for your application. It does not matter which OS you choose (as long as you have chosen one) 12. Copy the build-generated file appdata over the file myapp/IOS.app/assets/appdata 13. Copy the appropriate 8th binary over IOS.app/8th. Note: if you wish to submit to the App Store, you will need to use “lipo” to create a “fat-binary” of 8th (otherwise you can choose to just use one of 32 or 64 bit iOS binaries). Do that with lipo bin/ios*/8th -create -output fat8th, and copy the “fat8th” binary over IOS.app/8th 14. Run the 8th-provided bash script bin/floatsign.sh to create the IPA file The floatsign.sh script is invoked like this: bash bin/floatsign.sh myapp/IOS.app "iPhone Developer" \ -p my.mobileprovision \ -e entitlement.file IOS.ipa

— 117 —

The 8th Manual: Standalone Applications

Here, iPhone Developer is the signing key you wish to use, my.mobileprovision is the provisioning profile to use and entitlement.file is the entitlements file. The script will sign the IOS.app and embed the provisioning profile, leaving you with a signed and ready to deploy IPA in IOS.ipa. Getting that onto your device is left to you (fruitstrap is a nice command-line method). Thanks to Daniel Pfeiffer for the floatsign.sh script. Submitting to the Apple App Store requires you sign with a distribution key and comply with numerous other details which are prone to change and therefore left to you to work through when you so desire. 21.3.3 macOS The story here is much simpler. To get a properly functioning GUI application on macOS, your application needs to be packaged correctly. Fortunately, it’s not difficult (sorry, Apple: the ‘osx.app.zip’ will stay with that name): 1. Unzip the osx.app.zip file from 8th to a temporary area. For example, myapp. After that, you should have a folder myapp/OSX.app. 2. Convert your application logo.png to the “ICNS” format (there are online and command-line tools to do that) 3. Copy the converted ICNS file over the file Icon.icns in the OSX.app Resources folder. 4. Copy the build-generated file (given in the ‘App name’ field) for macOS (either 32 or 64 bit) over the file 8th in the MacOS folder 5. Copy the build-generated file appdata over the file myapp/OSX.app/assets/appdata 6. Edit the Info.plist as necessary 7. Rename the OSX.app folder to correspond to the ‘App name’ of your application At this point you should be able to run the application by simply clicking on its icon in the Finder application. You can also sign it if you wish, prior to distributing it using the codesign tool from XCode.

— 118 —

Chapter 22: Words by namespace

The following is an exhaustive list of the built-in words in 8th, arranged by namespace, including descriptions of the words and their stack-effects. The information here is the same as that provided by the console help. ID app a bt b con cr db d dbg f font g G hw h img m net n q r sio snd st s t w xml

Name Application Array Bluetooth Buffer Console Crypto DB Date Debug File Font GUI Global Hardware Heap Image Map Network Number Queue Regex Serial Sound Stack String Task Word XML

Description Application Arrays are sequentially ordered containers accessed by numeric index Bluetooth discovery and I/O Buffers represent a memory area with a specific length Console I/O Encryption and decryption SQLite database Date and time object Debugging words File operations Font utilities Graphical User Interface Catch-all class Hardware abstraction layer Ordered container JPEG, PNG and BMP images Maps are unordered containers accessed by a string key Internet and sockets Numbers: integers or floating-point FIFO Queue PCRE regular-expression Serial I/O Playing and recording sounds Fixed-size stack Arrays of UTF-8 encoded characters Task (Thread) Words are the smallest unit of execution XML parsing

Application app:8thdir

-- s

Returns a string s which is the name of the (OS specific) directory where 8th stores data; this is almost the same as app:datadir, but is always the ".8th" directory

— 119 —

The 8th Manual: Words by namespace app:asset

name -- data

Read a 'built-in' asset, returning a buffer data with the content. The value name refers to a "relative path". That path is relative to where the script is located. So if the script is in src/app.8th then the asset "image/a.png" is in "src/image/a.png". For a compiled application, the asset is part of the application bundle created by the build tool app:atrun

opt --

Given a map opt, arrange to launch the indicated application at a specific time. The keys in the map are: "exe" - a string which is the name of the executable to run (required); "args" - an array of strings which has the command-line arguments to the application; "when" - a date which indicates the time at which the application should be run (required); "dir" - the directory where the exe should run (not effective on Linux/RPI). Not yet implemented on mobile platforms. On Linux and RPI this word requires "atd" be installed and running app:basedir

-- dir

Returns a string dir which is the name of the (OS specific) application-accessible directory app:datadir

-- s

Returns a string s which is the name of the (OS specific) directory where this application stores data app:exename

-- s

Returns a string s which is the running executable's name app:isgui

-- v

Returns a var v which determines whether 8th considers this a GUI application or not. It defaults to false except for mobile platforms. If you are writing a GUI application, you should set this to true before your app:main executes app:main

--

If you define a word with this name, your application will start there. Otherwise, the default version will run, which just invokes cold app:orientation

n f --

deferred: Invoked (on Android, currently) when the device orientation has changed. The boolean f is true if the orientation is "portrait", false otherwise. The number n is 1 for 'upright', 2 for 'upside down', 3 for 'rotated clockwise' and 4 for 'rotated anti-clockwise' app:resumed

--

deferred: Invoked when the application is about to be resumed. Take care of restoring application state here, saved in app:suspended app:suspended

--

deferred: Invoked when the application is about to be suspended. Take care of saving application state here, in preparation for app:resumed app:sysquit

-- f

deferred word which is invoked if the system requested that the application shut down. The default simply returns true, which means "quit". If you do not want to allow the system to close the application, you should return false instead

Array a:!

a ix z -- a

Put the item z in the array a at number index ix. If that index is larger than the largest current index, the array will be resized and the empty spots created will be filled with null. If ix is negative, then the element at the index from the end of the array will be modified. For example, an index of "-1" will modify the last element a:+

a1 a2 -- a1+a2

Append contents of array a2 to array a1, modifying it a:-

a n -- a

— 120 —

The 8th Manual: Words by namespace Remove the item at index n from the array a, moving other items over to fill the gap. If you just want to remove an item from the array without changing the position of other elements, simply store null in the position of the item you want to remove. If n is less than 0 or greater than or equal to a:len, nothing happens a:@

a ix -- a z

Returns the item in the array a at number index ix. If ix is negative, get the item from the end of the array, e.g. "-1" corresponds to the last element. If ix is out of bounds, null is returned (though null might be a valid element as well! It locks a while the item at ix is retrieved a:bsearch

a x cmp -- a ix

Search for the item x in the sorted array a, using the comparison word cmp. That word takes two items of the given type and returns a negative number if the first is less than the second, 0 if equal and a positive number if the first is greater than the second. Returns the number ix of the index of the matching item, or null if there was no match. The array must have been sorted in ascending order according to cmp in order for this to work correctly a:clear

a -- a

Remove all elements from the array a, similar to repeatedly invoking "a:pop drop" a:close

x1 x2 x3 ... xN N -- a

Create an array a from N items on the stack. This is the inverse of a:open. If n is 0 or negative, will only consume TOS (e.g. n) a:dot

a1 a2 w1 w2 -- x

Generalized "dot product" of the two arrays a1 and a2. If they are not the same length, returns null. Otherwise, execute the word w1 on each corresponding item in each array, and then execute the word w2 on each pair of results, accumulating them into a result x. For example: [1,2] [3,4] ' n:* ' n:+ a:dot will result in the number 11 a:each

a w -- a

Iterate over array a and invoke word w for each element in it. The stack effect of w is: "ix item"; that is, it is passed both the index of the item and the item itself. The array a is not available on the stack while a:each is running, to avoid consistency problems. w must consume both items passed a:exists?

a ix -- a f

Returns true if there is a value defined for the index ix in the array a. This is necessary because requesting an arbitrary index from an array will always succeed, returning null if the index does not exist as well as if the value stored is actually null a:filter

a1 w -- a2

Create a new array a2, whose elements are those from the array a1 for which the word w returns true. Each element of a1 is passed in turn to w, which returns true if that item should be kept or false if it should be removed from the result. It must consume each item it is given a:indexof

a x cmp -- a ix

Search for the item x in the array a, using the comparison word cmp. That word takes two items of the given type and returns true if they match, or false otherwise. Returns the number ix of the index of the matching item, or null if there was no match a:insert

a1 a2 x -- a3

Insert the array a2 into the array a1 at offset x, which must be a positive number. If x is greater than the current number of items in a1, the missing items will be null. The result is a new array a3 with the combined contents a:join

a s -- s1

Inverse of s:/. Join the array of strings a, inserting the string s between each pair of items; return new string s1 a:len

a -- a n

Return the length of the array a, e.g. the number n of items it currently contains. This is the highest index occupied plus 1 (indices start at 0) a:map

a1 w -- a2

— 121 —

The 8th Manual: Words by namespace Create a new array a2, whose elements are formed by executing the word w for each element of the original array a1. w is passed each item on the stack, "x -- x2. The mapping must consume the element given, producing a single result in TOS, which becomes the corresponding element in the new array a:op

a1 a2 w -- a3

Takes two arrays and invokes the word w to the corresponding elements of a1 and a2, producing a new array a3. If the arrays are not of equal size, will stop after processing the shorter one; thus, the result will be of the same length as the shorter of the two inputs a:open

a -- x1 x2 x3 ... xN

Open up the contents of the array a, spilling it onto the stack. Faster and more clear than manually unpacking the array. Be careful not to overflow the stack! Mostly useful after using unpack so you can access the data easily. Pair with a:close (you need to add back the length in TOS for that to work) a:pop

a -- a o

Pop the item o from the array a, that is from the highest index in the array which is currently occupied. If the array was empty, return null a:push

a o -- a

Push the item o onto the array a. The array will expand as needed, and o will be in the highest index in the array which is currently occupied a:reduce

a w x -- x

Iterate over the array a and invoke word w for each element in a. w is passed the stack: "item value -- result". "value" is the result of the previous calculation (or x if this is the first iteration). The initial value x is passed to w along with the first element. Leaves the result on TOS a:rev

a -- a

Given an array a, modifies it so the elements are in reverse order a:shift

a -- a x

Remove the item x from the first position in the array and put it on TOS. This makes the array one element shorter, and shifts all remaining elements one lower. Like pop but from the beginning of the array a:shuffle

a -- a

Randomly shuffles the entries in the array a. Uses rand-pcg, so it is not cryptographically random a:slice

a x y -- a1

Return an array a1, which is a slice of the array a beginning at index x for y items. A negative value of x means "take from the end of the array". If y is greater than the number of items in a (starting from the index x) then the slice will be only as large as the number of items in a permits a:slide

a x -- a

Add the item x to the first position in the array a, moving all remaining items up one index. Like push but at the beginning of the array a:sort

a w -- a

Sort the array a using the comparison word w. That word takes two items and compares them, returning 0 if they are equal, a positive number if TOS is less than the second, or negative otherwise. NOTE: If the comparison function modifies the elements it is given, they will be modified in the original array! a:when

a --

Takes an array a containing pairs of words. For each pair, it evaluates the first word. If that word evaluates to true then the second word will be invoked. If none of the elements evaluates to true, then if there is a last item it is invoked a:when!

a --

Same as when, but invokes all words whose matching first part evaluates to true

— 122 —

The 8th Manual: Words by namespace a:y

a w -- b

Given an array a and a word w which takes two items and returns one item; produce an array b which is the result of applying w to consecutive elements of a. This will result in an array one shorter than the input. If the input has less than two elements, a clone will be returned and w will not be invoked a:zip

a1 a2 -- x1 x2 ...

Takes two arrays a1 and a2, and "zips" them together, producing a new array for each corresponding item in the first two. For example: [1,2,3] [3,4,5] a:zip will produce [1,3] [2,4] [3,5]. If the arrays are not of equal size, will stop after processing the shorter one; thus, the number of resultant arrays will the minimum of the lengths of the two inputs

Bluetooth bt:accept

bt -- bt2|null

Given a bt bt created with bt:listen, waits for a connection to be created. When it is, returns bt2 which can be used with bt:read and bt:write; or it returns null if there was an error bt:ch!

bt svcuuid uuid data -- bt f

Writes a BLE characteristic identified by the string uuid in the service identified by the string svcuuid on the BT connection given in bt. The buffer data will be written; you must ensure that it contains data appropriate for the service and characteristic. Returns true if it succeeded initiating the write, false otherwise. See also bt:ch@ bt:ch@

bt svcuuid uuid -- bt data

Reads a BLE characteristic identified by the string uuid in the service identified by the string svcuuid on the BT connection given in bt. The buffer value will be returned (or null if it was unable to read). See also bt:ch! bt:connect

opts -- bt|null

Given a map opts returned from bt:scan, returns a new bt item bt which may be used with bt:read and bt:write. If it fails to connect, returns null. Additional keys in opts may be: "l2cap" - optional; if true use L2CAP protocol, otherwise use RFCOMM; "port" a number defining the port to use; "uuid" - a string containing the UUID of the service to connect to bt:disconnect

bt -- bt

Given a bt bt returned from bt:connect or bt:leconnect, disconnect the connection (if bt is currently connected) bt:err?

-- n

Returns a number n, which is the error code from the last bt: word which failed, and resets the code to 0. Corresponds to "errno" from the C library bt:leconnect

opts -- bt|null

Given a map opts returned from bt:lescan, returns a new bt item bt which may be used with bt:read and bt:write. If it fails to connect, returns null bt:lescan

cb to --

Scans for nearby Bluetooth 4.0 (BLE) devices. The word cb is called for any devices found. It receives a map with information about the device found, and must return true to continue scanning or false to stop scanning. The scan will continue as long as any devices were found within to seconds. If no devices were found within to seconds, the scan will cease and cb will be called with a parameter of null. The word cb is called on a separate task (thread) and should not do more than save the information and set a flag or similar bt:listen

opts -- bt|null

Given a map opts defining what service to bind to and listen on etc., returns a new bt item which may be used with bt:accept. If it fails to connect, returns null. The keys in opts are: "l2cap" - optional; if true use L2CAP protocol, otherwise use RFCOMM; "port" - a number defining the port to use; "uuid" - a string containing the UUID of the service to publish bt:on?

-- f

Returns true if the Bluetooth system of the machine is on, false otherwise bt:read

f s n -- f s n

— 123 —

The 8th Manual: Words by namespace Same as f:read but for a bt connection bt:scan

cb to --

Scans for nearby Bluetooth (BT) devices. The word cb is called for each device found, and passed a map with the device information. It is passed null when the scan is done. It must return true to continue scanning, or false to terminate the scan. The number to is the number of seconds to perform the scan. The map passed cb for each device will contain the keys "id" and "name", where "id" is the 48-bit identifier and "name" is the friendly name given the device by its owner bt:service?

id uuid -- a|null

Scan the BT device with string identifier id (as returned from bt:scan) for services using the string UUID uuid (or null) for all services. Returns an array a of service descriptors or null if none are available bt:services?

bt w to -- bt

Takes a bt returned from bt:leconnect representing a BLE peripheral, and a word w to invoke for each service the peripheral advertises. bt:write

f s -- f n

Same as f:write but for a bt connection

Buffer b:!

b n c -- b

Put the byte c at number offset n in the buffer b b:+

b1 b2 -- b3

Appends the buffer b2 to the buffer b1 yielding a new buffer b3 b:/

b n -- a

Split the buffer b at number offset n. Returns an array a with the first part of the buffer in element 0, the second part in element 1 b:=

b1 b2 -- f

Compare the two buffers b1 and b2 for byte-wise equality, returning true or false b:>base64

b -- s

Encode buffer b in base64 encoding, returning string s b:>hex

s -- b

Convert the 'hex dump' in the string s into the bytes it represents in a buffer b. See also b:hex> b:@

b n -- b x

Returns the byte (number) x at number offset n from the buffer b. Throws an exception if attemped read is beyond the bounds of the buffer b:base64>

s -- b

Decode string s from base64 encoding, returning buffer b b:clear

b -- b

Overwrite contents of buffer b with the value 0; the original buffer itself is modified b:compress

b -- b

Compress a buffer b using zlib b:conv

b1 from to -- b2|errcode null

— 124 —

The 8th Manual: Words by namespace Converts the buffer b1 from the character encoding given by the string from to the one given by to, returning the converted buffer b2 or null and an error code errcodeif it was unable to perform the conversion. Linux and RPI users must have installed the "libiconv" library for this to work. The errcode (if null was returned) is one of: 1 - no libiconv library; 2 - unknown charset; 3 - error converting text b:each

b w --

Invokes word w for each byte of the buffer b. It is w's responsibility to consume the byte. The word w is passed two items: ix n. The number ix is the index of the byte in the original buffer b; the number n is the value of the byte at that index b:expand

b n -- b

Expand a zlib-compressed buffer b, where the number n is the original size of the uncompressed buffer b:fill

b c| b n a -- b

Fill contents of buffer b with character c, or fill buffer with contents of buffer or string a at offset n in the original buffer. b:hex>

b -- s

Convert the buffer b into a 'hex dump' in the string s representing it. See also b:>hex b:len

b -- b l

Report the length l as a number of bytes, of the buffer b b:new

x -- b

Create a new buffer b. If x is a number, creates a buffer of size x bytes which is NOT initialized (use b:clear or b:fill to do that); if x is a string, creates a buffer as big as the contents of the string, with a copy of the string's contents. If x is a buffer, creates a clone of the original one b:op

b1 b2 w -- b3

Takes two buffers and invokes the word w for each byte of b1, applying w to that byte of b1 and a corresponding byte from b2 (modulo its size). The resultant byte goes into a new buffer b3. This can be used, for example, to perform an "xor" of a password against a block of data. The result is a buffer the same size as b1. The w word gets the byte from b1 and then the byte from b2, in that order (byte from b2 on TOS) b:rev

b -- b2

Given a buffer b, returns a copy of it b2 with the bytes in reverse order b:search

haystack needle -- haystack n

Search the buffer haystack for the first occurrence of needle, returning the offset of the found data in n, or null. needle may be either a string or a buffer b:shmem

name size ro -- b

Given a string name to use as an identifier for an interprocess shared-memory object, a number size specifying its size, and a flag ro indicating if the memory should be read-only (if the flag is true), return a buffer b which points to that shared memory, or null if this was not possible b:slice

b x y -- b1

Return a slice of the buffer b: semantically the same as s:slice. Returned buffer b1 is a slice of b, beginning at offset x for y bytes b:xor

b1 c|b2 -- b1

Apply a bytewise XOR between every byte of the buffer b1 and either the number character c, or the buffer b2, repeatedly until every byte of b1 has been XORed. The original buffer's data is overwritten

Console con:accept

n hist -- s

— 125 —

The 8th Manual: Words by namespace Requests a string of maximum length n from the console. If desired, a array of strings hist may be provided (must be null if no history is needed). The same editing keys as with regular console input are allowed. Returns the entered string s or null if Ctrl+C was pressed con:accept-pwd

n -- s

Requests a password string s of maximum length n from the console. Does not display the characters entered. Instead, it shows '*' for each character. The same editing keys are allowed as with con:accept con:black

--

Set the console foreground color to black. Must be paired with one of the con:on... color commands con:blue

--

Set the console foreground color to blue. Must be paired with one of the con:on... color commands con:bold

--

Set the console text attribute to bold con:clreol

--

Clear the current console line from the current position until the end of the line con:cls

--

Clear the console screen and put the cursor on the first row con:cyan

--

Set the console foreground color to cyan. Must be paired with one of the con:on... color commands con:dim

--

Set the console text attribute to dim con:down

--

Move the console position down one con:free

--

Closes the console window (Windows) con:getxy

-- row col

Return the position of the console cursor con:gotoxy

row col --

Set the console cursor position con:green

--

Set the console foreground color to green. Must be paired with one of the con:on... color commands con:key

-- n

Blocks while waiting for key input from the console. When a key is pressed, it returns the key-code of the pressed key as a number n con:key?

-- f

Return true if con:key would return a value without blocking, false otherwise con:left

--

Move the console position left one

— 126 —

The 8th Manual: Words by namespace con:load-history

s f --

Load the console's history from the file named s. Each line is a separate history item. If f is true, then overwrite the current history; otherwise, append the contents of s to the current history. Only up to 100 items will be read in con:magenta

--

Set the console foreground color to magenta. Must be paired with one of the con:on... color commands con:nobold

--

Un-set the console text attribute from bold con:normal

--

Set the console text attribute to normal con:nouscore

--

Re-set the console text attribute from underscore con:onBlack

--

Set the console background color to black. Must be paired with one of the con:... color commands con:onBlue

--

Set the console background color to blue. Must be paired with one of the con:... color commands con:onCyan

--

Set the console background color to cyan. Must be paired with one of the con:... color commands con:onGreen

--

Set the console background color to green. Must be paired with one of the con:... color commands con:onMagenta

--

Set the console background color to magenta. Must be paired with one of the con:... color commands con:onRed

--

Set the console background color to red. Must be paired with one of the con:... color commands con:onWhite

--

Set the console background color to white. Must be paired with one of the con:... color commands con:onYellow

--

Set the console background color to yellow. Must be paired with one of the con:... color commands con:print

s --

Print the string to the console, taking into account console text attributes and positioning con:red

--

Set the console foreground color to red. Must be paired with one of the con:on... color commands con:redir?

-- f

Return true if the input is redirected (from a pipe for instance) con:right

--

Move the console position right one

— 127 —

The 8th Manual: Words by namespace con:save-history

s --

If s is a string, open it as a text file in which to append the console's history of input. If s is null, close the history file previously opened. History is, by default, not saved. This word causes the history to be saved from the point it is invoked with file name until the point it is invoked with a null con:size?

-- col row

Returns the current size of the console in columns and rows con:up

--

Move the console position up one con:uscore

--

Set the console text attribute to underscore con:white

--

Set the console foreground color to white. Must be paired with one of the con:on... color commands con:yellow

--

Set the console foreground color to yellow. Must be paired with one of the con:on... color commands

Crypto cr:>decrypt

x key -- n

Given a buffer key containing an encryption key (see cr:genkey or cr:randkey) and a string or buffer x with encrypted data, begins decryption and returns a crypt n which must be passed to further crypt words, or null if there was an error cr:>encrypt

x key -- n

Given a buffer key containing a key (see cr:genkey or cr:randkey) and a string or buffer x with data to encrypt, starts encryption and returns a crypt n which must be passed to further crypt words, or null if there was an error cr:>uuid

b -- uuid

Creates a UUID string uuid from a buffer b whose length is 16 bytes cr:cipher!

s --

Used to set the cipher parameters. The string s may be any of: 3des aes blowfish camellia cast5 des twofish. Throws an exception if given an unknown cipher name cr:cipher@

-- g

Get the current cipher algorithm as a string g, suitable for passing to cr:cipher! cr:decrypt+

x n -- n

Given the crypt n returned by cr:decrypt, add the contents of the string or buffer x and return the same crypt for further processing, or null if there was an error cr:decrypt-ctr

b key iv -- x

Given an encrypted buffer b, a buffer key containing a key (see cr:genkey or cr:randkey) and a buffer iv containing an initialization vector, decrypt b using CTR mode and return a buffer x containing the decrypted result, or null if there was an error cr:decrypt>

n -- b

Given the crypt n returned by cr:decrypt or cr:decrypt+, finalize the decryption and return a buffer b with the decrypted data or null if there was an error

— 128 —

The 8th Manual: Words by namespace cr:dh-genkey

n -- priv pub

Generate an Diffie-Hellman key-pair of size n. That number may be from 96 to 512, corresponding to key sizes from 768 to 4096. Returns the binary encoded key-pair as two buffers priv and pub corresponding to the new private-key and public-key, or null if there was an error cr:dh-secret

priv pub -- b

Generate an Diffie-Hellman shared secret using one party's private DH key priv, and the other party's public DH key pub. The result is a buffer b which is the shared secret, or null if there was an error cr:dh-sign

dhkey hash -- sig

Given a buffer dhkey containing a Diffie-Hellman private key (of the sender), and another buffer hash containing a hash, signs the hash using DH algorithms and returns an signature buffer in sig. Returns null if there was an error cr:dh-verify

dhkey hash sig -- f

Given a buffer dhkey containing a Diffie-Hellman public key (of the sender), another buffer hash containing a hash which was signed, and another buffer sig containing the DH signature, verifies the hash signature using DH algorithms and returns true on successful verification or false otherwise cr:ecc-genkey

n -- priv pub

Generate an ECC key-pair of size n . Returns the binary encoded key-pair as two buffers priv and pub, corresponding to the new ECC private-key and public-key, or null if there was an error. Valid values of n are 12, 16, 20, 24, 28, 32, 48 and 65, which correspond to key sizes of 112, 128, 160, 192, 224, 256, 384, and 521 bits respectively. These are curves from http://csrc.nist.gov/cryptval/dss.htm cr:ecc-secret

priv pub -- b

Generate an ECC shared secret using one party's private ECC key priv, and the other party's public ECC key pub. The result is a buffer b, or null if there was a problem cr:ecc-sign

ecckey hash -- sig

Given a buffer ecckey containing a ECC private key (of the sender), and another buffer hash containing a hash, signs the hash using ECC algorithms and returns an signature buffer in sig. Returns null on error. Uses the ANSI X9.62 EC-DSA algorithm to generate signatures in the ANSI X9.62 format cr:ecc-verify

ecckey hash sig -- f

Given a buffer ecckey containing a ECC public key (of the sender), one containing a hash which was signed hash, and another buffer containing the signature sig, verifies the hash signature using ECC algorithms and returns true on successful verification or false otherwise cr:encrypt+

x n -- n

Given the crypt n returned by cr:encrypt, add the contents of the string or buffer x and return the same crypt for further processing, or null if there was an error cr:encrypt-ctr

x key iv -- b

Given a string or buffer x, a buffer key containing an encryption key (see cr:genkey or cr:randkey) and a buffer iv containing an initialization vector, encrypt x using CTR mode and return a buffer b with the encrypted result, or null if there was an error cr:encrypt>

n -- b

Given the crypt n returned by cr:encrypt or cr:encrypt+, finalize the encryption and return a buffer b with the encrypted results or null if there was an error cr:err?

-- n

Returns the error code number n (libtomcrpyt-specific) from the last crypto word which generated an error (null return value). If it is 0, no error occurred, or another crypto word ran successfully in the meantime cr:genkey

pwd salt iter -- key

Takes the password string pwd, the salt string salt, the number of iterations iter and returns a PBKDF2-generated key in a 32 byte buffer key, or null if there was an error

— 129 —

The 8th Manual: Words by namespace cr:hash

x -- n

Take the item x (string or buffer) and return its hash as a crypt n, or null if there was an error. The specific hash algorithm to use is determined by cr:hash!, with "blake" being the default hash. The hash to use is context-specific, so separate tasks or callbacks may use different hash functions simultaneously without concern. See also: cr:hmac cr:hash!

s --

Used to set the hash parameters. The string s may be any of: blake md5 rmd128 rmd160 rmd256 rmd320 sha1 sha256 sha384 sha512 tiger whirlpool. The "rmd" are RIPEMD hashes. Throws an exception if given an unknown hash name cr:hash+

x n -- n

Take the item x (string or buffer) and append its hash to the current hash in crypt n (returned from cr:hash). Returns the crypt it was given, or null if there was an error cr:hash>b

n -- b

Finalize the hash calculation of crypt n, and return the hash value as a binary buffer b, or null if there was an error cr:hash>s

n -- s

Finalize the hash calculation of crypt n, returning the hash value as a readable string s, or null if there was an error cr:hash@

-- g

Get the current hash algorithm as a string g, suitable for passing to cr:hash! cr:hmac

x s -- n

Take the item (string or buffer) x and return a crypt n which is its HMAC-hash using the key s (which may be a string or a buffer), or null if there was an error. The rest of its semantics are exactly the same as cr:hash cr:randkey

-- b

Return a buffer b containing a pseudo-random key for encryption, using a cryptographically strong random number generator cr:rsa_decrypt

key x -- b

Decrypt the string or buffer x with the RSA public or private-key x, putting the results in b cr:rsa_encrypt

key x -- b

Encrypt the string or buffer x with the RSA public key x, putting the results in b cr:rsa_sign

hash key -- b

Sign the hash of a message with the RSA private key, leaving the signed buffer b cr:rsa_verify

hash key sig -- f

Verify the hash of a message with the RSA private key, against the RSA signature sig. Returns true if ok, or false otherwise cr:rsagenkey

n -- priv pub

Generate an RSA key-pair of number size n. Valid values of n are 1024, 2048 and 4096. Returns the DER encoded key-pair as two buffers priv and pub on the stack, or null if there was an error cr:uuid

-- uuid

Returns a string uuid which is a cryptographically strong random UUID cr:uuid>

uuid -- b

Takes a string uuid which is a UUID and returns a buffer b 16 bytes long representing it, or null if the string is not in the correct format

DB — 130 —

The 8th Manual: Words by namespace db:bind

q x n|q a -- q

Bind the item x to the parameter number n of the prepared query q. Alternatively, bind the items in the array a, in order, to the query db:close

f --

Close the db f db:col

q n -- q x

Used ONLY inside a db:exec-cb callback. It returns the value x of the query column n from the sql q db:col[]

q -- q a

Used ONLY inside a db:exec-cb callback; retrieves all the columns of the query q into an array a db:col{}

q -- q o

Used ONLY inside a db:exec-cb callback; retrieves all the columns of the queyr into a map o db:err?

f -- n

Returns the last error code number n from the db f, or 0 if no error db:errmsg

f -- s

Returns a string s which is the last error message (database-specific) from the db f, or "OK" if no error db:exec

d n|s -- d

Execute the sql (prepared statement) n, or the SQL string s on the db d, running until finished db:exec-cb

d w n|s -- d

Like exec, but invokes the word w as a callback for each row retrieved. A callback word is given one parameter: a sql which is passed to the db:col words to get the column data db:key

db buf -- db

Tell the SQLite engine it should use the key buf (a buffer) as the encryption key for the database db. The database must have been created encrypted in order for this to work, and the key must exactly match the one used originally db:mysql?

-- f

Returns true if MySQL support is currently available, false otherwise. If true, you may use the db words to access MySQL databases. The support is provided by a third-party library which must be installed separately from 8th. The URL is: https://dev.mysql.com/downloads/connector/c/ db:odbc?

-- f

Returns true if ODBC support is currently available, false otherwise. If true, you may use the db words to access ODBC databases. It should always succeed on Windows. On Linux/RPI you need to have installed unixodbc or iodbc. On macOS you need to have configured an ODBC source. On mobile devices there is no ODBC support at present db:open

x -- f

Open the SQLite or MySQL database indicated by the string or buffer x. If x is a string, it is used as the name of a file to open (or create, if it doesn't exist) as a database. If x is a buffer, then it is assumed to be a SQLite database in its entirety, as a buffer (e.g. from app:asset or f:slurp). In that case, it is treated as a read-only database. Will return null if it was unable to open the database for some reason; otherwise returns a db f db:prepare

db s -- db q

Prepare the SQL query in the string s for execution against the db db. Return a sql q or null if there was an error db:rekey

db buf -- db

Tell the SQLite engine it should use the new key buf (a buffer) as the encryption key for the database. If the database was not encrypted, it will be now; otherwise, it will be re-encrypted with the new key

— 131 —

The 8th Manual: Words by namespace db:sqlerrmsg

sql -- s

Returns a string s which is the last error message (database-specific) from the sql sql, or "OK" if no error

Date d:+

d n -- d

Add n days to the date d. It may be a negative number, in which case the days are subtracted from d d:+msec

d ms -- d2

Advance the date d by the number of milliseconds ms, leaving the date d2. The ms value may be negative, in which case d is decreased d:-

d1 d2 -- n

Returns the difference n, in days, between the dates d1 and d2 d:/

d -- a

Split the date d into an array a containing, in order: year, month, day, hour, minute, second, tzHH, tzMM (time-zone offset in hours and minutes from GMT) and msec. See also d:join d:=

d1 d2 -- f

Return true if the dates d1 and d2 are equal d:>fixed

d -- fixed

Return the number fixed, which is a "fixed" time value corresponding to the date d d:>msec

d -- n

Return the number n of milliseconds since Jan 01 1970 corresponding to the date d d:>unix

d -- n

Return the Unix timestamp as a number n corresponding to the date d d:fixed>

n -- d

Return a new date d corresponding to the number n which is a "fixed" time value. The range of valid n is 0..3652059, corresponding to 1-1-1 to 9999-12-31 d:format

s d -- s

Format a date d according to the string s. If a "%" character appears, the following character is a format-specifier; otherwise, it is output directly. Valid format specifiers are 'Y' (four digit year), 'y' (two digit year), 'M' (two-digit month), 'm' (month), 'N' (long month name), 'n' (short month name), 'D' (two-digit day), 'd' (day), 'W' (long day name), 'w' (short day name), 'H' (2-digit hour), 'h' (hour), 'P' (2-digit 12hr), 'p' (12hr), 'T' (2-digit minute), 't' (minute), 'S' (2-digit second), 's' (second), 'x' (3 digit milliseconds), 'Z' time-zone offset d:join

a -- d

Inverse of d:/: takes an array a of numbers with year, month, day, hour, minute, second, tzHH, tzMM and msec, and returns a date d. See also d:/ d:msec

-- n

Returns the current time as a number n of milliseconds since Jan 01, 1970 d:msec>

n -- d

Return a new date d corresponding to the number of milliseconds n since Jan 01 1970 d:new

-- d

Create a new date d, initialized to the current time

— 132 —

The 8th Manual: Words by namespace d:parse

s -- d

Attempt to parse a valid date and/or time from string s, and return the date d appropriately set if successful, or set to the current time otherwise. The date/time string should be in one of the ISO-8601 formats d:unix>

n -- d

Return a new date d corresponding to the Unix timestamp number n

Debug dbg:bp

w --

Set a breakpoint at the word w. This is a "one-shot" breakpoint, and gets reset once you do dbg:go dbg:go

--

Continue operation after dbg:stop or a breakpoint from dbg:bp dbg:prompt

n --

deferred: word which issues the "dbg> " prompt. Otherwise the same as prompt dbg:stop

--

Stops and enters an interpreter waiting for commands. Use dbg:go to continue dbg:trace

f --

Turn "tracing" on or off. If on, new words will include invocations of the word set by dbg:trace-enter and dbg:trace-leave dbg:trace-enter

w --

If dbg:trace is turned on, then invoke the word w upon entry to any compiled word. w is passed a word in TOS which is the current one being executed. If null, turns off the trace. The word must consume TOS dbg:trace-leave

w --

If dbg:trace is turned on, then invoke the word w upon exit from any compiled word. w is passed a word in TOS which is the current one being executed. If null, turns off the trace. The word must consume TOS

File f:abspath

x -- s

Given a file (or string containing a file name) x, return a string s containing the absolute path of the original file name f:associate

ext desc longdesc app --

Associate the application app as the default for opening the file extension ext, with a short description of desc and a long description of longdesc. The short description must not have spaces in it. Currently, this word only works on Windows f:atime

f -- f dt

Return the last-accessed time of the file f as a date dt f:canwrite?

s -- f

Given the file named s, returns true if it is possible to write to it or false otherwise (if the file does not exist, will determine if the parent directory is writeable) f:chmod

x m --

Change the "mode" of the file x to that indicated in the string m. The mode can contain "r" for "readable", "w" for "writeable" and "x" for "executable". This only affects the user-modes. The file may be an open file or a string with the name of a file. If a "+" is included then the modes are added to the existing one, if "-" they are removed, otherwise they are set exactly

— 133 —

The 8th Manual: Words by namespace f:close

f --

Close the file f f:copy

orig dest -- f

Try to copy the file named orig to a new file named dest, which will be removed if it already exists. If the copy succeeds, true will be on TOS, otherwise false f:copydir

orig dest -- f

Try to recursively copy the directory named orig to a new one named, dest. If the copy succeeds, true will be on TOS, otherwise false f:create

s -- f

Create the file named by the string s, returning the file f. An existing file by that name will be destroyed; if that is not your intention, use f:open instead f:ctime

f -- f dt

Return the creation time of the file or string naming a file f as a date dt f:dir?

s -- f

Determine if the name s is a directory; return true if it is a directory, false otherwise f:dname

fname -- dir

Returns the front part (just the path) of the filename fname as a string dir f:eachbuf

f w n -- f

Similar to f:eachline, but passes a buffer of up to n bytes to the word w f:eachline

f w -- f

Similar to s:eachline, but leaves the file on TOS when done f:enssep

f -- f

Ensure that the file name given by the string f ends with the OS-appropriate directory-separator Use this instead of hard-coding a "\" or "/" f:err?

f -- n

Returns the last error code (OS-specific) number n from the file f, or 0 if no error f:exists?

s -- f

Determine if the name s is an existing file or directory; return true if it exists, false otherwise f:flush

f -- f

Make sure any buffers containing unwritten data in the file f are written f:fname

fname -- fn

Returns the last part (exclusive of path) of the filename fname as a string fn f:getline

f -- f s

Read one line as a string s from the file f. "line" means up to but not including a newline or carriage-return character ("\n" or "\r"). Returns null if no data are available (or trying to read past end-of-file) f:getmod

x -- n

Returns the OS-specific "mode" of the file x as a number n. See your OS documentation for the specific interpretation of the "mode" number. x may be an open file or a string representing the name of a file. See also f:chmod

— 134 —

The 8th Manual: Words by namespace f:glob

s -- a

Return an array a of file names matching the string pattern s. The "glob" pattern is not a regex but rather the usual "*" and "?" file matching f:glob-nocase

f --

If f evaluates to true, then the f:glob word will be case-insensitive; otherwise, case-sensitive. The default for this setting is true on Windows and macOS, and false on all other systems f:include

s --

Read the file named s and interpret it as 8th code. Looks first for the file name as given. If that does not succeed, looks for the same named item in the "incs" asset, and then in the app:datadir, in the directory pointed to by the "EIGHTHLIB" environment variable and finally in the app:8thdir. Throws an exception if it cannot load the file. See also: f:slurp, app:asset, needs f:launch

s params --

Launch the file named s: if it is executable, run it; if it is a document, start the appropriate application to open it; if it is a folder, show it in the OS-specific folder viewer. Give the parameter string params (may be null) f:link

old new -- f

Makes a symbolic link named new, to the file named old. Currently, this is only implemented on macOS and Linux). Returns true on success, or false on failure (or if unsupported) f:link>

orig -- orig'

If the file or folder named orig is a link or alias, returns what it points to; otherwise returns the original name f:link?

name -- f

Returns true if name is a link to a file f:mkdir

s -- f

Create the directory s; returns true on success, else false f:mmap

s ro -- buf

Opens the file named s as a "memory-mapped" file. The parameter ro is true if the file should be read-only, or false if it should be writeable. Note that resizing the file is not possible, it must be whatever size is required before opening it. Returns a buffer buf which contains the contents of the mapped file f:mmap-range

s ro start end -- buf

Same as f:mmap, but only maps the file from start to end, which must be numbers and within the range of the number of bytes in the file. The start value may be rounded-down to an OS page boundary f:mmap-range?

buf -- buf start end

Given a buffer buf returned from f:mmap or f:mmap-range, returns the start and end offsets it represents, or null if it was not an "mmap-ed" buffer f:mtime

f -- f dt

Return the last-modified time of the file f as a date dt f:mv

s s2 -- f

Rename ("move") the file named s to the new name s2. Returns true on success, false otherwise. See also f:rm f:open

s -- f

Open the file named by the string s for read/write acces, and create a file f. Returns null if there was an error (no access, or file doesn't exist). See also: f:open-ro and f:create f:open-ro

s -- f

Same as f:open, but the file is opened in "read-only" mode

— 135 —

The 8th Manual: Words by namespace f:popen

cmd ro -- f

Given a string with the name cmd of an external command to invoke, and a flag ro , returns a new file f from which the results of the command can be read, and which can also be written to. If it was not successful, return null. If ro is true, the returned pipe is read-only; otherwise it is write-only f:print

s --

Attempts to print the file named by the string s using the common method available on the system. Does not notify if there is an error. Uses CUPS on macOS, Linux and RPI; uses "ShellExecute" on Windows; currently does nothing on mobile platforms f:read

f s n -- f s n

Read n bytes from the file f, into the string or buffer s. The number of bytes read is left on TOS and s contains that many byte; or null is on TOS and s may have partial data, if there was a problem f:relpath

x s -- s'

Given a file (or string containing a file name) x, and a string s containing a folder name, return a string s' with the original file name relative to the given folder. If a relative path is impossible to produce, the returned path will be an absolute one f:rglob

s -- a

Same as glob, but recursively find all files in subdirectories as well f:rm

s -- f

Remove the file named s from the system. Returns true if it succeeded, false otherwise. See also f:rmdir and f:mv f:rmdir

s -- f

Remove the directory named s from the system, and all its contents. Returns true if it succeeded, false otherwise. See also f:rm f:seek

f n -- f

Seek to position n in the file f. If n is negative, it seeks from the end of the file, otherwise it seeks from the beginning f:sep

-- n

Returns the ASCII code n of the character used for separating path components. Use this instead of hard-coding a "\" or "/" f:show

s --

Show the location of the file named by the string s in the OS-specific folder viewer f:size

f -- f n

Return the byte size n of a regular file or string naming a file f, or the number of entries in a zip-file f:slurp

s -- b

Open the file named by the string s and return its contents as a buffer b. Fails if the file does not exist or if there is not enough memory to hold its contents f:stderr

-- f

Open a file f corresponding to the "standard error output". Desktop systems only: returns null on mobile systems f:stdin

-- f

Open a file f corresponding to the "standard input". Desktop systems only: returns null on mobile systems f:stdout

-- f

Open a file f corresponding to the "standard output". Desktop systems only: returns null on mobile systems f:tell

f -- f n

Return the current read or write position in the file f as a number n

— 136 —

The 8th Manual: Words by namespace f:times

s x y --

Sets the access time x and modification time y of the file named by the string s. If x or y is null, do not change that time; otherwise either may be a number (Unix timestamp) or date f:trash

orig -- f

Try to move the file or folder named orig to the system "trash". On success, returns true, otherwise false f:unzip

f dest force -- f

Unpacks the entire ZIP file f to the destination folder named by the string dest. If force is true, overwrites an existing entry by that name. Otherwise, will not. Leaves the original file on TOS f:unzip-entry

f dest ix force -- f

Unpacks one item from the ZIP file f, designated by the number ix into the destination folder named by the string dest. If force is true, overwrites an existing entry by that name. Otherwise, will not. Leaves the original file on TOS f:write

f s -- f n

Write the string or buffer s to the file f. The number of bytes written is left on TOS, or null if there was a problem f:writen

f s n -- f n

Write n bytes to the file f from the string or buffer s. The number of bytes written is left on TOS, or null if there was a problem f:zip+

n s x -- n

Add item x to the new zip-file n, giving it the name s. If x is a string, it is considered to be a file-name. If it is a buffer, it is considered to be data to be put in the zip-file f:zip@

f x -- f b

Read item x from the zip file f, returning a buffer b or null. If x is a number, then the item with that index is returned. If x is a string, the first item with that name is returned f:zipentry

f n -- f d n s

Returns information about the entry at index n in the zipfile f. Returns the string name of the entry s, the number size n and the date of the item d f:zipnew

-- f

Create a new zip-file f (in-memory). The file is saved to disk using f:zipsave f:zipopen

s -- f

Open the zip-file named by s and create the file f. Returns null if there was an error f:zipsave

f s --

Save the (in-memory) zip file f created with f:zipnew or opened with f:zipopen to the file named by the string s. After saving the zip, no further write operations are possible on it

Font font:bold

fnt f -- fnt

If f evaluates true, make the font fnt bold; otherwise remove bold font:face?

fnt -- fnt facename

Returns the font fnt face name, as a string facename font:glyph-path

fnt n -- fnt x

Returns an X containing the "path" representing the outline of the glyph number n in the given font fnt

— 137 —

The 8th Manual: Words by namespace font:glyph-pos

fnt txt -- fnt a1 a2

Returns the series of glyph numbers (from the font fnt, not Unicode points; in array a1) and their offsets from the start (e.g. the width of each glyph) in array a2 of the string txt using this font. The length of a2 is one more than a1, as it also lists the right-edge of the last glyph, which corresponds to the value returned from font:measure font:italic

fnt f -- fnt

If f evaluates true, make the font fnt italic; otherwise remove italic font:ls

-- a

Return an array a of strings containing the names of all fonts known to the system font:measure

fnt txt -- fnt n

Returns a number n which is the width (in pixels) of the string txt using the given font fnt font:new

x -- fnt

Create a new font fnt from the description in x. If it is null, the default system font will be produced. If it is a string, a buffer or a number, the same font creation rules as elsewhere will apply font:pixels

fnt n -- fnt

Change the size of the font fnt to n pixels font:pixels?

fnt -- fnt n

Return the font fnt height in pixels as a number n font:points

fnt n -- fnt

Change the size of the font fnt to n points font:points?

fnt -- fnt n

Return the height n of the font fnt in points font:styles

s -- a

Return an array a of strings containing the names of all styles available for the font family named by the given string s in the system font:styles?

fnt -- fnt m

Return a map m of containing the styles which are applied to the given font fnt. The keys are "italic", "underline", "bold" font:underline

fnt f -- fnt

If f evaluates true, make the font fnt underlined; otherwise remove underlined

GUI g:+child

parent child -- parent

Add the gui child to the gui parent, making parent the parent of the child; also updates the map used to create the parent gui. Returns parent g:+path

g path rot scale x y -- g

Add the "path" given by the X to the current "path" of the gui, scaled by the number scale and rotated rot degrees, at the position given by the numbers x and y g:-child

p x -- p

Remove the child x from the parent gui p, updating the map used to create the parent. The child to remove can be either a gui, a string which is the child's name, or a number which is the index of the child (from 0 to g:childcount - 1)

— 138 —

The 8th Manual: Words by namespace g:/path

g -- g

Close the current path in the gui g g:>progress

g n -- g

Set the value of the progress-bar gui g to the number n g:add-items

g a propname -- g

Adds an array a of string items to the "property" gui g, under the name propname g:adjustwidth

g b -- g

If b is true, resizes the "btn" gui g's width to fit neatly around its current text g:arc

g x y r start stop -- g

Draw an arc in the gui g, positioned at (x,y) with radius r, from angle start to stop (where 0 is at the 3 o'clock position), in degrees. Similar to g:arc2 except it specifies a radius rather than a width and height g:arc2

g x y wide high start stop -- g

Same as g:arc, but start from position (x,y) fitting in the rectangle of size (wide,high), from angle start to stop (0 is the 3 o'clock position, in degrees). Similar to g:arc except that it specifies a width and height instead of a radius g:autohide

g b -- g

If b is true, tells the scrollbar gui g to make itself invisible when not needed g:back

g -- g

For a "web" gui g, navigate to the previous URL g:bezier

g x1 y1 x2 y2 x3 y3 -- g

Draw a (cubic) Bézier curve on the gui g, from the current position, using (x1,y1) and (x2,y2) as control points, and ending at (x3,y3) g:bg

g s -- g

Set the background color of the gui g to s. See also g:fg. The color may be specified as a string (e.g. "red"), a number (e.g. 0xFFFF0000 - note the top byte is the "alpha", or transparency) or an array with RGBA values (each a number between 0 and 1, e.g. [.5,.4,.6,1.0]). Not used for drawing shapes; for those use g:fcolor and g:scolor g:bg?

g -- g n

Returns the background color of the gui g as a number n. See also g:bg g:bounds

g s -- g

Set the 'bounds' of the gui g to the string s g:bounds?

g -- g s

Returns the 'bounds' of the gui g. If the "bounds" key of the map used to create the gui is set, then that is returned; otherwise the actual dimensions are rendered into a bounds string s g:box-label

g s -- g

Sets the label string s that will be displayed next to the filename entry box of the "filename" gui g g:bubble

g msg msec --

Given a gui g to point to, a string msg with a message to display, and a number msec of milliseconds to display, will show a text-bubble with the message g:button-size

g n -- g

Changes the size of the buttons shown along the top of the preferences gui g to be n pixels

— 139 —

The 8th Manual: Words by namespace g:buttons-visible

g b -- g

If b is true, makes the the open/close buttons of the "treeview" gui g visible g:c-text

g -- g

Set text alignment in the gui g to 'center-aligned'. Text will be drawn so the current position is as close as possible to the center g:callout

g content --

Given a gui g to point at (or null for the upper left corner) and a content item which contains either some gui with content or a string of content, put up a callout box containing the content and pointing at g g:center

g1 g2 -- g1

Center gui g1 on g2. If g2 is null, center on screen g:child

g name -- g'

Returns the child g' named name from the gui. If name is a number, then the child that number child (counted from 0) will be returned. If that index does not correspond to a gui, then null is returned g:clear

g -- g

Removes all the items from a combo gui g drop-down list g:clearpath

g -- g

Clear the path in the gui g, removing everything from it g:clr>n

clr -- n

Take a color descriptor clr and return a number n which is the ARGB value of the color. g:coleven

g -- g

Given a "table" gui g, set the widths of all columns so they are evenly distributed across the width g:colordlg

g clr w -- g

Choose a color via a callout. Pass it a word w to invoke when the user makes a choice, a color clr to set initially, and a gui g to point to (or null). The word w will get a stack of g clr -- whenever the user changes the color. g:colordlg returns immediately, e.g. the color chooser is asynchronous g:colwidth

g ix n -- g

Given a "table" gui g set the width of column ix to n pixels g:connectededges

g n -- g

Set which edges of the "btn" gui g might be connected to adjoining buttons. n is a number which is a combination of 1 - left, 2 - right, 4 top, 8 - bottom. Thus "10" means connected on the right and bottom. It is a hint to the GUI engine to not make the button edges round; depending on the "look and feel", it may be ignored g:contrasting

clr -- clr'

Given one color clr, return a color clr' which contrasts with it, e.g. which should be clearly visible against it g:curmouse?

-- o

Valid any time. Returns a map o, the same as g:mouse?, but may be used any time. May not work as expected in the console, since 8th does low-level keyboard manipulation g:default-font

s --

Set the default font for text to the one described in the given string s g:deselect-row

g n -- g

— 140 —

The 8th Manual: Words by namespace If the gui g is a "list", will deselect the given row if n is a number, or will deselect all rows if n is null g:destroy

g --

Destroy the gui g and release any resources it may have g:dismiss

g --

Given a gui g which is inside a g:callout invocation, dismiss the callout box g:do

x --

Takes a word or a string x and either invokes the word itself, or invokes eval on the string in the normal, non-GUI-thread, context g:draw-fitted-text

g s wide high -- g

Draw the text string s at the current position in the gui g, constrainted to fit in a rectangle wide by high pixels large. The constraint is the same as g:fit-text, except that if after adjusting for the width the height of the text would be bigger than high, it is shrunk g:draw-text

g s -- g

Draw the text string s at the current position in the gui g g:draw-text-at

g x y s -- g

Draw the text string s in the gui g at the specific position given by the numbers x and y g:each

g w -- g

Iterate the gui g and its children, invoking the word w for each gui encountered. The callback w is passed a stack of g --, that is it must consume the gui it is passed g:edit-on-double-click

g b -- g

If b is true, make double-clicking the "label" gui g turn it into an "edit". If false, a single-click will work g:editable

g n -- g

If n is true, then if the gui g is a "slider" one can enter values into the textbox, if a "toolbar" make its items able to be rearranged, and if a "combo" make the text-box in the combo-box editable g:empty-text

g s -- g

If the gui g is a "combo", sets the string s to display when there is no item currently selected. For a "propertypanel" sets a message to be displayed when there are no properties in the panel. For an "edit", set the text to show when it's empty g:enable

g b -- g

Enable or disable the gui g according to the value b g:enabled?

g -- g b

Return the enabled status b of the gui g g:fade

g n f -- g

Performs a 'fade-in' (if f is true) or 'fade-out' (if f is false) of the gui g over a period of n milliseconds g:fb-files

g -- a

Given a filebrowser gui g, get the files selected in it as an array a of strings g:fcolor

g x -- g

Set the gui g fill color to x, used when drawing shapes. See also g:scolor. For gui foreground and background colors, see g:fg and g:bg

— 141 —

The 8th Manual: Words by namespace g:fg

g s -- g

Set the foreground color of the gui g to s. See also g:bg. Not used for drawing shapes; for those use g:fcolor and g:scolor g:fg?

g -- g n

Returns the foreground color of the gui g as a number n. See also g:fg g:file-filter

g s -- g

Changes the filter for the "filebrowser" gui g, to the string s. For "all files", use "*", otherwise use a specific filter, like: "*.8th;*.cpp" etc g:file-name

g s -- g

Changes the name currently shown in the filename box at the "filebrowser" gui g to the string s g:filedlg

g o -

Display a file chooser callout, whose options are determined by the map o. Keys which may appear in it are: title - the text to put on the selection button; flags - the same flags allowed in a "filebrowser" gui map; filter - same as a "filebrowser" filter key; root likewise; and cb, which is a word to be invoked by pressing the button of the filedlg. That callback word gets passed the gui of the button and an array of strings which are the selected file names. You can use g:dismiss on the gui to dismiss the callout if you wish. It will be shown in using g:callout relative to the gui g g:fill

g -- g

Fill the path in the gui g, using g:fcolor g:fillall

g clr -- g

Fill the gui g with the given color clr g:fit-text

g f -- g

Change the gui g so that text drawn in it (the label, for example) is made to fit (or not), depending on whether f is true or false. The font will only be shrunk to fit, it will not be enlarged g:focus

g --

Puts the keyboard focus on the gui g g:fontdlg

g m -- g

Given a gui g to act as the "anchor point" and a map m containing options, presents a font chooser dialog. The option keys are: "cb" - a word to invoke when the OK button is pressed. It receives a string representing the name of the font, suitable for giving to font:new; "fontface" a string with the initial font-face to use in the dialog, and "fontsize", a number which represents the size of the font in pixels. The dialog is asynchronous g:forward

g -- g

For a "web" gui g, navigate forward to the next URL g:fullscreen

g f -- g

If f is true, make the "win" gui g full-screen g:get-lasso-items

g -- g a

Returns an array a of items that lie within the lassoed region of the gui g g:get-tab

g n -- g g2

Given a "tab" gui g, return the gui g2 for the tab with index n, or null if the index was out of range g:getclr

g -- g clr

Return the currently selected color clr from the "color" gui g (to set the gui's color you can use g:bg)

— 142 —

The 8th Manual: Words by namespace g:getfont

g -- g f

Returns a copy of the font f currently being used by the gui g. If you modify this value, the font being used will not be changed; for that you need to invoke g:setfont with the modified font g:getimage

g -- g img

Returns the img img used by the gui g g:getpath

g -- g X

Get the "path" from the gui g as an X X g:getroot

g -- g r

Returns the root item r in the "tree" gui g g:gradient

g x1 y1 x2 y2 rgba1 rgba2 -- g

Draw a linear gradient pattern on the gui g, from the starting point (x1,y1) to the ending point (x2,y2), and starting with the color rgba1 and ending with the color rgba2. The color designators are given just as for g:fg etc g:gui?

-- f

Returns true if GUI is available and false otherwise. This would return false if running on Linux without X-Windows running, for instance. Usually it is true g:handle

g -- g n

Return a number n which is the internal handle the gui g. Used internally, not generally useful g:headerheight

g n -- g

Sets the height of the header of a "table" gui g, to n pixels g:hide

g -- g

Make the gui g invisible g:image

x -- img

Load an img img from the item named x. This may be a PNG, GIF or JPEG image file. If the item is a string, it refers to a file name. If it is a buffer, it is the raw image data. If it is a img, it is another image, in which case a copy of that image is made g:image-at

g img x y -- g

Draw the img img at the specified coordinates (x,y) in g, which may be a gui, or another img g:invalidate

g -- g

Invalidate the gui item g so it redraws. Note: a redraw will not occur immediately, but at the next opportunity g:ix?

g -- g n

Returns the gui g's index n in its parent. That is, what number child of its parent is it? If the gui has no parent, then null is returned g:justify

g a -- g

Set the justification of the gui g to the values defined by the array a. See the manual for valid values for the "justify" property. g:l-text

g -- g

Set text alignment in the gui g to 'left-aligned'. Text will be drawn starting at the current position g:laf

g n -- g

Set the gui g's "look-and-feel" to n. See also g:laf? and g:laf!

— 143 —

The 8th Manual: Words by namespace g:laf!

n --

Set the default "look-and-feel" for all new gui elements to n. See also g:laf and g:laf? g:laf?

g -- g n

Returns a number n which is the index of the gui g's current "look-and-feel" (LAF). Built-in LAFs range from 1 to 3, and custom ones created by g:new-laf start at 4. The default value is 3. g:len

g -- g n

Returns the number n of children of the gui g. It is possible that some of the children are not guis, because the JUCE library may insert its own children independently g:line-width

g m -- g

Set line width for drawing on the gui g to m pixels g:lineto

g x y -- g

Draw a line on the gui g from the current position to (x,y) g:list+

g s -- g

Add a string item s to the "combo", "list" or "tree" gui g g:list-

g n -- g

Remove the item at index n from the "combo", "list" or "tree" gui g. An index of -1 removes all the items g:loadcontent

g s -- g

Sets the string s as the content of the "codeeditor" gui g g:loadtext

g s -- g

Load the string s as the content of the "html" gui g. The result will become visible after the contents have been retrieved g:loadurl

g url -- g

Load the contents of the URL string url into the "html" gui g. The result will become visible after the contents have been retrieved g:localize

m --

Adds the translations in the map m so that Juce uses them. Each key in the map is a base word to translate, and the value is the translated string. Use this if you need to change the text of displayed words in Juce GUI items (for example, the default right-click menu in edit controls) g:m!

g key value -- g

Insert the (key,value) pair in the gui g's internal map g:m@

g key -- g val

Retrieve the item val corresponding to the string key in the gui g's internal map (may return null) g:menuenabled

g b -- g

If b is true, enable "right-click-menu" for the "slider" or "edit" gui g g:mouse?

-- o

Only valid within a mouse-event callback. Returns a map o whose keys describe the current mouse event. The keys are: x, y - number coordinates of the event; the rest of the keys are true or false. "cmd" - the "command" key is down (Apple key on macOS, Ctrl otherwise), "pum" - "pop up menu key" (Ctrl or rclick on macOS, rclick otherwise), "left" - left button, "right" - right button, "mid" - middle button, "ctrl" - Ctrl key down, "alt" - Alt key down, "shift" - Shift key down. Returns null if used outside a mouse-event callback g:mousepos?

g -- g x y

— 144 —

The 8th Manual: Words by namespace Returns the current position (x,y) of the mouse, relative to the gui g's upper-left (0,0) position g:moveto

g x y -- g

Move the current drawing position to (x,y). If g is a gui or img, this also sets the text output position g:msgdlg

o --

Display an asynchronous modal message dialog with parameters from the map o. Keys: "type" - the icon (0=no icon, 1=question, 2=warning, 3=info); "title" - the title of the dialog; "msg" - the contents of the dialog; "cb" - a word which gets invoked when the user presses a button, and is passed the index of the button in the buttons array; "buttons" - an array of strings to show as buttons. Because the dialog is asynchronous, msgdlg returns immediately. Therefore you just provide a "cb" key in the map if you want to accept values from the dialog g:multi

g f -- g

If f is true, then if the gui g is a "text", allow multiple lines; if a "list" or "tree", allow multiple selection g:name

g -- g s

Returns the name s of the gui g, or null if no name was set g:new

m -- g

Take a map m describing a GUI layout, and create a gui g or null if unsuccessful. The gui represents the on-screen displayed GUI, while the map is its "backing-store", e.g. the data behind the gui g:new-laf

m -- index

Create a new "look-and-feel" corresponding to the user's settings in the map m. Any of the documented functions which are overwritten by the user will be used instead of the built-in laf ones. Returns a number index for the new laf, which can be used with g:laf etc, or null if there are too many lafs defined (the maximum is 7) g:next

g -- g

For a "stack" gui g, transition to the next page g:obj

g -- g obj

Returns the map obj which is the gui g's "backing store", or null if there is not one g:on

g f -- g

Set the toggled state of the gui g to f g:on?

g -- g f

Return the toggled state f of the gui g g:ontop

g f -- g

If f is true, make the gui g be "topmost", e.g. always on top (towards the front of the screen). Otherwise, disable that property so the item may move towards the back g:outlinethickness

g n -- g

Sets the thickness of a border that will be drawn around the "list" or "tab" gui g to n pixels. For a "label" or "edit" gui, changes the border that is left between the edge of the component and the text g:panel-size

g ix n -- g

Set the size of the panel of a "concertina" gui g at index ix to n pixels g:panel-size?

g ix -- g n

Get the size of the panel of a "concertina" gui g at index ix, as a number n of pixels g:parent

g -- g'

Returns the parent of g, or null

— 145 —

The 8th Manual: Words by namespace g:path

g -- g

Start a new path in the gui g g:pie

g x y r pct start stop -- g

Draw an pie-wedge on the gui g. The meaning of the parameters is the same as for g:arc, with the addition of pct which is the proportion of the circle which is left open (the hole in the doughnut) g:pix!

g x y -- g

Set the pixel at position (x,y) in the gui g to the current g:fcolor g:pop

g -- g

For a "stack" gui g, pop the last gui child from the stack g:popmenu

m --

Shows a popup menu as defined by the map m. The keys are "menu", which has the same format as for a "menubar"; and "cb", which is the name of a word to invoke when the menu has been selected or dismissed. If dismissed, the callback will be given null on TOS. Otherwise, it will be given the number defined for that item in the menu description. This word returns immediately, the callback is asynchronous g:pos?

g -- g left top

Returns the position of the gui g as (left, top), in pixels relative to the screen. See also g:xy? g:prev

g -- g

For a "stack" gui g, transition to the previous page g:progress-task

cancel task canceltitle title --

Execute the word task as a background task, running with a pop-up dialog having a progress-bar and a title. The progress-task gui itself will be passed as the only parameter to the task word, so it can update it as needed. When the word exits, the message box will go away. If cancel is not null, then a "Cancel" button will appear with the text canceltitle g:progress-task-msg

g s --

Set the message displayed in the progress-task gui g to the string s g:progress-task-pct

g n --

Set the percent done indicator of the progress-task gui g to the number n g:propval!

g name val-- g

Set the value of the "property" gui g's named value name to val g:propval@

g name -- g val

Returns the value val of the property named name from the "property" gui g g:push

g child -- g

For a "stack" gui g, push the gui child onto the end g:qbezier

g x1 y1 x2 y2 -- g

Draw a quadratic Bézier curve from the current position on the gui g, using (x1,y1) as the control point, and ending at (x2,y2) g:quit

--

Quit the main GUI thread and shut down g:r-text

g -- g

Set text alignment for the gui g to 'right-aligned'. Text will be drawn so the last character is at the current position

— 146 —

The 8th Manual: Words by namespace g:readonly

g f -- g

If f is true, set the "edit" or "codeeditor" gui g to be read-only g:rect

g x y wide high -- g

Add a rectangle at position (x,y) and of dimensions (wide,high) to the gui g g:refresh

g -- g

For a "web" gui g, refresh the loaded URL g:restore

g -- g

Restore the saved state of the gui g's context g:root

g -- g'

Returns the root of the gui g. That is the "parent of all parents" for this gui g:root-item-visible

g b -- g

If b is true, makes the "tree" gui g's root item visible g:rotate

g angle -- g

Rotate the gui g by angle degrees g:rowheight

g n -- g

Sets the height of each row in the "list" or "table" gui g to n pixels. The default height is 22 pixels g:rrect

g x y wide high radius -- g

Add a rounded rectangle to the gui g. The parameters are the same as for g:rectangle, except for radius which is the radius of the rounded corners in pixels g:save

g -- g

Save the current state of the gui g's context g:say

s --

Puts up a message box, using G:appname as the title and the string s as the message to display. The deferred word (say) will be invoked when the "OK" button is pressed g:scale

g x y -- g

Scale the gui g by (x,y). The x value is a horizontal scaling factor, y is a vertical scaling factor; both must be provided g:scolor

g x -- g

Set the gui g's stroke color to x, used when drawing shapes. See also g:fcolor. For gui foreground and background colors, see g:fg and g:bg g:scrollthickness

g n -- g

Changes the width of the scrollbar for the "codeeditor", "edit" or "view" gui g, to n pixels g:sectionenable

g ix b -- g

If b is true, enable the section at index ix for the "property" gui g g:select!

g n -- g

Set the selected index of the "combo" gui g to the number n, where "0" is the first item g:select@

g -- g n

— 147 —

The 8th Manual: Words by namespace Returns the currently selected index n of the "combo" gui g, where "0" is the first item g:selected-rows

g -- g a

If the gui g is a "list", returns an array a containing the index of each row which is selected. It will return null if there are no selected rows, or if the gui wasn't a list g:set-lasso

g b -- g

Determines whether to begin or end "lassoing" on the gui g according to the value b g:set-long-press

g msec pix -- g

Sets parameters for a "long-press" event for the gui g. The msec value is how many milliseconds the press must be down before it is considered a "long-press". Similarly, pix is the maximum number of pixels the press can move and still be a "long-press". The default is 200 msecs and 20 pixels g:set-popup-font

s --

Set the font for pop-up menus to the one described in the string s g:set-swipe

g msec pix -- g

Sets the parameters for a "swipe" event for the gui g. The msec value is how many milliseconds the press must be down before it is considered a "swipe". Similarly, pix is the maximum number of pixels the press can move and still be a "swipe". The default is 50 msecs and 40 pixels g:setcursor

g s -- g

Set the cursor shape for the gui g. The string s may be one of "none", "parent" (whatever the parent control uses), "normal" (arrow), "wait" (hourglass or spinning ball), "ibeam" (vertical I-beam), "crosshair" (pair of crosshairs), "copy" (normal with a "+" on it), "point" (hand w/ pointing finger), "drag" (open flat hand), "lr-resize" (arrow pointing left-right), "ud-resize" (arrow pointing up-down), "resize" (arrow pointing up, down, left, right), "top-resize", "bottom-resize", "left-resize", "right-resize", "topleft-resize", "topright-resize", "bottomleftresize", "bottomright-resize". These are the same values permitted in the "cursor" attribute in a gui item g:setfont

g x | g n b -- g

Set the font of the gui g to the one described in the item x. If x is a font, just set the font. If it's a string, create a font from it and sets it. If it's a buffer b, then a number n representing the desired font size must also be given. If x is a number, then the default font in that size will be used g:setheader

g s -- g

Adds a column to the "table" gui g, where the string s is the column name g:setimage

g img -- g

Set the image of the gui g to the img img, where g may be an "image", a "btn" or a "systemicon" g:setname

g s -- g

Set the name of the gui g to the string s g:setroot

g s -- g

Set the root item of the "tree" or "filebrowser" gui g. Changes the directory that's being shown in the listbox of the "filebrowser" to the string s g:settab

g n -- g

Given a "tab" gui g, set the active tab to the number n. The tabs are numbered left to right, from 0 g:show

g -- g

Make the gui g visible g:show-line-numbers

g f -- g

If f is true, enables line-number display for the "codeeditor" gui g

— 148 —

The 8th Manual: Words by namespace g:show-pct

g b -- g

If b is true, turns the percentage display on for the "progressbar" gui g g:showmenu

g n -- g

Shows menu number n from the gui g g:showtooltip

f --

If f is true, makes tooltips visible; otherwise, makes them invisible g:size

g wide high -- g

Sets the size of the gui g to (wide, high) pixels. If null is given for either parameter, that dimension won't change g:size?

g -- g wide high

Returns the size of the gui g, in pixels (wide, high) g:stackix

g n -- g

For a "stack" gui g, set the currently shown item to the one at index n g:state

g s -- g

For a "win" gui g, restore the current state from the string s, which was saved with g:state? g:state?

g -- g s

For a "win" gui g, return the current state as a string s, which may be restored with g:state g:stepsize

g n -- g

Sets the amount n (relative to the entire range of the scroll) by which the up and down buttons will move the bar of a "scroll" gui g g:stroke

g -- g

Stroke the path in the gui g, e.g. draw the outline using the g:scolor g:stroke-fill

g -- g

Stroke and fill the path in the gui g g:style

g s -- g

Changes interface of the "slider" gui g according to the string s. See the manual for details on slider styles g:tabname

g ix nm -- g

Given a "tab" gui g, set the name of the tab with the index ix to the string nm g:text

g s -- g

Set the text of the gui g to the string s. Exactly what is set depends on the gui type g:text-box-style

g h w ro pos -- g

Changes the location and properties of the text-entry box of the "slider" gui g. Parameters are h: the height, w: the width, ro if true means "read-only", and pos: the position - 0=none, 1=left, 2=right, 3=top, 4=bottom g:text?

g -- g s

Returns the text string s from the gui g. See also: g:text g:textcolor

g s -- g

Sets the text color s of the gui g

— 149 —

The 8th Manual: Words by namespace g:textsize

g s -- g wide high

Returns the dimensions (wide,high) of the string s in pixels, using the font currently selected in the gui g g:timer!

g n -- g

Set the period of a timer (assumes a "timer" callback has been declared) in the gui g. If the number n is 0, disables the timer. Otherwise, sets the timer to fire at (approximately) every n milliseconds g:timer@

g -- g n

Returns the current period of a timer in milliseconds n, for the gui g. If there is no timer, null is returned. A number of "0" means the timer is not running g:toggle-row

g n -- g

If the gui g is a "list", will toggle the selection state of the given row number n g:tooltip

g s -- g

Set the text of the pop-up tooltip text to the string s, when the mouse hovers over the gui component g g:transition

g duration sp1 sp2 -- g

For a "stack" gui g, make the transition for the gui last duration milliseconds, and have a speed at start of sp1 and at the end of sp2 g:translate

g x y -- g

Translate the origin of the gui g to (x,y) g:tree-open

g b -- g

If b is true, set the "tree" gui g's items open by default g:triangle

g x1 y1 x2 y2 x3 y3 -- g

Add a triangle to the current path in the gui g, denoted by the points (x1,y1), (x2,y2) and (x3,y3) g:updateitems

g a -- g

Update the "tree" gui g with the items in the array a g:url

g s -- g

For a "web" gui g, set the URL to the string s and navigate to it g:user

g x -- g

Cause the "user" event to be issued for the given gui. The item x is passed to the event handler, along with the gui. The stack effect for the "user" event generated is g x --. If you want to do this for the gui g as well as all its children, use g:user! instead g:user!

g x -- g

Same as g:user except it operates on the gui g and all its children as well. If you want to do this only for the gui t, use g:user instead g:vertical

g b -- g

If b is true, orient the "scroll" or "toolbar" gui g vertically. For an "edit" gui, show or hide the vertical scrollbar g:view

g s -- g

Take a "view" gui g and the string s as the name of an item to view inside it, and make that item the one actively viewed g:visible?

g -- g b

Return the visible status b of the gui g g:vpos!

g n -- g

— 150 —

The 8th Manual: Words by namespace Set the current vertical position of a "scroll" gui g. The number n passed in is a percentage from 0 to 1 (e.g. 0.5 is half-way down the list) g:vpos@

g -- g n

Get the current vertical position of a "scroll" gui g. The result is a number n whose value is from 0 to 1 representing the percentage of the rows (0.5 is half-way down the list) g:waitcursor

f --

If f is true, sets the cursor to the "wait" kind. If false, resets to the normal cursor g:winding

g n -- g

If n evaluates false, sets the gui g to use "zero winding" otherwise sets "non-zero winding". This affects how overlapping items are colored during a fill operation g:xy

g left top -- g

Sets the position of the gui g by moving its top, left corner to the position (left,top). If either left or top is null, that position parameter won't change. The values are relative to g's parent g:xy?

g -- g left top

Returns the position of the gui g as (left,top), in pixels relative to its parent See also g:pos?

Global G:!

x v --

Put the item x in the variable v. x may be from any namespace G:!const

x -- x

Tells 8th that the item x is not "constant". See const G:#!

--

immediate:Like \, but intended for use on Linux or macOS where this tells the system which interpreter to use. If you do use it this way, make sure to put a space after it so 8th recognizes it properly and ignores it G:##

n --

Set the precision, e.g. the number n of digits to the right of the decimal (for floating point; integers will be printed only to the left of the decimal). The default is 5. Setting it to 0 will print as many places as are necessary G:#>

n --

Make s:fmt format the next string, or a number print, in a field n wide, aligned to the right. n must be a positive number. The alignment is reset to the default (left) after the string is formatted G:#if

f --

Analogous to if but only in interpret mode, and only for "pre-processing". If parses the input stream for "#then", and then parses that for "#else". It then evaluates the #else or #then text depending on the value held in TOS G:'

-- w

immediate:Return the word w whose name is (taken from the input stream), and put it on TOS. Returns null if it cannot find the G:(

--

immediate:Begin compiling a new anonymous word. The ) word finishes the process (and if you forget it, you'll stay in compile mode forever...) G:(:)

s --

Begin defining the word named by the string s

— 151 —

The 8th Manual: Words by namespace G:(code)

-- used allocated

Return the number of bytes of code space used as well as the total amount allocated G:(getc)

-- n

Returns one character as a number n from stdin or the console. Reads as an ASCII character from stdin, or a Unicode character from the console G:(gets)

-- s

Read a string s from stdin or the console G:(interp)

-- x

Start the normal interpreter, e.g. the "REPL loop" G:(putc)

n --

Print the (Unicode character) number n to stdout G:(puts)

s --

Print the string s to stdout G:(putslim)

s n -- n

Print up to n characters of the string s to stdout. If n is smaller than s:len, will print three dots (...) at the end of the printed characters G:(say)

--

deferred: invoked from g:say when the user pressed the OK button G:(stat)

n -- a|null

For the ns n, return an array a containing in order, 1) the maximum number of items per pool, 2) the total in use, 3) the number of pools allocated, 4) the number of words in the namespace, 5) the namespace short name, 6) the namespace long name. If an invalid namespace number is given, returns null G:)

-- w

immediate:End compilation of a new anonymous word w, and leave it on TOS. If you did not start such a word using (, an exception will be thrown G:+ref

a -- a

Increase the "reference-count" of the item a. Usually you should not need to use this G:,#

n --

Sets the thousands separator for printing numbers to the ASCII character given by the number n. If zero, no separator will be used (the default) G:--

--

immediate:Same as \, this is a SQL-style comment G:-Inf

-- -Inf

Put the value -Inf on TOS, "negative infinity" G:-Inf?

o -- o f

Return f which is true if the item o is -Inf, or false otherwise G:-ref

a -- a

Decrease the "reference-count" of the item a. Usually you should not need to use this

— 152 —

The 8th Manual: Words by namespace G:-rot

a b c -- c a b

Move the item in TOS to the third position on the stack G:.

x --

Print the item x G:.#

n --

Sets the decimal separator for printing numbers to the ASCII character given by the number n; if zero, a period will be used (the default) G:.needs

--

Prints the names of all libraries loaded by the needs word, one per line G:.r

--

Print the top 10 items in the "r-stack", in the same manner as .s does for the data stack G:.s

--

Display the top ten items on the data stack. The display shows the index on the stack, the namespace name, the address of the item, its reference-count and finally its value. If there is nothing on the stack, will print "Stack empty". If the item is currently locked (see lock), an asterisk ("*") will appear after the stack index and before the namespace name. If the item is constant, an exclamation point ("!") will appear before the namespace name G:.stats

--

Display system statistics. The first line shows how much code space has been used vs. how much is allocated (in bytes). Then, for each namespace it shows its name followed by how many words are currently defined in it, how many data items of that type are in use, how large the pool is for that namespace and finally, how many pools have been allocated. G:.ver

--

Print the version of 8th, including build number, OS and bit-size, and customer id G:.with

--

Displays the current "with list". See also G:with: G:0;

x --

If x is the number 0, drop it and exit the word; otherwise, continue execution. Used within a word instead of the phrase "dup 0 n:= if drop ;; then" G:1,

n --

Inserts the byte value of the number n (that is, just n modulo 0xFF) at the current value of here. This may be used for writing an assembler for example G:2drop

a b c d -- a b

Drop the two top items from the stack G:2dup

a b -- a b a b

Duplicate the two top items on the stack G:2over

a b c d -- a b c d a b

Copy items in positions 3 and 4 to TOS G:2swap

a b c d -- c d a b

Like swap but for the two sets of two items on TOS G:4,

n --

Same as 1, but takes the four bytes value of n (n modulo 0xFFFFFFFF)

— 153 —

The 8th Manual: Words by namespace G:8thver?

-- s

Return a readable string of the 8th version G::

--

immediate:Begin defining the word named by , which is taken from the input stream. May only be used in interpret mode, and may not be used inside another word definition (e.g. nested words are not allowed) G:;

--

immediate:Terminate a : definition. May only be used in compile mode. Must be used after an initial : G:;;

--

immediate:Exit the current word immediately G:;;;

--

immediate:Immediately exit the word which invoked this one (as opposed to ;;, which exits the current word immediately) G:;with

--

immediate:Drops the last with: ns from the with list. See also G:with: G:clip

x --

Take an item x and put it on the system clipboard. The item's string representation will be put on the clipboard G:>json

x -- s

Take an item x and convert it to a string s which is its JSON representation. An equivalent item may be retrieved by giving the resultant JSON to json>. Note that this does not work with all namespaces, it only works with JSON standard types of number, boolean, string, array and map as well as null G:>kind

o -- n

Returns a number n which is the namespace identifier of the item o. Each ns's identifying number is obtained by using its name in the ns: namespace. For example, the identifier of strings is ns:s G:>n

s -- n

Convert the string s to the number n, obeying the current numeric base. If a number is passed, it is simply returned. If neither a string nor a number is passed, or the string cannot be converted to a number in the current base, will return null G:>r

x -- (r: x)

Pop the value x and push it onto the "r-stack" G:>s

x -- s

Convert the item x to its string representation s. If x is already a string, returns it as-is G:???

ofs s -- f

deferred: Last gasp: the interpreter doesn't know what to do with the string s at offset ofs in the input. Return f, which if true means you handled s somehow. Return false if you didn't handle it. The default behavior throws an exception G:@

v -- o

Returns the contents o of the var v. The var may contain an item from any namespace

— 154 —

The 8th Manual: Words by namespace G:Inf

-- Inf

Put the value Inf on TOS, "positive infinity" G:Inf?

o -- o t

Return true if the item o is Inf, or false otherwise G:NaN

-- NaN

Put the value NaN on TOS. This is generally the result of dividing zero by zero, for example. Any numeric operation on NaN propagates, so e.g. NaN 0 + gives NaN G:NaN?

o -- o t

Return true if the item o is the same as NaN, or false otherwise G:\

--

immediate:Comment to end-of-line: everything after the "\" is ignored. Remember that a space must follow the "\" ! In other words, if you put an empty comment at the end of a line, the *next* line will be dropped, which is not what you probably want G:`

` --

immediate:Evaluates the text read from the input stream until the next back-tick ("`"). May be used inside a word-definition to evaluate something only known at that time G:actor:

x w --

immediate:Similar to a var, but an "actor" takes an item x as its value, and a word w to invoke. As with var, the is taken from the input stream and is the name by which the actor is invoked G:again

--

immediate:Unconditional return to repeat. May only be used in compile-mode, throws an exception otherwise. Also throws an exception if you forgot to start a repeat. May be stopped with ;; (which immediately exits the word), or break (which causes the loop to not repeat) G:and

x y -- x AND y

boolean "AND" of x and y G:appname

-- v

A var v which contains the name of the current application. The default value is "8th", so you probably want to change it, e.g. "myappname" appname ! G:apropos

--

Looks for any text whose description or name contains (taken from the input stream) and prints out the documentation for it to the console. The match is not case-sensitive G:argc

-- n

Returns the number n of command-line arguments to the running program. Always 0 on mobile G:args

n -- s

Returns the command-line argument number n to the running program, as a string s. Numbering starts at 0, and accesses items on the command-line which were not treated as options. Note: On macOS and Linux, a 'backslash' on the command line is ignored unless the argument is enclosed in quotes. Forgetting that may lead to unexpected consequences G:array?

x -- x f

Returns f which is true if x is an array, false otherwise G:assert

x --

Assert that the value x in TOS is "true", quit with a message if it is not. If the value is a string, it is evaluated using eval and then TOS is checked

— 155 —

The 8th Manual: Words by namespace G:base

n -- oldbase

Set the numeric base to the number n and return the previously used base oldbase G:bits

-- n

Return a number n, which is either 32 or 64, the "bit-size" of the current build of 8th G:break

--

Causes the while, again, times, loop or loop- iterators to stop when the word containing break returns. It does not stop the iteration immediately, but rather prevents the next iteration. Also causes o:each and a:each and a few other iterators to stop. Besides these, it will terminate the interpretation of a file at the point it is encountered G:break?

-- f

Returns true if break was invoked G:build?

-- s

Return a readable string s of the OS/bits G:buildver?

-- s

Return a readable string s of the 8th build version G:bye

--

Quit 8th G:c#

n --

Set the "filler" character whose ASCII value is the number n, to be used for padding aligned fields in strings. The default is a space, character 32 G:c/does

x dw cw --

Similar to ANS Forth "CREATE... DOES>". Takes an item x which is the default value, a word dw which is the "run-time" behavior, a word cw which is the "create-time" behavior and a string which is read from the input stream. It creates a new word called , which is itself used to create new words. Those new words it creates will invoke the cw word when they are created, and the dw word when they are run. In the case of dw, it is passed a clone of the item x. In the caes of cw, it is passed an array which contains the item x as well as the dw word. Thus, the cw word may modify the value or the action taken at run-time G:case

key table --

Similar to caseof, but takes a number or string key, and an array or map table. The table consists of key,value pairs where the value is a word. If key exists in table, its value is invoked. If not, nothing happens. See also caseof G:caseof

x y -- item|null

Take either an array x and number y, or a map x and string y. Looks for the index or key y in x. If the item found is a word, invoke it and leave the result of the invoked word on TOS; otherwise, put item itself on TOS. If no such item was found, put null on TOS. See also case G:chdir

s --

Change the current directory to s G:clip>

-- s

Returns the current contents of the system clipboard as a string s G:clone

x1 -- x1 x2

Create a clone x2 of the item x1. Like dup, a "clone" has the same value as the original. However, modifying it does not change the value of the original item x. If x1 is a container type, all the contained items are also cloned. See also same? and dup and clone-shallow. The only item types which cannot be cloned are "db", "sql", "hw", and "X" G:clone-shallow

x1 -- x1 x2

The same as clone, except that if x1 is a container type then the items contained are not cloned

— 156 —

The 8th Manual: Words by namespace G:cold

--

The default system startup, begins the interpreter loop G:compile

w --

immediate:Compiles an invocation of the word w (which is on TOS) into the word currently being compiled. So when that word is subsequently invoked, the word w will be invoked at that point G:compile?

w --

immediate:Same as compile, except it only compiles if 8th is in compile mode; otherwise, it invokes the word w G:conflict

s -- f

deferred: Determine how 8th responds if a new word or other named item already exists in the current namespace. It is passed the name of the conflicting item (s), and returns true to permit it to be created, or false to disallow it. The default 8th behavior is to permit overwriting of existing items, but to warn that it is occurring G:const

x -- x

Tells 8th that the item x is "constant", and cannot be modified. An attempt to modify a const item will silently create a clone on which the modification is performed. Any item declared inside a word is const by default, so that its value will remain the same on repeated invocations of the word. If it is desired that the item change value in such a case, you must use !const to permit it to be changed G:const?

x -- x f

Reports true if the item x is "const", false otherwise G:cr

--

Print an OS-specific 'newline' character G:curlang

-- v

A var v containing a string which determines the current language for use by s:intl etc. The default value is "en", for English. It should be set by the appropriate "lang/xx" asset G:decimal

--

Set the numeric base to 10 G:defer:

--

Create a deferred word (taken from the input stream). This new word initially does nothing; assign it an action using w:is G:deg>rad

deg -- rad

Convert the number deg from degrees to radians rad G:depth

-- n

Current depth of the stack, e.g. the number n of items it contains (before pushing the depth to TOS) G:die

n --

Stop 8th immediately, with n as the program's return code G:drop

a b -- a

Drop the item on TOS. One less reference to the item will be held G:dstack

-- st

Returns a st st item which references the "data-stack", similar to rstack G:dump

x --

Do a hex-dump of the contents of the item x

— 157 —

The 8th Manual: Words by namespace G:dup

a -- a a

Duplicate the item a on TOS. This makes an additional reference to the item on TOS, not a separate copy. If you wish to make a separate copy, use clone. See also: dup? clone G:dup?

a -- a a

Duplicate the item on TOS if and only if it is not null. Thus if TOS is null, it remains null; otherwise, it is duplicated. See also: dup G:else

--

immediate:Begin alternate branch of a conditional begun with if. May only be used in compile-mode, throws an exception otherwise. Also throws an exception if there was no accompanying if G:eval

s --

Interpret string (or buffer) s as if it were typed into the interpreter. If s is null, it will silently ignore it G:eval!

s -- f

Same as eval, but will not throw exceptions if the string s would cause them to be thrown. Instead, returns a true if no exceptions would have been thrown, false otherwise G:execnull

x w --

If x is null, then invoke the word w and continue; otherwise just continue. The word w should take care of whatever reason a null was on TOS, and should leave a value in place of x on TOS. If x was not null, then w is dropped and execution continues as if it weren't there G:expect

a x -- a flag

Tests the >kind of a against the number or array of numbers x. If a is not one of the listed types, puts false on TOS otherwise, puts true on TOS. In either case, the original item a is left under TOS G:false

-- t

Returns the value false on TOS G:fnv

s -- n

Takes a string s and returns its FNV1a hash as the number n G:func:

p s

Create a word called (taken from the input stream), which will invoke the external function s from the external library last invoked when creating the func. At runtime, the parameter string p will be used to convert 8th types to native and vice-versa. The parameter string contains the return value as the first character, followed by one character for each parameter to the function, with a maximum of 12 parameters total. Please view the manual's chapter on FFI for a complete description of the parameters G:getc

-- n

deferred: Read one character from the input (standard input or console) and return as a number n G:getcwd

-- s

Returns the current working directory as a string s G:getenv

s -- val

Returns the value of the environment variable s as a string val G:gets

-- s

deferred: Read from standard input or the console, up to a newline and return a string s G:handler

x -- f

deferred: Handle an exception, gets item x which describes the exception (usually a string, but you can throw any item type); return true to continue or false to quit. The default is to quit

— 158 —

The 8th Manual: Words by namespace G:header

nm --

Creates a new dictionary entry named nm whose code is left unfilled, and does not change to compile mode G:help

--

Looks for any word whose name is (read from the input stream) and prints out the documentation for it to the console. The name matching is case-sensitive G:here

-- n

Returns the value of "here" -- the current location where code is compiled -- as a number n G:hex

--

Set the numeric base to 16 G:i:

--

immediate:Make sure the next word is run immediately rather than compiled in. Has not effect if the word is an 'immediate' one. See also i; and p: G:i;

--

immediate:Mark the word being compiled as an immediate one, e.g. one which is immediately invoked rather than compiled, and terminate the word's compilation just as ; does. Must be paired with : G:if

--

immediate:Begin a conditional. At runtime, examines (and consumes) TOS and if it is true or non-zero, the code after the if is run. Otherwise, the code after the else or then is run. May only be used in compile-mode, throws an exception otherwise. Must be accompanied by then G:if;

x --

If x evaluates true , exit the current word; otherwise, continue execution. Used within a word instead of the phrase if ;; then G:invalid-throw

f --

If f evaluates to true, makes attempting to display an INVALID item (e.g. one with a reference count of 0) throw an exception, to aid debugging. By default, no exception is thrown G:isa?

x n -- x f

Returns f which is true if x is an item from the namespace identifier given by the number n, false otherwise. So to test if TOS contains a gui for example, you could use: ns:g isa? G:jcall

x a -- y

ANDROID ONLY. Takes an X returned from jmethod, and an array a of parameters to pass to the method. Makes the function call with the given parameters, and returns y, the type of data specified in the parameters list of the jmethod G:jclass

s -- x

ANDROID ONLY. Takes a string s containing the fully qualified name of a Java class (such as "java.lang.Thread") and returns an X x, which may be passed to jmethod to create a method by which one may call that method using jcall G:jmethod

cls name params -- y

ANDROID ONLY. Takes a string containing the name name of a Java method in a Java class cls previously returned from jclass. The params string follows the JNI specification and must match the signature of the Java method exactly. The returned X item y can then be passed to jcall. Please refer to the manual for a complete description of how this is used G:json-pretty

n --

Tell the >json and other JSON output words to pretty-print JSON so it is easier for humans to read. A value of 0 means don't pretty-print; any other value is the number n of spaces to indent each nested level. Legal values are between 0 and 16 G:json>

s -- x

— 159 —

The 8th Manual: Words by namespace Take a JSON string (or buffer) s on TOS and convert it to an equivalent of the original item given to >json, x. null on TOS will result in null. Note: 8th-specific enhancements to JSON are not permitted for security reasons, and will appear as null in the final item returned. If you have trusted JSON with 8th enhancements which you want to restore, use eval instead. Be aware that using eval may pose a security risk if the string it is given is not from a trusted source G:k32

-- n

Windows only: A word which returns a number n whihc is the lib handle of the "kernel32" system library G:l:

--

immediate:Compile the string (from the input stream) into the current word. At runtime, look up the word with that name. This lookup will happen every time the word containing l: is run, so while it is very flexible, it is also slow G:last

-- w

Return the last word compiled G:lib

s --

Create a word named (read from the input stream), which will load the external library s when invoked. At runtime, invoking the created word will have the stack effect -- n where n is the number representing the loaded library's handle, or 0 if it was unable to load it. The library name s may be a complete name which is OS specific, such as "libiconv.so" or "iconv.dll". If just the base name is given, e.g. "iconv", then 8th will try to load "iconv", then "iconv.dll" (or .so or .dylib, depending on OS) and then "libiconv.dll" (etc). This makes writing cross platform library routines much easier, assuming the dynamic library has the same base name across platforms. That is, "iconv.dll", "libiconv.so" and "libiconv.dylib" in this example G:libc

-- n

Linux, RPI and macOS: Returns a number n, which is the lib handle of the "libc" system library G:literal

x --

immediate:Compiles the item x (which is on TOS) into the word currently being compiled. So when that word is subsequently invoked, the item x will be put on TOS G:lock

x -- x

Acquire a lock on the item x. That means it will execute a tight loop until it can lock the item. If the item is already locked, it will "spin" forever until it acquires the lock. Locks are "advisory", meaning that they do not prevent other tasks accessing the item unless they cooperate and also use the locking facilities. See also: lock-to, locked?, unlock G:lock-to

x n -- x f

Same as G:lock, but takes a timeout value as a whole number n of milliseconds. If that many msec pass without being able to acquire the lock, it returns false; otherwise it acquires the lock and returns true G:locked?

x -- x f

Queries the lock state of the item x, returning true if it is currently locked or false otherwise G:log

x --

Write the item x to the 8th log (console), converting to a string if necessary G:long-days

-- v

A var v which contains a map, which maps language names (e.g. "en") to an array of long names of the week-days. The default contains the English names of the week-days. It should be set by the appropriate "lang/xx" asset G:long-months

-- v

A var v which contains a map, which maps language names (e.g. "en") to an array of long names of the months. The default contains the English names of the months. It should be set by the appropriate "lang/xx" asset G:loop

w low hi --

Invoke the word w, high - low + 1" times, counting up from low to high, inclusive. Pushes the current iteration number on TOS, so w must consume it. If low is greater than high, loop will not iterate. See also loop-

— 160 —

The 8th Manual: Words by namespace G:loop-

w low high --

Same as loop, but in the reverse direction, e.g. from high to low G:map?

x -- x f

Returns f which is true if x is a map, false otherwise G:mark

--

Makes it possible to return to the state the system was in as of this 'mark', using release G:mobile?

-- f

Return true if running a mobile platform, false otherwise G:n#

n --

Set the accuracy, e.g. the number n of significant digits kept after certain big floating-point calculations. It affects, n:sqrt, n:exp, n:ln, n:sin, n:cos, n:tan, n:asin, n:acos, n:atan, n:atan2, n:^. Defaults to 32 G:name>sem

name -- x

Given a string name, return the opaque X representing the semaphore of that name created by G:sem, or null if it doesn't exist G:needs

--

Parses the white-space-delimited string from the input stream (reading until the end of the line), and includes that library and evaluates it. First it looks in the "libs" asset. If it does not find the library there, it will search in the app:datadir, then in the directory pointed to by the "EIGHTHLIB" environment variable and then app:8thdir. NOTE: In all cases, the library must reside relative to a 'libs' directory. That is, if EIGHTHLIB points to "~/mylibs", then "needs joe" will load "~/mylibs/libs/joe", if it exists (and wasn't found by a prior search). NOTE: Throws an exception if it cannot load the library. Unlike f:include, it will only include the needed library once. See also f:include, app:asset, .needs and f:slurp. NOTE: Because needs parses to end-of-line, you cannot have a comment begin on the same line after the file name G:new

n -- x

Create a new item x with the ns identifier n, which may be obtained by invoking the ns name (for example, ns:n for a number). If n is not a valid identifier (that is, less than 0 or greater than the largest namespace identifier), then null is returned G:nip

a b -- b

Drop the item under TOS G:noop

--

Literally, do nothing G:not

t -- t

Convert true to false and vice versa. Interprets numbers which are non-zero as true for the purpose of this conversion G:ns

n --

Take a namespace identified by the number or string n and make it the current one. Initially, the G (global) namespace is default, so new words are created there unless changed. See also G:ns: G:ns:

--

Use the namespace named (taken from the input stream) as the current "namespace". A namespace is the vocabulary where new words will be put (the default namespace is G) G:ns>ls

n -- s

Convert the number n which is a namespace identifier to its long string representation. See also ns>s G:ns>s

n -- s

Convert the number or namespace n, which is a namespace identifier, to its short string representation. That is, it will convert the number given by ns:n to the string n, or return null if it does not correspond to a known namespace

— 161 —

The 8th Manual: Words by namespace G:ns?

-- s

Return the name of the current active namespace as a string s G:null

-- null

Put the value null on TOS. This is an item whose value is indeterminate. It is often returned from words as a way of indicating there is no valid value to return G:null;

x -- x|exit

If x is null, drop and exit the word; otherwise, continue execution. Used within a word instead of the phrase "null? if drop ;; then" G:null?

x -- x t

Return true if the item x is null, or false otherwise. Note the change from prior versions! Now the original item remains on the stack G:number?

x -- x f

Returns f which is true if x is a number, false otherwise G:onexit

w --

Adds the word w to the list of words to be executed, in reverse order, upon program termination G:only

n --

Makes the ns designated by the number n the only namespace in which the interpreter will look for words. This should be used inside an application where you wish to give user access to eval under controlled conditions. If null is passed for n, then all namespaces are available again (that is, the "only" is cancelled) G:or

x y -- x OR y

boolean "OR" of x and y G:os

-- n

Return a number n indicating the operating system. 0 for Linux, 1 for Windows, 2 for macOS, 3 for Android, 4 for iOS, 5 for Raspberry Pi G:os>name

osnum -- name

Return a string name corresponding to the number osnum indicating the operating system as returned from os. Values of osnum which are outside of the legal range will return null. Uses the internal var os-names, which contains an array of OS names G:over

a b -- a b a

Duplicate the item underneath TOS and make it TOS G:p:

--

immediate:Make sure the next word is compiled in, rather than run immediately. Has no effect unless the word is an 'immediate' one. See also i: G:pack

a s -- b

Takes the items in the array a and "packs" them according to the format string s, returning a buffer b with the binary representation of the packed array items. The format string may have any of: [0-9]* (repeat count), c=character (string), b=byte (as buffer), B=byte (as one-byte number), h= hex bytes (reverse hex dump), w=2 byte integer, W=big-endian w, i=4 byte integer, I=BE i, l=8 byte integer, L=BE l, f=float, d=double, x=ignore byte, p= pointer (to buffer or string data), s=count byte(etc). A '*' means use the full length of the buffer or string. A ':' if present separates the "repeat count" from the "number of bytes" count. For example: "3:2c" means repeat three times, a string of two bytes. Inverse of unpack G:parse

x -- s

Parse a string from the input stream. If x is a number, then parse until the character whose value is 'x' is reached (ASCII only). If x is a string, parse until that string is matched. The matched item is excluded from the resultant string s which is put on TOS G:parsech

-- s

Parse the next non-whitespace character from the input stream into a string s of one character.

— 162 —

The 8th Manual: Words by namespace G:parseln

-- s

Parse a string from the input stream until the end of the line and put the resultant string s on TOS G:parsews

-- s

Parse a string from the input stream until the next whitespace, and put the resultant string s on TOS G:pick

n -- a

Duplicates the item a at position n in the stack, putting it on TOS. TOS is 0, item under is 1, etc. If you try to pick beyond the limits of the stack, it will throw an exception G:pool-size

id size --

Given the namespace id of a pool (e.g. "ns:n") and a desired size (in number of items), changes the allocated pool size for that namespace. Similar to the command-line option "-p", but from within a program. Note that this should be done at the beginning of a program in order to make it most effective, and that it only has an effect if the value given is greater than the default value G:prior

w -- w2|null

If a word w with the same name as an existing word was created in the same ns, then return the prior version of that word w2, which would otherwise be inaccessible by name. If there is no prior word it returns null G:prompt

s -- s2

deferred: word which returns the "ok> " prompt. It is passed the string s, which contains spaces or one of the following: '"', '{', '[', or '+' to indicate which of those items is currently 'open'. The string s2 is the prompt which will be displayed G:putc

n --

deferred: Print the character n, which is a number representing the Unicode character to print G:puts

s --

deferred: Print the string s G:putslim

s n --

deferred: Print up to n characters of the string s. If n is smaller than s s:len, prints three dots (...) at the end of the printed characters G:quote

-- s

immediate:Examines the next character from the input stream, and parses the rest of the input stream up to the next instance of that character, and returns a string s. This is useful if you have embedded double-quotes, for instance. Note: the standard 8th "string-escapes" (for example "\n") are not processed in a "quote" string G:r>

(r: x) -- x (r: )

Pop the value from the "r-stack" and push it to TOS G:r@

(r: x) -- x (r: x)

Return the value from the "r-stack" without removing it, and push it to TOS G:rad>deg

rad -- deg

Convert the number rad from radians to degrees deg G:rand

-- n

Generate a 64-bit pseudo-random number n using the "Fortuna" generator. Slower than rand-pcg but presumably more secure G:rand-pcg

-- n

Generate a 64-bit pseudo-random number n using a PCG generator. This is much faster than rand, but is not cryptographically random

— 163 —

The 8th Manual: Words by namespace G:rand-pcg-seed

n m --

Set the 'seed' for the PCG to the given numbers n and m. Using null instead of two numbers will make the PCG choose a random seed using rand G:randbuf

n -- b

Generate a buffer b of size n filled with pseudo-random bytes from the cryptographically strong random source G:randbuf-pcg

n -- b

Generate a buffer b of size n filled with pseudo-random bytes from the PCG random generator G:rdrop

(r: x) -- (r: )

Drop the TOS of the "r-stack". Same effect as G:drop but for the "r-stack" G:recurse

--

immediate:Invoke the last word created (even if anonymous) G:ref@

x -- x n

Returns the "reference-count" n of the item x. This is what's shown when invoking .s G:reg!

key value -- f

Windows only: set the value of a Windows Registry string key. The value may be a string, a number or a buffer. Returns true if succeeded, false otherwise G:reg@

key -- value

Windows only: get the value of a Windows Registry string key. Returns null if the value does not exist G:regbin@

key -- val kind

Windows only: get the value of a Windows Registry string key, as a buffer val with whatever data are in the key, and a number kind which indicates the kind of item (the value for kind is the same as the Windows RegQueryValueEx() returns). Returns null if the value does not exist G:release

--

Restores the 8th system to the state the it was in as of the last 'mark'. Any items created will be released, including data and code items. The data and r-stacks will be reset G:repeat

--

immediate:Begin a repeated block of code terminated with either again or while. May only be used in compile-mode, throws an exception otherwise G:reset

--

Remove all items from the data stack G:roll

n -- a

Moves the item a at position n in the stack to the TOS, and move all other items down the stack - in effect, rotating the items. TOS is 0, item under is 1, etc. If you try to roll beyond the limits of the stack, it will throw an exception. "2 roll" has the same effect as G:rot. If n is negative, roll takes the TOS and puts it at position n, moving items up the stack. So "-2 roll" is the same as G:-rot G:rot

a b c -- b c a

Move the item in the third position to TOS G:rpick

n (r: a...) -- a (r: a...)

Returns the item a at position n in the "r-stack". TOS is 0, item under is 1, etc., same as G:pick, but for the "r-stack" G:rroll

n -- a

Same as G:roll but for the r-stack

— 164 —

The 8th Manual: Words by namespace G:rstack

-- st

Returns a st item st which references the "r-stack". This permits you to operate on the r-stack with all the stack words G:rswap

(r: x y) -- (r: y x)

Swap the top items on the "r-stack". Same as G:swap, but for the "r-stack" G:rusage

-- o

Returns a map o containing the values of various resources used by the running program. For example, the "rss" key is the maximum resident set size, e.g. the maximum amount of memory this program required at once G:same?

x y -- f

Given two items x and y, returns true if they are precisely the same item (not just having the same value), or false if they are not. Note: an item and its clone are not the same! G:scriptdir

-- s

Returns a string s, which is the directory from which the script is running G:scriptfile

-- a

Returns an array a containing the full path name of the script being run as well as scripts leading up to it (e.g. via f:include or needs). It is empty if no script is run. Index -1 is the currently running script G:sem

name init -- x

Returns an interprocess semaphore of type X, with the given string name and the initial count of init. Returns null if it cannot create or open the semaphore G:sem-post

x --

Given an X containing the result from G:sem, increment its count so another process using G:wait can continue G:sem-wait

x --

Given an X containing the result from G:sem, wait until its count becomes non-zero, then continue G:sem-wait?

x -- f

Given an X containing the result from G:sem, return true if G:sem-wait would succeed, false if it would block G:sem>name

x -- x name

Given an opaque X representing a semaphore created with G:sem, return the string name used when creating it, or null if it doesn't exist G:set-wipe

x -- x

Given a string or a buffer x, sets its internal "wipe" flag. That ensures that when the item's refcnt has gone to zero, the data it holds is wiped before being released. This means the user does not have to manually use clear G:setenv

k v --

Set the value of the environment variable k to the string value v G:sh

s w --

Execute the external command string s, invoking the word w when the process has finished. If w is null, the app will not be informed when the command finishes. Execution is asynchronous G:sh$

s w --

Same as sh, except that the callback word w is given the string result from the shell invocation G:short-days

-- v

A var v containing a map, which maps language names (e.g. "en") to an array of short names of the week-days. The default contains the English names of the week-days. It should be set by the appropriate "lang/xx" asset

— 165 —

The 8th Manual: Words by namespace G:short-months

-- v

A var v containing a map, which maps language names (e.g. "en") to an array of short names of the months. The default contains the English names of the months. It should be set by the appropriate "lang/xx" asset G:sleep

n --

Sleeps for the number of seconds in the number n, which does not have to be an integer. Fractional seconds will be broken into milliseconds. A negative number means 'wait forever'. So "1.5 sleep" will sleep for approximately 1500 milliseconds G:space

--

Print a space character G:stack-check

f --

Determines whether or not type and bounds-checking are performed on stack operations. The default is true, and should only be changed once you have completely debugged your application. The '-x' command-line option also turns off the stack-checking G:stack-size

size --

Sets the main data-stack size to the given number size. This is useful if you will need more than 512 items on the stack (but if you do need more than 512 items on the stack, you should probably reconsider your code!). It will not affect the data-stack size for callback words. The stack size for tasks is set using t:def-stack G:stat

n -- x y|null

For the ns n, return the maximum number of items x and the total in use y. If an invalid namespace identifying number is given, returns null G:step

n --

Increment the current loop counter by n, which may be positive or negative. Works with loop and loop-, but not with times. Quits if the index is beyond the original loop limits G:string?

x -- x f

Returns f which is true if x is a string, false otherwise G:swap

a b -- b a

Exchange TOS with the item underneath it G:syslang

-- s

Returns the language of the user's locale as reported by the OS, as a string s. The return value should be a 2 or 3 letter language code (ISO 639-1 or ISO 639-2) G:sysregion

-- s

Returns the region of the user's locale as reported by the OS, as a string s. The return value should be a 2 letter country code (ISO 3166-1 alpha-2) G:tab-hook

s -- s2 f

deferred: This is the word responsible for console tab-completion. It receives a string s which is the text entered in the console before the TAB key was pressed. It should return a completed string s2 (which may be the same as the original) and a flag f which is true if the replacement should be used instead of the original, or false if the replacement should be ignored. The default completes the word immediately before the TAB was pressed. If there is more than one match, it will display a list of possible matches G:tell-conflict

-- v Returns a var v, which controls whether or not 8th will complain when overwriting an existing word. It is true by default G:tempdir

-- dir

Returns a string dir, which is the directory where temporary files will be created G:tempfilename

-- fname

Create a filename string fname suitable for a temporary file, in the directory G:tempdir

— 166 —

The 8th Manual: Words by namespace G:then

--

immediate:End a conditional begun with if. May only be used in compile-mode, throws an exception otherwise. Also throws an exception if there was no accompanying if G:throw

a --

Throw an exception. Quits the current word and passes a to handler. The item a may be any type: if it is a string it will be displayed as-is; otherwise, it will be converted to a string for display. If you throw a number, its value must be greater or equal to 1000. The default behavior prints a message and quits the application, unless 8th is running from the console rather than a file or application G:thrownull

x y --

If x is null, then throw the item y. Otherwise, continue (with x on TOS). This should be used when a null result is a fatal error G:times

w n --

Invoke the word w, n times. If n is zero or negative, then w will not be invoked G:true

-- t

Returns the value true on TOS G:tuck

a b -- b a b

"Tuck" the item on TOS under the item under TOS G:type-check

f --

If f evaluates to false, prevents 8th from checking data types in the built-in words. This will increase performance but also increase risk of unexpected failures. The default is true, meaning items are type-checked by builtin words G:unlock

x -- x

Release the lock on the item x. Note that any task can lock or unlock any item! That means that the locking model is cooperative, and you are responsible to make sure the task which locks is the same one which unlocks (or conversely, that another task doesn't unlock before testing the lock state). See also: lock, lock-to, locked? G:unpack

b s | b n s -- a n

Takes the items in the buffer or string b and "unpacks" them according to the format string s, returning the number n of bytes processed, and an array a with the interpreted data from the buffer. If a number is provided under the format string and above the buffer, it indicates an offset in bytes from the beginning of the buffer, from which to start unpacking. Inverse of pack; see pack for details of the format string G:var

--

immediate:Create a var named (read from the input stream), initialized with the number "0". Invoking the name will put the var on TOS; you can then retrieve data using @ or store data using !. Note that var as well as var, may only be used in interpret mode (that is, not inside a colon-def or anonymous word) G:var,

x --

immediate:Same as var except that the var is initialized with the value "x" G:while

x -- x

immediate:At runtime, peeks at x on TOS. If it evaluates to true, returns to the most recent repeat. Note that this does not pop TOS! If you want a destructive version of this, use G:while!. It is only available in compile-mode, and throws an exception otherwise. It also throws an exception if you forgot to invoke repeat before it. A "while loop" may also be stopped with ;; (which immediately exits the word), or break (which prevents the loop from repeating) G:while!

x --

immediate:This is the same as G:while, but destructively pops x from TOS G:with:

--

immediate:Add the ns (read from the input stream) to the "with list", which is the list of nss which will be searched. Matched by ;with. The namespace name should not have the "ns:" prefix, e.g. use with: n to add the number namespace to the with list

— 167 —

The 8th Manual: Words by namespace G:words

--

List all currently known words, alphabetically by ns G:words-like

filter -- arr

Like words/, takes a filter string filter, but returns an array arr of strings containing the fully-qualified names of words which match the filter. If filter is null, returns all words G:words/

--

Like words, but matches only words which match the string "". If the filter ends with a colon, will display words in that namespace, only G:xor

x y -- x XOR y

boolean "EXCLUSIVE OR" of x and y

Hardware hw:arm?

-- f

Return true if running on an ARM hw:camera

o -- hw|null

Takes a map o returned from the hw:camera? query, and requests the use of that camera from the OS. Returns a hw hw representing the camera on success, or null if it could not get use of the camera hw:camera-fmt

hw s w h -- hw

Selects the image format to use with the camera hw hw. The string s must be one of the formats returned in the camera's map, and the width w and height h should be one of the values given there; otherwise, the largest format not exceeding the input values will be used hw:camera-img

hw cb -- hw

Grabs images from the camera hw hw. The word cb will be invoked with an img in TOS, and must return true to continue taking more pictures, or false to stop hw:camera?

-- a|null

Queries the system for information on available cameras. Returns an array a of maps, one map per detected camera. The specifics about the camera are in the map, and the map itself should be used to request the use of the camera, using hw:camera. Subsequent invocations of hw:camera? may return different values (as hardware is connected or disabled), so you must not rely on the index in the array. Returns null if there are no devices available hw:cpu?

-- s

Returns a string s which identifies the properties of the CPU hw:device?

-- s

Returns a string s which is a description of the device on which 8th is currently running hw:dial

hw s -- hw

Given a hw hw returned from hw:phone, dial the phone number given in the string s. On some platforms this will cause the application to lose input focus hw:displays?

-- n

Returns the number n of displays (monitors) attached to this device hw:displaysize?

n -- wide high

Returns the dimensions of display n (from 0 to hw:displays? - 1), in pixels as numbers wide and high

— 168 —

The 8th Manual: Words by namespace hw:gpio

n read -- x

Create a new GPIO X item, which will be used for I/O on the GPIO pin n. If read is true, use the pin to read from; otherwise use it to write to hw:gpio!

x v --

Writes to GPIO pin x (returned from hw:gpio) the value v. That value is evaluated as: anything which would be true evaluates to '1' (e.g. "on") and anything which would be false evaluates to '0' hw:gpio-mmap

n --

The number n determines how to access GPIO. If it is "0", its turns off the memory-map accessors for GPIO (the default is to use the OS accessors). If it is "1", it tries to use the Raspberry Pi specific memory-map accessors. If the hardware you are running on is not a RPI, bad things might happen. You've been warned! hw:gpio@

x -- x m

Reads from GPIO pin defined in the X x (returned from hw:gpio) and returns null if it is unable to do so, or the value from the pin as a number m , which will be either '0' (for "off") or '1' (for "on") hw:i2c

bus addr -- hw

Given two numbers bus and addr, representing the bus-id and the device-address, returns a hw hw describing the opened I2C device, or null if it could not. Note: this functionality is currently only available on Linux, Android, and Raspberry Pi, and requires "root" access hw:i2c!

hw n b -- hw m

Given a hw hw returned from hw:i2c, writes the data in the buffer b to the I2C device register number n. Returns the number m of bytes written or null if there was a failure hw:i2c@

hw n -- hw b

Given a hw hw returned from hw:i2c, reads a number n bytes from the I2C device as a buffer b. Conversion of those data may be done with unpack. See hw:i2c for caveats regarding this word hw:mac?

-- a

Return this computer's network-cards' MAC addresses as an array a of strings hw:mem?

-- n

Returns the amount of RAM installed as a number n in MB hw:phone

o -- hw

Given a map o returned from hw:phone?, return a hw hw representing that phone (or null on failure) hw:phone?

-- a

Returns an array a of maps describing phone devices which may be used, or null if none were detected or available hw:poll

hw -- o

Poll the current state of the hw sensor hw, returning a map o whose keys specify the data for that device. For example, a "gps" device will return "lat", "lon" and "alt" keys, at least; and a "gyro" will return "x", "y", and "z"; and a "compass" will return "head" and "true". If the device is not available or has no data, null will be returned hw:sensor

s -- hw|null

Returns a new hw hw corresponding to the sensor type giving in the string s. Currently, that may be one of gps, gyro, compass or accel. Returns null if it failed to get that kind of sensor, or a hw item hw which may be polled, etc hw:sms

hw num msg -- hw

Given a hw hw returned from hw:phone, send an SMS message string msg to the phone number string num. On some platforms this will cause the application to lose input focus hw:start

hw --

Activate the hw sensor hw, which was created using hw:sensor. Retrieve data from the sensor using hw:poll

— 169 —

The 8th Manual: Words by namespace hw:stop

hw --

Stop the hw sensor hw from requesting updates from the hardware

Heap h:+

h1 h2 -- h1

Transfer all items from the heap h2 to the heap h1 h:clear

h -- h

Remove all items from the heap h h:len

h -- h n

Returns the number n of items on the heap h h:new

w -- h

Create a new heap h, using the word w as the comparator. w must take two items and return their order (negative if less, 0 if equal, positive if greater) h:peek

h -- h x

Return the "largest" item x off the heap h without removing it, or return null if the heap is empty. The order of items is determined by the heap comparator word passed it on creation h:pop

h -- h x

Return the "largest" item x from the heap h while removing it, or return null if the heap is empty. The order is determined by the heap comparator word passed it on creation h:push

h x -- h

Push the item x onto the heap h

Image img:>file

img s --

Write the img img to a file named by the string s. s should have an extension of ".png" or ".jpeg" or ".gif", and 8th will save in the corresponding format img:crop

img1 x y wide high -- img2

Given an img img1, return another img img2 which is the sub-image taken from the starting point (x,y) for a rectangle wide by high pixels. If the dimensions are outside the boundaries of the source img, returns null img:desat

img1 -- img2

Desaturate (convert to grayscale) the img img1 resulting in img img2 img:filter

img1 mat rect -- img2

Apply the convolution matrix defined by the array of numbers mat, to the img img1 over the rectangle defined by the array of numbers rect (which if null is the entire image), producing a new img img2. The array mat should have a size which is a perfect square; it will be treated as if it is (so if it has for example 10 numbers, the first 9 will be used to make a 3x3 convolution kernel). The array rect must have at least 4 numbers: [left, top, wide, high]. Anything other than an array will be taken to mean "apply to the entire image". The parameter mat may also be a map, in which case it must contain a key "mat" which is the matrix to use, and it may optionally contain the keys "mode" which is a number: 0 means ignore edge (the default); 1 = wrap edge; 2 = extend edge; 3 = treat edge as transparent black; and "normalize" which is a number to which the sum of the values in the matrix will be adjusted. So "normalize": 1 will make the matrix sum to 1 so that the overall brightness of the image is not affected img:flip

img1 horiz? -- img2

— 170 —

The 8th Manual: Words by namespace Given an img img1, return another img img2 which is the first one flipped end for end (mirrored). If horiz? is true, then it flips horizontally; otherwise, if flips vertically img:from-svg

x wide high -- img

Load an image from the item named x into an img img which is wide by high pixels. x may be a string or buffer and must contain SVG instructions img:new

x | wide high -- img

Load an img img from the item x. Allowable formats for the img are PNG, GIF or JPEG. If the item x is a string, it refers to a file name. If it is a buffer, it is the raw image data. If it is a img, it is another image, in which case a copy of that image is made. Alternatively, if two numbers wide and high are given, create a new blank img of those dimensions img:pix!

img row col clr -- img

Given a source img img and the numbers row and col and a color clr (string, number or RGBA array), set the pixel color at that point in the img img:pix@

img row col -- img n

Given a source img img and the numbers row and col, return the pixel color as an RGBA number n at that point in the img img:qr-parse

img -- results

Given a black and white img img, scans for QR codes and returns null if there are none, or an array results containing a string with the value encoded, or a number containing an error code. The possible error codes are: 1 Invalid grid size, 2 Invalid version, 3 ECC format error, 4 Data error, 5 Unknown data type, 6 Data overflow, 7 Data underflow img:rot

img1 how -- img2

Given an img img1, return another img img2 which is the first one rotated by how degrees img:scale

img1 wide high -- img2

Given a source img img1, resize it to wide by high pixels and return a new img img2 img:size

img -- img wide high

Given a source img img, return its width wide and height high in pixels

Map m:!

o key z -- o

Put the item z in the map or user-defined type o using string key key m:!?

m k val -- m Sets the value for the key k to val, if there isn't already a value for that key m:+

o1 o2 -- o1 Add the keys (and their current values) from map o2 into map o1 m:-

o s -- o Remove the string key s (and its associated item) from the map o m:@

o key -- o z

Returns the item z in the map or user-defined type o at key key, which is usually a string, but may also be a number. In that case, the map's keys are iterated in order until that number is reached; the specific order of the keys is indeterminate. It locks o while the key's value is retrieved m:@?

m k def -- m val

Gets the value for the key k, if it exists. If it doesn't exist, returns the default value def instead

— 171 —

The 8th Manual: Words by namespace m:clear

o -- o

Remove all elements from the map o m:data

o -- o p

If the item o is a user-defined type, then this returns the map p which holds its data. That permits you to use all the map words on it, if needed. Note that in general, you should normally use m:@ and m:! and m:exists? to act on user-defined types. If the item o is any other type then p will be null m:each

o w -- o

Iterate over map o and invoke word w for each element in o. The stack effect of w is "key item --"; that is, it is passed the key of the item as well as the item itself, and must consume both. The map o is not available on the stack while m:each is running, to avoid consistency problems. m:exists?

o key -- o f

Returns true if there is a value defined for the string key in the map or user-defined type o. This is necessary because requesting an arbitrary key from a map will always succeed, returning null if the key does not exist as well as if the value stored is actually null m:keys

o -- o a

Returns all the keys of the map o, as an array of strings a m:len

o -- o n

Return the length of the map o, e.g. the number of keys it currently contains, as a number n m:map

o1 w -- o2

Create a new map o2, whose elements are formed by executing the word w for each element of the original map o1. w is passed each item on the stack, "key x -- x2. The mapping must consume the key and element given, producing a single result in TOS, which becomes the corresponding element in the new map

Network net:>url

s -- s2

Take the string s and URL-encode it as per RFC 3986, returning an encoded string s2 net:DGRAM

-- n

Returns a number n which is a constant value telling net:socket to use a datagram (UDP) protocol net:INET4

-- n

Returns a number n which is a constant value telling net:socket to use internet v4 addressing net:INET6

-- n

Returns a number n which is a constant value telling net:socket to use internet v6 addressing net:STREAM

-- n

Returns a number n which is a constant value telling net:socket to use a streaming (TCP) protocol net:accept

sock -- sock2

Waits on the net sock after invoking net:listen, for a connection. When the connection occurs, returns a new net sock2 on which to talk to the remote side net:addrinfo>o

ai -- o

Given an X ai returned from net:getaddrinfo, convert it into a map o with keys: "flags" - a number which is various flags, OS dependent; "family" - a string, either "V4" or "V6"; "type" - a string, either "stream" or "dgram"; "proto" - a number which is the protocol; "addr" which either null or a valid IPv4 or IPv6 address string; "canon" - if present, a string with the canonical name of the address

— 172 —

The 8th Manual: Words by namespace net:bind

ai sock --

Binds the net sock to the addrinfo ai returned from getaddrinfo net:browse

s --

Tries to launch the system's default browser to open the URL given by the string s net:close

f --

Close the net f net:connect

ai sock --

Connects to the net sock with the X ai returned from net:getaddrinfo net:del

x -- n

Execute an HTTP DELETE request based on the map or string x. Return value n same as for net:put net:err>s

n -- s

Takes a number n which is an error code from one of the net: invocations, and converts it to a string s which describes the code net:err?

f -- n

Returns the last error code number n (OS-specific) from the net f, or 0 if no error net:get

url -- b f|h b f

Retrieve the web page given by the string or map url using HTTP GET. If successful, true is on TOS and a buffer b with the retrieved data is below it. If unsuccessful, false is on TOS and a number b with the error code is below it. If using a map, the parameters are the same as for net:post, please refer to the documentation for it. net:getaddrinfo

addr service -- ai

Given an internet address (dotted-ip or name) string addr, and the number or string of a service service (e.g. "http" or 80), returns an opaque X ai which is the address information for the given server. If null is passed as addr, it means "localhost". The return value is null if the lookup failed net:head

x -- o f

Execute an HTTP HEAD request based on the map or string x. Returns a map with the headers o, and a flag f for success or failure net:listen

sock --

Given a net sock which has been bound to an address using net:bind, listen for an incoming connection. Will block until the listen succeeds or times-out net:opts

n -- n opts

Retrieve the map opts used to initialize the net n. net:post

opts -- b f|h b f

Execute an HTTP POST based on the parameters in the map opts. The keys in opts may be any of: "bufsize" - Set the size of the buffer used to read (default: 65536 bytes); "checkexpire" - Check that the certificate has not expired (default: true); "data" - (required) holds the data to be POSTed; "getheaders" - if true returns the HTTP headers received as a map h, below the data (if the POST succeeded). If data is not a string it is converted to one using >s; "headers" - a map which has one key,value pair for each (additional) header desired; "pincert" - a buffer with a PEM-encoded certificate which the server must present to validate the connection; "readcb" - a word which (if present) is called-back after each chunk of data has been read. It receives the net item as well as the number of bytes received so far; "redirs" - a number which is how many redirections are permitted before resolving the URL (default is 5); "rootcert" - a buffer with a PEM-encoded root certificate; "sni" - if false, do not do SNI verification (default is true); "sniname" - a string which is the hostname to use for SNI verification (defaults to the hostname in the "url"). If it is set, it implies "sni" is true; "url" - (required) the web resource's URL; "vchain" whether or not to check the certificate's chain of validity (default: false); "verify" - whether or not to verify the host certificate (defaults to true); "vhost" - whether or not to verify the host name in the host certificate (defaults to true); "vhostname" - a string which sets the hostname that "vhost" checks. the default is the hostname of the "url". If present, "vhostname" implies "vhost" true; Return values are the same as for net:get

— 173 —

The 8th Manual: Words by namespace net:proxy!

o --

Takes a map o containing the keys "server" (a string) and "port" (a number), which will be used as a proxy for "net" connections. Setting the proxy to null restores direct-connections net:put

o -- n|h n

Execute an HTTP PUT based on the parameters in the map o, which are the same as for net:post. The additional key "overwrite", if true, means the PUT will overwrite the existing resource on the server. Returns a number n which is either an HTTP code or a negative value relating to an connection error. If the key "getheaders" was true in o, then also returns the HTTP headers from the response in a map h net:read

f s n -- f s n

Same as f:read but for a net net:s>url

s -- a

Breaks a string s representing a URL into an array a whose values are, in order: "protocol" (string, e.g. "http"), "server" (string, e.g. "google.com", "port" (number, e.g. 80) and "file" (string, e.g. "index.html). Missing values will be given defaults. An invalid URL will cause a null to be returned net:server

o -- net

Given a map o which describes information about the server, create a net net is itself a server which services requests. The default port number is 8080, if one is not provided using the key "port". The required key "recv" ( a word) is invoked when a client connects, and is given a net which refers back to the connected client, as well as a buffer containing the data received (on TOS). It may use net:write to return data to the client using the net it was given. The "made" and "lost" callbacks are invoked when a connection is made or lost, respectively. If the key "chunk" is present, it should be a number representing the largest chunk of data to receive at a time (default is 16K bytes). The "recv" callback must return true to terminate the connection, or false if it is desired to keep the connection open. The key "recv" is required, and if not present net:server returns null. TLS is supported if the "tls" key is true, and if the "cert" and "key" keys contain either a file-name with a PEM certificate or private key, or a buffer containing them. An exception will be thrown if "tls" is true but "cert" or "key" are not present, or if "cert" or "key" are invalid net:socket

domain type -- S

Create a new net S with the parameters given. domain is either net:INET4 or net:INET6, type is either net:STREAM or net:DGRAM. 8th does not directly support other socket variants -- for that you need to roll your own using the FFI. The net S encapsulates a socket, or null on error net:url>

s -- s2

Take the string s and URL-decode it as per RFC 3986, returning decoded string s2 net:user-agent

x --

Set the HTTP "user-agent" to use to the string x when making net invocations. It defaults to appname net:wait

net read? msecs -- net f

Wait to see if the net net is ready. Will wait msecs milliseconds (a number), and if read? is true, waits for incoming data to be ready; otherwise it waits for the underlying socket to be ready to write. Returns true if the net is ready, false otherwise net:write

f s -- f n

Same as f:write but for a net

Number n:*

n m -- n*m

Multiply 'n' and 'm' leaving the product on TOS n:*/

n x y -- n*x/y

Calculates the product of n with the ratio x/y n:+

n m -- n+m

Add 'n' and 'm' leaving the sum on TOS

— 174 —

The 8th Manual: Words by namespace n:+!

n var --

Add the number n to the number in the variable var n:-

n m -- d

Subtract the number m from the number n, returning the number difference d n:/

n m -- q

Divide the numbers n by m, returning the quotient as a number q n:/mod

n m -- r q

Divide the number n by m, returning the numbers remainder r and quotient q on the stack n:1+

n -- n++

Increment the number n n:1-

n -- n--

Decrement the number n n:


n m -- t

Compare numbers n and m, returning true if n is greater than m, otherwise false n:E

-- e

The mathematical constant "e" (2.71828...) as a "float". If you want an extended "bfloat", accurate to 130 decimal places, use "needs math/big" n:PI

-- pi

The mathematical constant "pi" (3.14159...) as a "float". If you want an extended "bfloat", accurate to 130 decimal places, use "needs math/big" n:^

n m -- p

Raise the number n to the power m, returning the number p n:abs

n -- n

Take the absolute-value of n n:acos

n -- acos(n)

Calculates the arc-cosine of the number n n:asin

n -- asin(n)

Calculates the arc-sine of the number n n:atan

x -- atan(x)

Calculates the arc-tangent of the angle x (in radians) n:atan2

x y -- atan(x,y)

Calculates the arc-tangent of the point (x,y) n:band

n m -- x

Returns a number x which is the bitwise AND of the numbers n and m. May modify n!

— 175 —

The 8th Manual: Words by namespace n:between

x low hi -- f

Return true if the number x is between low and hi, inclusive n:bfloat

n -- n

Converts the number n to a big floating-point representation, if possible n:bint

n -- n

Converts the number n to a big integer representation, if possible n:bnot

n -- m

Returns a number m which is the bitwise NOT of the number n n:bor

n m -- x

Returns a number x which is the bitwise OR of the numbers n and m. May modify n! n:bxor

n m -- x

Returns a number x which is the bitwise XOR of the numbers n and m. May modify n! n:ceil

n -- ceil(n)

Returns the nearest whole number (integer), greater than or equal to the number n n:clamp

n low hi -- n

Ensure that the number n is not less than low and not higher than hi (inclusive). So for example "23 10 20 n:clamp" will produce "20" n:cmp

a b -- n

Compare the two numbers a and b, returning a number n which has the value -1 if a < b, 0 if a=b and 1 if a > b n:cos

n -- cos(n)

Calculates the cosine of n, where n is in radians n:exp

n -- exp(n)

Raises "e" to the n power; inverse of ln n:float

n -- n

Converts the number n to a (native) floating-point representation, if possible n:floor

n -- floor(n)

Returns the nearest whole number (integer), less than or equal to the number n n:frac

n -- n

Return the fractional part of the number n n:int

n -- n

Converts the number n to an integer (or big integer, if it was a big float) representation, if possible. This is equivalent to casting to an "int" on C-like languages n:kind?

n -- n k

Given a number n, return a number k corresponding to its kind: 0=native integer, 1=native floating point, 2=big integer, 3=big floating point, 4=NaN, 5=Inf, 6=NegInf. If k is negative, indicates that the number n is a complex number of the given type (e.g. -2 means "a complex number whose components are big integers") n:ln

n -- ln(n)

Natural logarithm (e.g. base "e") of n

— 176 —

The 8th Manual: Words by namespace n:max

a b -- max(a,b)

Return the larger of the numbers a and b n:min

a b -- min(a,b)

Return the smaller of the numbers a and b n:mod

n m -- r Divide the numbers n by m, returning the remainder as a number r n:neg

n -- -n

Negate the number n. That is, change its sign from positive to negative and vice-versa n:round

n -- n

Round the number n to the nearest whole number (integer); if the fractional part is 0.5 or greater, round up (or down, if n is negative) n:round2

n d -- n

Rounds the number n according to the integer number d. If d is zero, then this is exactly the same as n:round. If d is a positive number, then n is rounded to that many digits to the right of the decimal. If d is negative, then that many significan digits is kept. So 123.456 2 round2" results in "123.460", while 123.456 -2 round2" results in "120.000" n:sgn

n -- m

Given the number n, returns a number m, which is -1 if n is less than zero, 0 if it is zero and 1 if it is greater than zero n:shl

n m -- x Returns the number x, which is the number n "shifted left" m bits. Thus 1 2 shl will give 4 n:shr

n m -- x Returns the number x, which is the value of the number n "shifted right" m bits. Thus 4 2 shl returns 1 n:sin

n -- sin(n)

Calculates the sine of n, where n is in radians n:sqr

n -- n^2

Return the square of the number n, e.g. n*n n:sqrt

n -- sqrt(n)

Return the square-root of the number n n:tan

n -- tan(n)

Calculates the tangent of n, where n is in radians n:trunc

n -- m Truncate the number n, dropping the fractional part and returning the integer part as a number m. This means rounding-towards-zero n:~=

n1 n2 eps -- f

Returns true if the numbers n1 and n2 are within the number eps of each other. Particularly useful for determining if "floating point" numbers are close to each other (rather than testing absolute equality)

Queue q:+

q1 q2 -- q1

Add as many items as will fit from queue q2 to the queue q1, popping them from one and pushing to the other. If q1 is not big enough to hold the data from q2, then it will throw an exception unless q:throwing was false for q1

— 177 —

The 8th Manual: Words by namespace q:clear

q -- q

Remove all items from the queue q q:len

q -- q n

Return the number n of items in the queue q q:new

n -- q

Create a new queue q of maximum capacity n, which must be a positive number. If a negative or zero size is given, returns null. Limited only by available memory q:overwrite

q f -- q

Set the queue q to "overwrite" mode (if f is true), so that it acts as a circular buffer rather than a queue. This means that continued q:push without q:pop will save the last N items pushed, where N is the size of the queue. If f is false, restore normal queue behavior q:peek

q -- q x

Return the first item x from the queue q without popping it from the queue q:pop

q -- q x

Pop the first item x off the queue q, removing it from the queue q:push

q x -- q

Push the item x into the queue q making it the last item in the queue q:shift

q -- q x

Remove the item x from the back of the queue q and put it on TOS. This makes the queue one element shorter. Like q:pop but from the back of the queue q:size

q -- q n

Returns the size n of the given queue q. The size is the maximum number if items the queue may contain q:slide

q x -- q

Add the item x to the front of the queue q. Like q:push but at the front of the queue, adding one more element to the queue (q:push puts the item at the back) q:throwing

q n -- q

If n evaluates true, the queue q will throw an exception on failure to push or pop. By default, the queue will return null in that case

Regex r:+match

r -- n

Match the regex r against the previously matched string, beginning from just after the previous match. Returns a number n which is the number of matches, or null if there were none r:/

s r -- a|null

Split a string s based on a regex r and return an array containing the matches or null if there were no matches. For example, "1234567" /(\d\d\d)(\d\d\d\d)/ r:/ would give the array ["123","4567"] r:@

r n -- r s

Returns the string s which is match number n from the regex r, or null if there was no match r:err?

-- s

Returns a string s representing the last error from a regex operation

— 178 —

The 8th Manual: Words by namespace r:match

s r -- n

Match the regex r against the string s. Return the number n of matches or null if there were no matches r:new

s -- r

Create a new regex r from the string s, or null if it failed to create one

Serial sio:close

sio --

Closes a previously opened sio sio, and terminates any connections sio:enum

-- a

Returns an array a of string paths to valid serial devices. One of these may be passed to sio:open. Returns null if there are no valid devices sio:open

nm -- sio

Returns a sio item sio, which represents the opened serial port named by the string nm, or null if it was unable to do so sio:opts!

sio opts -- sio

Given a sio sio, set its options based on the map opts as returned from sio:opts@ sio:opts@

sio -- sio o

Given a sio sio, returns a map o containing its current settings. All known settings will be returned as a key in the map, and all values are either numeric or boolean sio:read

sio s n -- sio s m

Read a number n bytes from the sio sio, into the string or buffer s. The number of bytes read, m, is left on TOS, or null if there was a problem. The string or buffer s remains on the stack sio:write

sio s -- sio n

Write the string or buffer s to the sio sio. The number n of bytes written is left on TOS, or null if there was a problem

Sound snd:curlen

-- n

Returns the currently playing snd's length as a number n in seconds snd:len

snd -- snd n

Returns the length n of a snd snd in seconds. This may be used on a snd whether it is playing currently or not snd:loop

t --

If t evaluates to true, make the currently playing snd repeat continuously. Otherwise, make it play just once snd:new

x -- snd

Create a new snd snd from the file-name or buffer x. To play the sound, invoke snd:play, passing the snd item. Returns null if the sound format is not supported or the sound is otherwise unplayable snd:play

snd --

Plays the snd snd which was created by snd:new snd:rate

snd rate -- snd

Set the sample rate of the snd snd to the number rate

— 179 —

The 8th Manual: Words by namespace snd:seek

n --

Sets the position in seconds n of the currently playing snd snd:stop

--

Stops the currently playing sound snd:tell

-- n

Returns the current playing position n, in seconds, of the current snd snd:volume

n --

Sets the system sound volume to a number n between 0 and 1, where 1 is 'full volume' snd:volume?

-- n

Returns the system sound volume as a number n between 0 and 1, where 1 is 'full volume'

Stack st:+

s1 s2 -- s1

Add as many items as will fit from stack s2 to the stack s1, popping them from one and pushing to the other. If s1 is null, the data-stack will be the destination. If s1 is not big enough to hold the data from s2, then it will throw an exception unless st:throwing was false for s1. If s1 is not null, it will remain on TOS; otherwise it is removed st:.

s --

Print the top 10 items in the st s, in the same manner as .s does for the data stack st:clear

s -- s

Removes all the items currently on the stack s. Equivalent to issuing st:pop drop repeatedly until the s is empty. NOTE: to clear the main data-stack, use G:reset and not st:clear st:len

st -- st n

Return the number n of items currently in the stack st st:new

n -- st

Create a new stack st of capacity n. The value given must be a positive non-zero number; if it is not, null is returned st:peek

s -- s x

Peeks at the top of the stack s. Returns the item x from the stack or null if empty st:pick

s n -- s x

Same as G:pick, but for the specified stack st:pop

st -- st x

Pops the item x from the stack st. If it is empty, throw an exception, unless st:throwing was set false, in which case it returns null st:push

st x -- st

Push the item x onto the stack st. If it is full, throw an exception, unless st:throwing was set false, in which case it fails quietly st:roll

s n -- s x

Same as G:roll, but for the specified stack st:shift

st -- st x

Remove the item x from the bottom of the stack st and put it on TOS. This makes the stack one element shorter, and shifts all remaining elements one lower. Like st:pop but from the bottom of the stack

— 180 —

The 8th Manual: Words by namespace st:size

st -- st n

Returns the size n of the given stack st. The size is the maximum number if items the stack may contain st:slide

st x -- st

Add the item x to the bottom of the stack st, moving all remaining items up one index. Like st:push but at the bottom of the stack st:swap

s -- s

Same as G:swap, but for the specified stack. That is, it exchanges TOS of the stack s with the item below it st:throwing

st n -- st

If n evaluates to true, make the stack st throw an exception on failure to push or pop; otherwise, the stack will return null on error

String s:!

s ix c -- s

Replace the character at index ix in the string s with the character c (which is a number representing a Unicode character). If ix is greater than s:len-1, nothing will happen. If it is negative, the character that many characters from the end of the string will be modified (-1 is the last character) s:*

s n -- s2

Create a new string s2 by replicating the string s the number n times. If n is 0 or negative, an empty string is returned s:+

s1 x -- s1+x

Appends the string or number x to the string s1. If x is a number it is treated as a Unicode character. The first string is modified by appending the contents of x s:-

s ofs len -- s

Remove len characters from the string s, starting at character offset ofs. Both len and ofs must be positive numbers, and if the combined length is greater than the string length then nothing is done s:/

s x -- a

Split the string s using x. If x is a number, split at that character index (starts at 0). If it is a string or a regex, split on all occurrences of x, omitting x from the results. If it is null, splits s into its component characters. Returns an array a of results, or an array with the entire string as the only element, if there are no matches. Inverse of a:join s:/scripts

s -- a

Given a string s, break it into an array a consisting of runs of characters with the same script and direction characteristics (LTR vs RTL). See s:script? s:base64

s -- s'

Encode string s in base64 encoding, returning string s' s:@

s ix -- s c

— 181 —

The 8th Manual: Words by namespace Returns the character c at index ix in the string s. The character is returned as a number representing the Unicode value of the character. If ix is greater than the number or characters in s, null is returned instead of a character. If ix is negative, the character that far from the end of the s will be returned (-1 is the last character). So for example, "abcdef" -2 s:@ will return the character "e" (e.g. 101) s:base64>

s -- s'

Decode string s from base64 encoding, returning string s' s:clear

s -- s

Overwrite the contents of the string s with 0, and reset its length to 0; the original string itself is modified s:cmp

a b -- n

Compare the two strings a and b, giving the number n which is negative if a < b, 0 if a = b and positive if a > b s:cmpi

a b -- n

The same as s:cmp, but compares in a case-insensitive manner s:compress

s -- s

Compress a string s using zlib s:days!

short long --

Takes two arrays: short, containing the short names of the week-days, and long containing the long names of the week-days, and inserts them into the appropriate maps for localization according to the current value of curlang. Should be used in the appropriate "lang/xx" asset s:each

s w --

Invokes word w for each character of the string s. It is w's responsibility to consume the character. The word w is passed two items: ix ch. The number ix is the index of the character in the original string s; __ch_is a number representing the character's Unicode encoding s:eachline

s w --

Invokes the word w for each line of the input string s, passing that line in TOS s:expand

s n -- s

Expand a zlib-compressed string s, where the number n is the original size of the uncompressed string s:fill

s x -- s

Fill the contents of the string s with character or string x. If x is a string, it will be repeatedly copied into s as many times as will fit, and any left-over will be filled with as many characters from x as possible without extending the length of s s:fmt

s -- s

Format the string s according to the alignment and other settings s:globmatch

filename glob -- f

Using the f:glob matching algorithm, compares the string filename with the glob string. If there is a match, returns true, otherwise false. See also f:glob and f:rglob s:hexupr

f --

Controls how hexadecimal numbers are converted to strings. If f is true, then hex numbers will be printed with uppercase text. The default is false s:insert

s1 s2 x -- s3

Insert the string s2 into the string s1 at offset x, which must be a positive number. If x is greater than the current number of characters in s1, then s2 will be appended to s1. Similarly, if it is 0 or less, s2 will be prepended to s1. The result is a new string s3 with the combined contents

— 182 —

The 8th Manual: Words by namespace s:intl

orig -- xlate

Attempts to return the translation of the string orig, based on the language set by s:lang. If no translation was given, the original string is returned, otherwise the translated string xlate is returned s:intl!

m --

Sets the map m to use for translating strings for the language G:curlang s:lang

la --

Attempts to set the current language for s:intl to the value la. The la is the name of a sub-asset; for example, if the language is given as "de", there must be an asset called "lang/de". That asset consists solely of a JSON map whose keys are the untranslated strings, and whose values are the translation of the key into the requested language. If no such language exists, the current language is not changed s:lc

s -- s

Convert the string s to lowercase. This only works for ASCII text, it does not handle UTF8 and locales s:len

s -- s n

Return the length n of the string s, e.g. the number of characters it currently contains (takes UTF-8 into account, so may be less than what s:size reports) s:lsub

s n -- s

Return the leftmost n characters of the string s s:ltrim

s -- s

Remove whitespace from the left end of the string s s:map

s w -- s2

Create a new string s2, whose elements are formed by executing the word w for each character of the original string s. w is passed each item on the stack: "ch -- ch2", meaning it gets an item and must modify it (or just leave it alone). The mapping must consume the element given and return either a number which is a Unicode character, or a string, producing a single result in TOS, which becomes the corresponding element in the new string s:months!

short long --

Takes two arrays: short, containing the short names of the months, and long containing the long names of the months, and inserts them into the appropriate maps for localization according to the current value of curlang. Should be used in the appropriate "lang/xx" asset s:replace

s1 pat s2 -- s3

In string s1, replace the pattern pat with s2 producing s3. The pattern can be a string or a regex, and is replaced only once. To replace all, use s:replace! s:replace!

s1 pat s2 -- s3

Same as replace, but replace all occurrences s:rev

s -- s2

Given a string s, returns a copy of it s2 with the characters in reverse order s:rsearch

haystack needle -- haystack n

Same as s:search, but returns number n which is the last occurrence of needle in haystack. Returns null if there is no match s:rsub

s n -- s

Return the rightmost n characters of the string s. If n is negative, starts from the left side of the string s:rtrim

s -- s

Remove whitespace from the right end of the string s

— 183 —

The 8th Manual: Words by namespace s:script?

s -- s m

Given a string s, return information about its script and directionality in a map m. The "dir" key will be either "LTR" or "RTL". The "script" key in the map returned will be one of "mixed", "latin", "greek", "cyrillic", "armenian", "hebrew", "arabic", "syriac", "thaana", "nko", "indic", "cjk", "number", "whitespace" or "symbol". If "mixed", then more than one script is present in the string s:search

haystack needle -- haystack n

Search the string haystack for the first occurrence of needle, returning the offset of the found text in n, or null if not found. needle can also be a regex s:size

s -- s n

Return the size n of the string s in bytes. Not necessarily the same as the number of characters given by s:len, due to 8th using the UTF-8 encoding in strings s:slice

s x y -- s1

Return s1 which is a string representing a "slice" of the string s, beginning at the position x for y characters. A negative value of x means "from the end of the string". If x is beyond the end of s, null is returned s:strfmt

a fmt | x1 x2 ... xn fmt -- s

Like the "printf" function in C. Takes a "format string" fmt containing formatting characters, and either an array a which has the items to interpolate into the result string s, or items x1 etc. on the stack corresponding in number to the items to be interpolated. The formatting is done by taking a % inside fmt to mean "format an item from the stack or array, right here". A literal %character is given by %%. Valid formatting codes are "d" for integer, "x" for hex integer, "f" for floating-point number, "s" for string s:trim

s -- s

Remove whitespace from both ends of the string s s:tsub

template values -- newstr

Takes a string template with replacement parameters such as %0%, %1%or %name%, %address%, and values as an array (if using %0%etc) or a map (if using %name%etc) containing items to replace the parameters in template. The sequence "%%" in template produces a literal "%" in the new string newstr. If the value being substituted is a word, it is invoked and the result is used as a substitute. Otherwise, the item is converted to a string and inserted s:uc

s -- s

Convert the string s to uppercase. This only works for ASCII text, it does not handle UTF8 and locales s:utf8?

s -- s f

Determines if the string s is a valid UTF-8 sequence or not. Returns true if s is valid UTF-8, false otherwise s:zt

s -- s

Ensure the string s ends with NUL (ASCII zero) and adjust its length if needed. Not generally needed, since 8th strings already have a NUL terminator; but if you convert from an external buffer (e.g using unpack) you may need this. The original string is modified

Task t:curtask

-- t

Returns the identifier for current task t t:def-queue

n --

Sets the default size of the queue to give new tasks to the number n, which must be between 1 and 100000. The default is 8 t:def-stack

n --

Sets the size of the stack to give new tasks to the number n, which must be between 16 and 100000. The default is 256. The default data stack size is set using stack-size t:done?

t -- t f

— 184 —

The 8th Manual: Words by namespace Given a task t, returns true if it is done (meaning that the word used to run it has finished). Returns false as long as that word continues running t:kill

t to --

Kill the task t, waiting to seconds before forcibly killing it. A negative number means 'wait forever' as for G:sleep t:main

-- t

Returns the identifier for the main task (there is always one task, which the main interpreter runs on) t:notify

t --

Notify the task t to stop sleeping. See also: t:task, sleep t:pop

-- x

Pops an item x (or null if there is no such item) from the current task's queue. This must be done within the word defining the task (or from one invoked from it) t:priority

t pri --

Set the priority of the task t to pri. The priority is a number from 0 (lowest) to 10 (highest). 5 is the normal value t:push

t x --

Pushes the item x onto the queue belonging to the task t. The size of that queue is determined by t:def-queue. The item pushed can be retrieved only by the task itself, using t:pop t:qlen

-- n

Returns the number of items, n, in the current task's queue t:result

t -- t x

Given a task t, returns the last value x it put on it's stack (when the task has finished). The value x will be null until the task is finished (and might be null after, depending on what's on TOS). Check for the task having finished using t:done? t:task

w -- x

Create a new "task" x, which is a thread of execution which runs independently of others. It receives its own data stack and you provide the word w which is invoked as its starting point. When that word exits, the task goes away. Returns the task's identifier x. See also: G:sleep, t:notify t:task-n

aN... a2 a1 N w -- x

Same as t:task, except that it takes a number N of items to transfer from the current stack to the new task's stack t:task-stop?

-- f

Return true if the current task has been told to stop; false otherwise. Must be invoked within the context of the task to be checked

Word w:alias:

w --

Create a new word named (from the input stream) and make it an alias to the word w. After this, invoking name will have the same effect as invoking w. Can be used to give a name to an anonymous word, among other things w:exec

w --

Invoke (call, run, execute) the word w. Does nothing if w is null. See also: w:exec? w:exec?

s -- f

Try to invoke the word named by the string s, and return true if successful or false otherwise

— 185 —

The 8th Manual: Words by namespace w:find

s -- w

Look up the word named s and return it as the word w, or null if s cannot be found w:forget

x --

Look up the word named by the string x, or the namespace designated by the number x, and make it invisible to the find word. The word's code remains, but you will not be able to invoke it by name or find it w:is

w --

immediate:Assign the word w as the action for the deferred word whose name is (read from the input stream), which was created using defer:. This assignment can be reversed using w:undo w:undo

w --

immediate:Undoes the last assignment from 'w:is' to the deferred word w

XML xml:+

x1 x2 -- x1

Insert the xml x2 as a child of the xml x1 xml:>s

x -- s

Convert the xml x to a string representation s. This will not necessarily be a complete round-trip of a file parsed with xml:parse xml:>txt

x -- x s

Given an xml x, return its text content, recursively, in a single string s xml:@

x y -- x x1

Given an xml document x (returned by xml:parse) and either a number or a string y, return the child document xml x1 (by index number or by name string), or null if the child could not be found xml:attr!

x attr val -- x

Set string attribute attr to the string, number or boolean value val for the xml x. The value of val is converted to a string if it isn't already one xml:attr@

x attr -- x val

Returns the string value val of the string attribute attr for the xml x xml:attrs

x -- x m

Returns a map m containing all attributes of the xml x, or null if there were none xml:each

xml w -- xml

Iterate over the xml document xml and invoke the word w for each element in it. w is passed the xml for each element and must consume it. Iterates the item and all its children xml:len

x -- x n

Return the number n of children in the xml document x xml:new

s -- x

Create a new xml (XML element) x with the tag s xml:parent

x -- y

Returns the parent y of the xml element x, which will be another xml or null if there is no parent element

— 186 —

The 8th Manual: Words by namespace xml:parse

o -- x

Take an item (string or buffer) o containing XML and parse it into an internal format. Return null if it failed to parse or an xml x. Currently it requires that the XML be encoded in UTF-8 xml:parse-html

o -- x

Take an item (string or buffer) o containing HTML and parse it into an internal format. Returns null if it failed to parse or an xml x. Yes, an xml -- because HTML is closely related to XML. The difference is mainly that HTML is not strict about pairing tags xml:tag!

x s -- x

Sets the "tag" of the xml element x to the string s xml:tag@

x -- x s

Returns the tag of the xml element x as a string s xml:text!

x s -- x

Sets the text in the xml element x to the string s xml:text@

x -- x s

Returns the text contained in the single xml element x as string s

— 187 —

Chapter 23: Libraries

8th includes some code as externally-loadable libraries, accessible using the needs word. So for example, to utilize the code in the 8th library net/soap, one would have a line like this in one’s code: needs "net/soap"

After that, the words in that library are available to be used in the 8th program.

23.1 crypto/root-certs Provides “root certificates” for TLS in case your applications need to validate certificates and you don’t otherwise have access to them. Defines the var cr:root-certs, which contains a buffer.

23.2 crypto/totp Implements HOTP and TOTP (one-time) passwords. See RFC-6238 for details. Defines the vars cr:totp-epoch and cr:totp-time-step, which may be modified if your needs require. In general, you will only need to use the words defined: cr:hotp

key time digits -- hotp

Return the HOTP based on the key, time and number of digits cr:totp

key time digits -- hotp

Return the TOTP based on the key, time and number of digits

23.3 date/dst Determines whether or not a date should be observing DST (daylight savings time). It handles the following standards: • 0: off - DST is always false • 1: on - DST is always on • 2: US - According to USA practice, depends on year • 3: EU - According to EU practice • 4: Israel - According to Israeli practice, depends on year • 5: Mexico - According to Mexican practice • 6: Australia - According to Australian practice — 188 —

The 8th Manual: Libraries

d:adjust-dst

dt n --

dt

Adjust the date dt by an hour if it should be DST according to the number given d:dst?

dt n -- dt f

Return true if the date dt is DST according to the rules number n

23.4 date/hebrew Provides Hebrew calendar support. The sample “hebrew.8th” shows how it may be used.

23.5 date/islamic Provides Islamic calendar support. The sample “calendar.8th” shows how it may be used.

23.6 date/sunrise Calculates the sunrise and sunset for a particular location. The sample “hebrew.8th” shows how it may be used. Provides the following words in the d namespace: d:do-dawn

--

Calculate dawn based on the value of the var d:dawn, default is -15 degrees d:do-dusk

--

Calculate dusk based on the value of the var d:dusk, default is -15 degrees d:do-rise

--

Calculate sunrise and sunset; this is the default d:location!

m -- m

Set the current location for calculations to the values in the given map m. See also geo/location. d:sunrise

d -- rise set

For the given date d, calculate the sunrise rise and sunset set based on the location previously set.

23.7 date/utils Various date utilities. Defines Sun Mon Tue Wed Thu Fri Sat as symbolic names for the days of the week, as well as the following words: d:+min

d min -- d2

Advance the date d by the number of minutes min, resulting in a new date d2 — 189 —

The 8th Manual: Libraries

d:+hour

d hr -- d2

Advance the date d by the number of hours hr, resulting in a new date d2 d:+day

d dy -- d2

Advance the date d by the number of days dy, resulting in a new date d2 d:ymd

d -- d s

Format a given date as “YYYY-MM-DD” d:next-week

d1 -- d2

Return a new date one week after the given one d:last-week

d1 -- d2

Return a new date one week before the given one d:next-year

d1 -- d2

Return a new date one year after the given one d:last-year

d1 -- d2

Return a new date one year before the given one d:next-month

d1 -- d2

Return a new date one month after the given one d:last-month

d1 -- d2

Return a new date one month before the given one d:prev-dow

d1 dow -- d2

Return a new date which is the specific day of the week before or on the given date d:next-dow

d1 dow -- d2

Return a new date which is the specific day of the week after or on the given date d:first-dow

d1 dow -- d2

Return a new date which is the first day of the week given, for the month of the given date d:last-dow

d1 dow -- d2

Return a new date which is the last day of the week given, for the month of the given date d:ymd>

y m d -- dt

Return a new date which represents the given year, month and day, at midnight exactly d:>ymd

dt -- y m d

Returns the year, month and day represented by the date given

23.8 geo/location — 190 —

The 8th Manual: Libraries

Establishes a new namespace “loc”, which encapsulates location information. A “location” is a map with the fields: • loc - The English name of the location • loch - The Hebrew name of the location • ofs - The offset from GMT, in minutes • tz - The DST zone (0-6, see date/dst) • lat - the location’s latitude (negative is south) • lon - the location’s longitude (negative is west)

23.9 gui/skin This makes “GUI skinning” easy. You define your skins, preferably as assets in the “skins” folder. Then you can use g:named-skin to apply that skin to the gui in question (the stack-effect is gui name -- gui). See the sample code in gui/skins.8th for practical details.

23.10 math/big Defines n:BIGPI and n:BIGE. Previously, the internal n:PI and n:E were “big floats”. That was a bad decision from a memory usage and efficiency standpoint, so the internal versions are now standard floats. If you require very high accuracy versions, you can use the BIG versions, which are accurate to 130 places after the decimal point.

23.11 math/comb-perm Combinations and permutations. Provides: • n:comb \ n k -- C(n,k) : Returns the number of combinations of n items taken k at a time • n:perm \ n k -- P(n,k) : Returns the number of permutation of n items taken k at a time

23.12 math/complex Previously, complex math was included in the core of 8th. That functionality has been moved to this library. If you need complex number math, use this library. See the sample math/complex.8th for practical details.

23.13 math/factorial Factorials. Provides: • n:! \ n -- n! : Returns n factorial — 191 —

The 8th Manual: Libraries

23.14 math/gcd Greatest common divisor. Provides: • n:gcd \ a b -- gcd(a,b) : Returns the greatest common divisor of a and b • n:xgcd \ a b -- gcd(a,b) x y : Returns the extended GCD of a and b, including x and y which satisfy the equation: a*x + b*y = gcd(a,b)

23.15 math/invmod Modular multiplicative inverse. Provides: • n:invmod \ n m -- invmod(n,m) : Returns the multiplicative inverse of n modulo m

23.16 math/matrix Previously, matrices were included in the core of 8th. That functionality has been moved to this library. If you need matrix math, use this library. Note that currently only regular numbers are supported, not complex numbers. See the sample math/matrix.8th for practical details.

23.17 net/basic-auth Provides support for “HTTP Basic Authentication”. Provides one word in the HTTP namespace: Word

Stack

>auth

name pwd -- auth

Given two strings: the user-name name and a password pwd, return a string auth which is HTTP Basic Authentication formatted

23.18 net/json-rpc Provides a simple mechanism for performing “JSON-RPC” calls. Provides one word in the JSONRPC namespace: Word

Stack

call

rpcobj paramobj -- rpcresult

Takes two maps, one rpcobj which defines the service to be called, the second paramobj which has the parameters to be given, and returns the result of the call as a map rpcresult or an error as null

— 192 —

The 8th Manual: Libraries

The first map, defining the service to be called, is not modified by the call. Its keys are url, which is the URL of the JSON-RPC provider. data which is a s:tsub template encased in an map. That map’s keys id - an integer value you provide, method - the name of the RPC method to invoke, params - an map with keys named and of the types required by the RPC call. The second map consists of the specific parameters to be substituted for the template placeholders in the first, prior to making the RPC call. The call word will return null on error, or an map with the results of the RPC call. See the sample json-rpc.8th for a specific example of how this may be used.

23.19 net/oath Makes using OAuth authentication easier. In the OAuth namespace the following words are useful: Word

Stack

auth-string

m url post? csec tsec -- s

Takes the map m created by “params” and the url to send to, whether is a POST or not, the secret keys for the consumer csec and token tsec, and generates an authentication string s gen-nonce

-- s

Creates a random string s of 32 characters for use as a nonce params

ckey token nonce hashtype -- o

Takes the consumer key ckey, the access token token, a nonce and a string hashtype stating the type of hash (e.g. “HMAC-SHA1”) and creates a map o which has the correct information in it. Does not create the signature, use auth-string for that.

See the “twitter.8th” sample for how this library is used.

23.20 net/soap Provides a simple mechanism for performing “SOAP” calls. Provides one externally useful word in the SOAP namespace: Word

Stack

call

soapobj -- result

Takes one map soapobj with parameters for the SOAP call, and returns result which is XML data or null

The map passed in contains url - the URL of the SOAP service, action - the URI of the action to perform, api - an map with the api and ns (namespace) for the API, and params - an map with parameters for the API. The call word will return null on error followed by an error code, or an xml with the results of the RPC call. See the sample soap.8th for a specific example of how this may be used.

23.21 utils/os-names — 193 —

The 8th Manual: Libraries

Provides utility words: os>long-name

n -- s

Convert a number returned from os to a long (human-readable) name name>os

s -- n

Convert a string (like “Windows”) to the number which os would return on that platform

23.22 utils/pdf Previously, PDF functionality was in the 8th core. It has been moved to this library. If you need PDF output, use this library. See the samples in “pdf” for practical usage.

23.23 utils/settings Provides a simple save/restore mechanism for application settings. To use this, one must set appname to something other than the default of “8th”! The settings database will be in the app:datadir, and will be named “settings.db”. This library provides: settings@

key -- value

Given a string key, returns the corresponding item value if it exists, or null if it does not settings@?

key default -- value

Same as settings@, but it returns default if the key was not present settings!

key value --

Save the setting named key, storing the string representation of value

— 194 —

Chapter 24: Error codes

Some of the facilities in 8th return additional error information as numeric codes, usually via a “err?” word in the specific namespace. The codes you may encounter are listed in the following sections.

24.1 Crypto error codes The word cr:err? will return the last error generated by the crypto words. A value of “0” means “no error”. Otherwise, possible values are: 1. Generic error (no specific information available) 2. No operation was performed (not really an error) 3. Invalid key size was given 4. Invalid number of rounds 5. The algorithm failed test vectors 6. Not enough space for output 7. Invalid input packet given 8. Invalid number of bits for a PRNG 9. Could not read enough from PRNG 10. Invalid cipher specified 11. Invalid hash specified 12. Invalid PRNG specified 13. Out of memory 14. Not equivalent types of PK keys 15. Requires a private PK key 16. Generic invalid argument 17. File Not Found 18. Invalid type of PK key 19. Invalid PK system specified 20. Duplicate key already in key ring 21. Key not found in keyring 22. Invalid size input for PK parameters — 195 —

The 8th Manual: Error codes

23. Invalid size of prime requested 24. Invalid padding on input

24.2 SQLite error codes db:err? will return one of these (or 0 if no error), and db:errmsg will return the string indicated. If you are using MySQL, the error code will be one of those listed on the MySQL site — please check there.

1. SQL error or missing database 2. Internal logic error in SQLite 3. Access permission denied 4. Callback routine requested an abort 5. The database file is locked 6. A table in the database is locked 7. A malloc() failed 8. Attempt to write a readonly database 9. Operation terminated by sqlite3 interrupt() 10. Some kind of disk I/O error occurred 11. The database disk image is malformed 12. Unknown opcode in sqlite3 file control() 13. Insertion failed because database is full 14. Unable to open the database file 15. Database lock protocol error 16. Database is empty 17. The database schema changed 18. String or BLOB exceeds size limit 19. Abort due to constraint violation 20. Data type mismatch 21. Library used incorrectly 22. Uses OS features not supported on host 23. Authorization denied 24. Auxiliary database format error 25. 2nd parameter to sqlite3 bind out of range 26. File opened that is not a database file 27. Notifications from sqlite3 log() — 196 —

The 8th Manual: Error codes

28. Warnings from sqlite3 log() 100. sqlite3 step() has another row ready 101. sqlite3 step() has finished executing

24.3 File I/O and other POSIX error codes 1. Operation not permitted 2. No such file or directory 3. No such process 4. Interrupted system call 5. I/O error 6. Device not configured 7. Argument list too long 8. Exec format error 9. Bad file descriptor 10. No child process 11. Resource temporarily unavailable 12. Cannot allocate memory 13. Permission denied 14. Bad address 15. Block device required 16. Device or resource busy 17. File exists 18. Cross-device link 19. Operation not supported by device 20. Not a directory 21. Is a directory 22. Invalid argument 23. Too many open files in system 24. Too many open files 25. Inappropriate ioctl operation 26. Text file busy 27. File too large 28. No space left on device — 197 —

The 8th Manual: Error codes

29. Invalid seek 30. Read-only file system 31. Too many links 32. Broken pipe 33. Numerical argument out of domain 34. Numerical result too large 35. Operation would block 36. Operation now in progress

24.4 net: word error codes -1. No such host -2. Cannot create the socket -3. Cannot connect to host -4. Write error on socket while writing header -5. Write error on socket while writing data -6. Read error on socket while reading result -7. Invalid answer from data server -8. Invalid URL - must start with http: or https: -9. Invalid port in URL -10. Too many redirects -21. TLS GENERIC ERROR -22. TLS BROKEN PACKET -23. TLS NOT UNDERSTOOD -24. TLS NOT SAFE -25. TLS NO COMMON CIPHER -26. TLS UNEXPECTED MESSAGE -27. TLS CLOSE CONNECTION -28. TLS COMPRESSION NOT SUPPORTED -29. TLS NO MEMORY -30. TLS NOT VERIFIED -31. TLS INTEGRITY FAILED -32. TLS ERROR ALERT -33. TLS BROKEN CONNECTION — 198 —

The 8th Manual: Error codes

-33. TLS BAD CERTIFICATE -34. TLS UNSUPPORTED CERTIFICATE

— 199 —

Suggest Documents