TeleBASIC Reference Guide

                                   +*#+=.
                  -=++==-:.:-    :@@@@@@%-.
                +@@@%##@@@@@@#. .******###+.
      :-:       #@@%###*:=*+*#%@@@@@@@@@@@@@@%#+=:.
     *@@@%+     .@@@@#-=#@@@@@@@@@@@@@@@@@@@@*=--+@@#+-.
     -@@@%#*:     ..-#@@@@@@@@@@@@@@@@@@@@%-=**:-@@@= :@@%*:
      +@@%%%+*. :=#@@@@@@@@@@@@@@@@%@@@@@+ *@@:=%@@@@#%*#+-**.
       #@@@*=.*@@@@@@@@@@@@%#*****=***##@:=-@@.**@@@+:=#-#@=
        #@##++@@@@@#####***#%%@@@@ =@%#%#+:#:#=**#%*=@#:@@#
         #@*+:=+**#@@@@@@@@@@@@@@@%--#%++-.=@:-:+#####%%#**-+#
          @#+=+=+=:*++++**#@@@@@@@@@@**==*@+=@#=.   .=+*###*=.
          =@*@*   -@@@@@@@@*-+%@@@@@%+#@@#**#=+#@@%%#*+-:
          :@@=    .@@@@@#%*.    ....=@@@@#+-
           @=       ...==.         -#++++##
           :                           =+-

    Dartmouth DTSS TeleBASIC (c) 1964,1966,1969,1970,1971,1979,2023


  > What is TeleBASIC?

  TeleBASIC is the flavour of BASIC (Beginners' All-purpose Symbolic
  Instruction Code), used on Telehack (https://telehack.com/).  TeleBASIC is
  based on the original Dartmouth BASIC, but with a large number of additional
  features, such as support for regular expressions, UNIX timestamps, many
  common hashing/encoding algorithms, multi-dimensional arrays, and the ability
  to use alphanumeric indices.

  Features from other types of BASIC such as HP2000 Access BASIC and Commodore
  BASIC have been added for increased compatibility and functionality.

  TeleBASIC has a wide user-base and is actively maintained by members of The
  Telehack Foundation (https://github.com/orgs/telehack-foundation/people/).


  > Table of Contents

  1. Set Up Your Editor for BASIC Programming
  2. Comparing/Logical Operators
  3. Variables and Data Types
  4. Arrays & Hashes
  5. Command Overview
  6. FAQ
  7. ANSI Escape Sequences


  > 1. Set Up Your Editor for BASIC Programming


  -> Using External Text Editors

  There are currently four user-made plugins, which enable syntax-highlighting
  in various editors:

  * Atom (https://telehack.com/r/tg9sD)
  * Nova (https://telehack.com/r/gDAbA)
  * Sublime Text 3 (https://telehack.com/r/lP7iz)
  * Visual Studio Code (https://telehack.com/r/vxEjh)


  -> Using PED

  You can also use the text editor PED within Telehack - a massively augmented
  version of the original program by Niek Albers.  Extra features include
  syntax highlighting, and the ability to run programs without closing the
  editor.

  These features are accessible via emacs-style meta-key shortcuts.

  To see a list of features type M-x list-packages RET.


  --> What does that mean?

  The "M" refers to the "meta" key on your keyboard (most often, this is the
  escape key) and "RET" refers to the "return" key.

  For example, to enable BASIC syntax highlighting, you would press escape,
  then x, then type "basic" and hit return.

  Thus, the shorthand would be M-x basic RET.

  Additionally, you do not need to type the full name of the command.  It is
  sufficient to simply type M-x ba RET.

  To run a BASIC program within PED type M-x run RET.

    Command-line options
    ====================
    ped /nomouse     disables mouse input support
    ped /noexpand    disables tab expansion
    ped /basic       enables BASIC syntax highlighting
    ped /tablen=<n>  set tab length to <n>


  > 2. Comparing / Logical Operators


  -> Comparing Operators

  * = (equal to)
    10  A% = 0 : IF A% = 0 THEN PRINT "It is equal!"

  * > (greater than)
    10  A% = 5 : IF A% > 0 THEN PRINT "It is greater!"

  * >= (greater than or equal to)
    10  A% = 0 : IF A% >= 0 THEN PRINT "It is greater or equal!"

  * < (less than)
    10  A% = -1 : IF A% < 0 THEN PRINT "It is less!"

  * <= (less than or equal to)
    10  A% = 0 : IF A% <= 0 THEN PRINT "It is less or equal!"

  * <> (not equal to)
    10  A% = 1 : IF A% <> 0 THEN PRINT "It is not equal!"



  -> Logical Operators

  * AND (bitwise "and" operation)
  * OR (bitwise "or" operation)
  * XOR (exclusive "or" operation)
  * NOT (negation)
  * EQV (material equivalence)
  * IMP (implication)


  --> Results Returned by Logical Operations

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+---------
    NOT       | X     |       | NOT X
    NOT       | True  |       | False
    NOT       | False |       | True

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+----------
    AND       | X     | Y     | X AND Y
    AND       | True  | True  | True
    AND       | True  | False | False
    AND       | False | True  | False
    AND       | False | False | False

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+---------
    OR        | X     | Y     | X OR Y
    OR        | True  | True  | True
    OR        | True  | False | True
    OR        | False | True  | True
    OR        | False | False | False

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+----------
    XOR       | X     | Y     | X XOR Y
    XOR       | True  | True  | False
    XOR       | True  | False | True
    XOR       | False | True  | True
    XOR       | False | False | False

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+----------
    EQV       | X     | Y     | X EQV Y
    EQV       | True  | True  | True
    EQV       | True  | False | False
    EQV       | False | True  | False
    EQV       | False | False | True

    OPERATION | VALUE | VALUE | RESULT
  ------------+-------+-------+----------
    IMP       | X     | Y     | X IMP Y
    IMP       | True  | True  | True
    IMP       | True  | False | False
    IMP       | False | True  | True
    IMP       | False | False | True


  -> Arithmetic Operators

  TeleBASIC supports the following standard mathematical operators:

  (), ^, **, mod, /, *, +, and -.


  > 3. Variables and Data Types

  You can store either text or numeric values in variables.

  Variable names can contain letters and digits, but they have to start with a
  letter (e.g FOO, BAR123$).

  You cannot use reserved keywords (e.g FOR, IF) as variable names.

  Variable names are most often suffixed with a type definition character
  (called a "sigil"):

  * $ represents a text (string) value
  * % represents a numeric (integer) value
  * ! represents a numeric (single-precision) value

  Strings MUST include the $ sigil.  If a variable is missing a sigil, then it
  is a number.

  For example:

    10  NAME$ = "some name"

  would represent a string variable NAME$, but

    10  NAME = "some name"

  ...would throw a TYPE MISMATCH ERROR, since you cannot assign a string to a
  numeric variable.


  > 4. Arrays and Hashes

  An array variable is basically a list of values.  These can be accessed by
  specifying an index number.
  In traditional Dartmouth BASIC, we define a string array of size 10:

    10  DIM MYLIST$(10)

  Now we can modify the 5th Entry (note that the array index usually starts at
  0, and can also be negative):

    20  MYLIST$(4) = "some text"

  TeleBASIC, however, does not require you to define the array's size before
  accessing it, so DIM is not necessary.

  In addition to this, TeleBASIC allows for creation of multi-dimensional
  arrays, such as:

    10  MYSTUFF( X, Y ) = 42

  ... and indices do not need to be numeric.  Thus, you can create unordered
  lists (hashes) such as:

    10  FAV$("fruit") = "Apple"
    20  FAV$("vehicle") = "Bicycle"
    30  FAV$("language") = "TeleBASIC"


  > 5. Command Overview


  -> Index


  --> A

  * ACCESS  Currently not implemented, does nothing
  * ARG$  A string containing all command line arguments
  * ARGC%  The number of arguments passed to the program
  * ARGV$(n)  An array containing all of the arguments passed to the program
  * ASC(s$)  Returns the ASCII value of the first character in the string s$
  * ATN(n)  Returns the arctangent of the specified value n


  --> B

  * BIN$(n)  Returns the binary representation of the integer n as a string
  * BRK(n)  Currently not implemented, does nothing


  --> C

  * CALL  Currently not implemented, does nothing
  * CHR$(n)  Convert an ASCII code n to its equivalent character
  * CINT(n)  Returns the nearest integer of the specified value
  * CIRCLE  Currently not implemented, does nothing
  * COLOR(a, b)  Changes the colours of the terminal
  * COS(n)  Returns the cosinus of a specified value n in radians
  * CSNG(n)  Convert a specified value n to a single precision number


  --> D

  * D2R(n) Convert degrees to radians
  * DATA n... Store variables accessed by the program READ statements
  * DEF FNname(Argument) = Expression  Define a function
  * DEFDBL (Variable)  Currently not implemented, does nothing
  * DEFINT (Variable)  Currently not implemented, does nothing
  * DEFSNG (Variable)  Currently not implemented, does nothing
  * DEFSTR (Variable)  Currently not implemented, does nothing
  * DIM (Variable)  Currently not implemented, does nothing
  * DIR$  Returns the filenames in your local directory, separated by spaces
  * DO  Currently not implemented, does nothing
  * DRAW  Currently not implemented, does nothing


  --> E

  * END  End program execution silently, without additional output
  * EOF(n)  Returns file pointer information
  * ERASE (arrays)  To eliminate arrays from a program
  * EXP(n)  Return base of natural logarithms to the power of n


  --> F

  * FOR x = startValue TO maxValue [STEP n]  Execute a series of instructions
  * FRE  Return available memory


  --> G

  * GOSUB (LineNumber)  Branch to a subroutine and return
  * GOTO (LineNumber)  Branch unconditionally to a specified line number


  --> H

  * HEIGHT  Returns your terminal height
  * HEX$(n)  Returns hexadecimal value of the specified number n


  --> I

  * IF expression THEN statements  Make a decision regarding program flow
  * INKEY$  Returns one character read from the terminal
  * INPUT FileNo, var$  Reads a line from an open file
  * INPUT var$  Read user input
  * INPUT "prompt", var$  Read user input
  * INPUT varA$, varB$, ...  Read user input
  * INPUT "prompt", varA$, varB$, ...  Read user input
  * INSTR(string$, search$, startPos)  Returns the position of a substring
  * INT (n)  Truncate a value to a whole number
  * ITM(fileNumber)  Returns the number of a data item


  --> L

  * LEFT$(s$, n)  Returns the leftmost n characters of the specified string s$
  * LEN(s$)  Returns the number of characters in the specified string
  * LET Variable = Value  Assigns a value to a variable
  * LIN(n)  Returns n newlines
  * LOCATE y, x  Change the cursor position to y, x
  * LOG(n)  Returns the natural logarithm of n
  * LOG10(n)  Returns the natural logarithm of n (base 10)


  --> M

  * MID$(s$, n, [l])  Returns a string of l characters from s$


  --> N

  * NINT(n)  Returns the nearest integer of the specified value
  * NUM(s$)  Returns the ASCII value of the first character in the string s$


  --> O

  * OCT$(n)  Returns the octal value of n
  * ON NUMBER%  Jump conditionally to a line number based on value given
  * OPEN filename$, AS fileNumber  Opens a file


  --> P

  * PCLEAR0  Currently not implemented, does nothing
  * PCLEAR1  Currently not implemented, does nothing
  * PEEK(n)  Read a value from the specified memory location n
  * PLAY  Currently not implemented, does nothing
  * PMODE0  Currently not implemented, does nothing
  * POKE n, m  Write a byte of data m into the specified memory location n
  * POLKEY$(n)  Returns one character read from the terminal
  * PORT%  Returns the port from the currently logged in user
  * POS(s1$,s2$)  Returns the position of a substring
  * PRINT expression  Prints an expression to the screen
  * PUT  Currently not implemented, does nothing


  --> R

  * R2D(n)  Converts n radians to degrees
  * READ n...  or a file and assign to variable
  * REC(n)  in the specified file
  * RENUMBER [start,[inc]  Renumbers the statements of the current program
  * RESTORE  statements to be reread
  * RETURN  Return from a subroutine
  * RIGHT$(s$, n)  Returns the rightmost n characters of s$
  * RND(n)  Returns a random number


  --> S

  * SCRATCH  Delete a file from the disk
  * SCREEN  Currently not implemented, does nothing
  * SGN(n)  Returns the sign of the specified value n
  * SIN(n)  Returns the trigonometric sine of the specified value n in radians
  * SLEEP n  Pauses the program for n seconds
  * SOUND  Currently not implemented, does nothing
  * SOUNDRND  Currently not implemented, does nothing
  * SPACE$(n), SPC$(n), SPA(n)  Returns n spaces
  * SQR(n)  Returns the square root of n
  * STOP  Halts the program and prints the current line
  * STR$(n)  Returns n as a string value
  * STRING$(n, s$)  Repeats the string s$ n times
  * SYSTEM  End program execution silently, without additional output


  --> T

  * TAB(n), TAB$(n)  Returns n spaces (not tabs!)
  * TAN(n)  Returns trigonometric tangent of n in radians
  * TH_B64D$  Returns argument decoded from base64
  * TH_B64E$  Returns argument encoded to base64
  * TH_DEFGROUP$  Returns the user's defgroup, separated by spaces
  * TH_EXEC  Executes a shell command and returns to the program
  * TH_GMTIME[$]  Returns a human-readable UTC time for a timestamp
  * TH_HASADMIN(sat$)  Returns 1 if the user has admin on sat$
  * TH_HASBADGE(badge$)  Returns when the user earned badge$
  * TH_HASLOGIN(host$)  Returns 1 if the user has login on host$
  * TH_HASROOT(host$)  Returns 1 if the user has root on host$
  * TH_HASSYSOP(bbs$)  Returns 1 if the user has sysop on bbs$
  * TH_HOSTNAME$  Returns current hostname or hostname of argument passed
  * TH_LOCALTIME[$]  Returns a human-readable local time for a timestamp
  * TH_MD5BASE64$  Returns md5 hex of argument passed as base64
  * TH_MD5HEX$  Returns md5 hex of argument passed as hex
  * TH_MODEM$  Returns modem information depending on option passed
  * TH_NETSTAT$  Returns a netstat, separated by spaces
  * TH_PLAN$  Returns the user's .plan as a string
  * TH_RE(txt$,pat$,count,case)  Returns regex matches
  * TH_RE$(txt$,pat$,ind$,case)  Returns regex matches
  * TH_REV$(s$)  Returns the string s$ in reverse order
  * TH_SED$(txt$,find$,replace$,opt$)  Substitute matched substring
  * TH_SPRINTF$(fmt$,[...])  Returns a formatted string
  * TH_STATUS$  Returns the user's status as a string
  * TH_SYSLEVEL  Returns the user's Telehack system level
  * TH_TIME  Returns the current UNIX timestamp
  * TH_UUD$(s$)  Decodes a uuencoded string
  * TH_UUE$(s$)  Returns uuencoded form of input string
  * TIM(n)  Returns values of time and date depending on n
  * TIME$  Returns the local system time
  * TIMER  Returns the number of seconds since midnight
  * TROFF  Stops tracing of program statements
  * TRON  Starts tracing of program statements
  * TYP(n)  Returns the type of the next record in a file


  --> U

  * UPS$(string)  Returns the uppercase value of the given string
  * USER$  Returns the current logged in user


  --> V

  * VAL(s$)  Returns the numeric value of s$


  --> W

  * WIDTH  Returns your terminal width


  > Detailed Overview


  -> ABS(n)

  Returns the absolute value of the specified value n

    10  PRINT ABS(-40)

     40


  -> ACCESS

  Currently not implemented, does nothing


  -> ARG$

  A string variable this is populated with a string containing the command
  line arguments when a BASIC program is run from the shell command prompt.

    10  PRINT ARG$

    @program foo bar
    foo bar


  -> ARGV$(n)

  An array containing all of the arguments passed to the program (see example
  for ARGC% below)


  -> ARGC%

  The number of arguments passed to the program

    10  FOR I = 0 TO ARGC%-1
    20  PRINT ARGV$(I)
    30  NEXT I

    @program foo "hello world" bar
    [run program.bas foo "hello world" bar]
    program.bas
    foo
    hello world
    bar


  -> ASC(s$)

  Returns the ASCII value of the first character in the string s$

    10  PRINT ASC("A")

     65

  See also NUM


  -> ATN(n)

  Returns the arctangent of the specified value n

    10  PRINT ATN(40)

     1.546


  -> BIN$(n)

  Returns the binary representation of the integer n as a string

    10  PRINT BIN$(123)

    1111011


  -> BRK(n)

  Currently not implemented, does nothing


  -> CALL

  Currently not implemented, does nothing


  -> CHR$(n)

  Convert an ASCII code n to its equivalent character

    10  PRINT CHR$(42)

    *


  -> CINT(n)

  Returns the nearest integer of the specified value (9.5 becomes 10)

    10  PRINT CINT(5.7)

     6


  -> CIRCLE

  Currently not implemented, does nothing


  -> COLOR(a, b)

  Changes the background b and/or foreground a colour of the terminal

    10  COLOR 3, 4
    20  PRINT "Hello"

  Prints Hello with blue b background and yellow a foreground text.  A list of
  possible colours can be found with the command SHOW COLORS.


  -> COS(n)

  Returns the cosinus of a specified value n in radians

    10  PRINT COS(67)

     -0.517769799789505


  -> CSNG(n)

  Convert a specified value n to a single precision number

    10  PRINT CSNG("3.45")

     3.450


  -> D2R(n)

  Convert degrees to radians

    10  PRINT D2R( 90 )

     1.571


  -> DATA n...

  Store the numeric and string constants that are accessed by the program READ
  statements

    10  DATA 4.1, 5.6, 9.98
    20  READ A, B, C
    30  PRINT A, B, C

     4.100          5.600          9.980


  -> DEF FNname(Argument) = Expression

  Define a function with the name FNname which accepts an Argument and returns
  the defined Expression.
  The function name must always begin with FN, followed by an optional space.

    10  DEF FN square(x) = x^2
    20  DEF FNcube(x) = x^3
    30  DEF FNtood$(s$) = s$ + "tood"
    40  PRINT FNsquare(5),FNcube(5),FNtood$("foo")

     25             125           footood


  -> DEFDBL (Variable)

  Declare a variable as double precision number (currently not implemented,
  does nothing)


  -> DEFINT (Variable)

  Declare a variable as integer number (currently not implemented, does
  nothing)


  -> DEFSNG (Variable)

  Declare a variable as single precision number (currently not implemented,
  does nothing)


  -> DEFSTR (Variable)

  Declare a variable as string (currently not implemented, does nothing)


  -> DIM (Variable)

  Define an array of a fixed size (currently not implemented, does nothing)


  -> DIR$

  Returns the filenames in your local directory, separated by spaces

    10  PRINT DIR$

    advent.gam againstip.txt basic15.a2 bbslist.txt c8test.c8 changelog.txt
  colossus.txt command.txt crackdown.txt do-well.txt etewaf.txt finger.txt
  fireworks.vt fnord.txt future.txt hammurabi.bas hckr_hnd.txt ien137.txt
  jfet.a2 johnnycode.txt k-rad.txt learncode.txt leaves.txt lem.bas lostpig.gam
  mastermind.bas notes.txt orange-book.txt oregon.bas porthack.exe privacy.txt
  rogue.gam rootkit.exe satcom.man smile.c8 starwars.txt sysmon.txt
  telehack.txt ttest.vt underground.txt unix.txt valentin.vt wardial.exe
  wumpus.bas xmodem.exe zork.gam


  -> DO

  Currently not implemented, does nothing


  -> DRAW

  Currently not implemented, does nothing


  -> END

  End execution of the program silently, without additional output (in
  contrast to STOP).
  Note that SYSTEM is an alias for END.

    10 PRINT "hello"
    20 GOSUB 100
    30 END
    40 PRINT "WORLD"
    50 RETURN


  -> EOF(n)

  Returns -1 if the file pointer in file number n is currently at the end of
  the document, otherwise returns 0.

  The reason for -1 being used to denote truth is that -1 is 11111111 in binary,
  and conversely, 0 is 00000000.

  See also TYP.


  -> ERASE arrays

  Eliminate an array from the program.  Accepts a list of arrays.

    10  A(1) = 123
    20  A(2) = 456
    30  B$( "foo" ) = "bar"
    40  B$( "bar" ) = "baz"
    50  ERASE A, B$
    60  PRINT A(1) A(2) "'" B$( "foo" ) "' '" B$( "bar" ) "'"

     0  0 '' ''


  -> EXP(n)

  Return the base of natural logarithms to the power of the specified value n

    10  PRINT EXP(13)

     442413.392


  -> FOR x = startValue TO maxValue [STEP n]

  Execute a series of instructions a specified number of times in a loop,
  optionally incrementing x by n each time.

  Note that FOR I=A TO B STEP S: ... : NEXT I works like I=A; do { ... } while
  ((I+=S) < B); (in the C programming language), so the last NEXT I increases
  I one step beyond B.

    10  FOR I = 1 TO 40
    20  PRINT I
    30  NEXT I
    40  REM the I variable is now 41

  This would run 40 times and output every time the current counter,
  incrementing I by 1 each time.

    10  FOR I = 1 TO 40 STEP 2
    20  PRINT I
    30  NEXT I

  This would run 40 times and output the current counter in each iteration,
  and would increase I by 2 each time.

    10  FOR I = 1 TO 0 STEP 0
    20  PRINT I
    30  NEXT I

  This would create an endless loop, printing 1 over and over until
  terminated.


  -> FRE

  Return the available system memory in bytes

    10  PRINT FRE

     1048576


  -> GOSUB (LineNumber)

  Branch to a subroutine and return

     10  GOSUB 100
     20  PRINT "Now I'm back from the subroutine"
     30  END
    100  REM Subroutine starts here
    110  PRINT "I am now in the subroutine"
    120  RETURN

    I am now in the subroutine
    Now I'm back from the subroutine


  -> GOTO (LineNumber)

  Branch unconditionally out of the normal program sequence to a specified
  line number

    10  PRINT "Hello World!"
    20  GOTO 10

    Hello World!
    Hello World!
    Hello World!
    Hello World!
    Hello World!
    Hello World!
    [...]

  You might want to use a SLEEP statement here!


  -> HEIGHT

  Returns your terminal height


  -> HEX$(n)

  Returns a string which represents the hexadecimal value of the specified
  number n

    10  PRINT HEX$(127)

    7F


  -> IF expression THEN statements

  Make a decision regarding program flow based on the result of a returned
  expression

    10  K = 3
    20  J = 10
    30  IF J > K THEN PRINT "J is bigger than K"

    J is bigger than K

  See section 2. Comparing/Logical Operators


  -> INKEY$

  Returns one character read from the terminal. It will wait until a character
  is typed. For a non-blocking alternative, see POLKEY$

    10  A$ = INKEY$
    20  PRINT A$


  -> INPUT var$

  Shows the default prompt and reads input from the user and saves it into
  var$.

    10  INPUT A$
    20  PRINT A$


  -> INPUT "prompt", var$

  Shows prompt$ and reads input from the user and saves it into var$. Note
  that the prompt must be a string literal, not a variable.

    10  INPUT "Enter something>", A$
    20  PRINT A$


  -> INPUT varA$, varB$, ...

  Shows the default prompt and reads input from the user, splits it at commas,
  and saves it into varA$, varB$, ...

    10  INPUT A$, B$, C$
    20  PRINT A$, B$, C$


  -> INPUT "prompt", varA$, varB$, ...

  Shows prompt$ and reads input from the user, splits it at commas, and saves
  it into varA$, varB$, ... Note that the prompt must be a string literal, not
  a variable.

    10  INPUT "Enter something>", A$, B$, C$
    20  PRINT A$, B$, C$


  -> INPUT FileNo, var$

  Reads a line from an open file and saves it into var$

    10  INPUT# 1, A
    20  PRINT A


  -> INSTR(string$, search$, startPos)

  Returns the position (starting with 0) of a substring within a string

    10  TEXT$ = "Hello World"
    20  SEARCHFOR$ = "W"
    30  PRINT INSTR(TEXT$, SEARCHFOR$, 0)

     6


  -> INT (n)

  Truncate a value to a whole number

    10  PRINT INT(5.6)

     5


  -> ITM(fileNumber)

  Returns the number of the data item currently pointed to in the current
  record of file fileNumber.
  In TeleBASIC this will almost always be 1.

    10  PRINT #1;A,B,C
    20  READ #1,1;A
    30  PRINT REC(1),ITM(1)

     1            2


  -> LEFT$(s$, n)

  Returns the leftmost n characters of the specified string s$

    10  A$ = "Hello World"
    20  B$ = LEFT$(A$, 5)
    30  PRINT B$

    Hello


  -> LEN(s$)

  Returns the number of characters in the specified string

    10  A$ = "Hello World"
    20  PRINT LEN(A$)

     11


  -> LET Variable = Value

  Assigns a value to a variable.  Traditionally this is for use with
  constants, which are not supported in TeleBASIC, and so LET is superfluous.

    10  LET A = 12345
    20  PRINT A

     12345


  -> LIN(n)

  Returns n newlines

    10  PRINT "A" LIN(2) "B"

    A

    B


  -> LOCATE y, x

  Change the cursor position to y, x

    10  LOCATE 5, 5


  -> LOG(n)

  Returns the natural logarithm of n using Euler's Number
  (https://en.wikipedia.org/wiki/E_(mathematical_constant)) as the base

    10  PRINT LOG(6)

     1.792


  -> LOG10(n)

  Returns the natural logarithm of n using 10 as the base (decimal).

    10  PRINT LOG10(6)

     0.778


  -> MID$(s$, n, [l])

  Returns a string of l characters from s$ beginning with the nth character

    10  A$ = "Hello World"
    20  PRINT MID$(A$,3,3)

    llo


  -> NINT(n)

  Returns the nearest integer of the specified value (9.5 becomes 9)

    10  PRINT NINT(5.6)

     6


  -> NUM(s$)

  Returns the ASCII value of the first character in the string s$

    10  PRINT NUM("A")

     65

  See also ASC


  -> OCT$(n)

  Returns the octal value of n

    10  PRINT OCT$(66)

     102


  -> OPEN filename$, AS fileNumber

  Opens a file

    10  OPEN "filename.txt", AS #1


  -> ON NUMBER%

  Jump conditionally with GOTO/GOSUB, based on value given

     10  NUMBER% = 2
     20  ON NUMBER% GOTO 100,200,300
    100  PRINT "Goto 100, will NOT jump here" : END
    200  PRINT "Goto 200, will jump here" : END
    300  PRINT "Goto 300, will NOT jump here" : END

    Goto 200, will jump here


  -> PCLEAR0

  Currently not implemented, does nothing


  -> PCLEAR1

  Currently not implemented, does nothing


  -> PEEK(n)

  Read a value from the specified memory location n

    10  PRINT PEEK(1300)

     83


  -> PLAY

  Currently not implemented, does nothing


  -> PMODE0

  Currently not implemented, does nothing


  -> POKE n, m

  Write a byte of data m into the specified memory location n

    10  POKE 1300, 255


  -> POLKEY$(n)

  Returns one character read from the terminal. When no key is hit within n
  seconds, it returns the empty string

    10  A$ = POLKEY$(5)
    20  REM This will wait 5 seconds, waiting for user input
    30  PRINT A$


  -> PORT%

  Returns the port from the currently logged in user.  Not to be confused with
  the current socket (e.g 23 for telnet)

    10  PRINT USER$ + " is logged in on port: " + STR$(PORT%)


  -> POS(s1$,s2$)

  Returns the position of s2$ in s1$ indexed from 1, or 0 if not found

    10  A$="ABCDE"
    20  PRINT POS(A$,"CD")

     3


  -> PRINT expression

  Prints an expression to the screen

    10  A = 5
    20  B = 10
    30  PRINT A + B

     15

    10  A$ = "Hello "
    20  B$ = "World"
    30  PRINT A$;
    40  PRINT B$
    50  PRINT A$ + B$
    60  PRINT A$ B$

    Hello World
    Hello World
    Hello World

  & and ? are available aliases for PRINT

  Adding a ; at the end of PRINT will suppress the newline


  -> PRINT #fileNumber[,recordNumber]; expression

  Prints a expression into an open file, with optional record (line) number

    10  OPEN "myfile.txt", AS #1
    20  PRINT# 1, "Hello world"
    30  CLOSE #1


  -> PRINT #fileNumber[,recordNumber];END

  Prints an EOF mark to a file, truncating the file at that record

    10  PRINT #1;A$
    20  PRINT #1,1;"Overwriting A$ in record 1"
    30  PRINT #1,1;END : REM Truncates file at record 1

  Observe the placement of the # in PRINT, AS, and CLOSE statements in the
  above examples


  -> PUT

  Currently not implemented, does nothing


  -> R2D(n)

  Converts n radians to degrees

    10  PRINT R2D(1.2)

     68.755


  -> READ n...

  Read a value from DATA or a file and assign them to variables

    10  DATA 4.1, 5.6, 9.98
    20  READ A, B, C
    30  PRINT A, B, C

     4.100          5.600          9.980


  -> READ #fileNumber[,recordNumber];variables

  Read a value from DATA or a file and assign them to variables

    10  READ #1;A$
    20  READ #1,4;B$


  -> REC(n)

  Returns the current record number (line number) in the specified file.
  Starts at 1

    10  OPEN "telehack.txt", AS #1
    20  INPUT# 1, DUMP$
    30  INPUT# 1, DUMP$
    40  INPUT# 1, DUMP$
    50  PRINT REC(1)
    60  CLOSE #1

     3


  -> RENUMBER [start,[inc]]

  Renumbers the statements of the current program in memory. When optional
  parameters are not specified, number starts at 10 and increments by 10 for
  each line. Can be abbrieviated to REN or RENUM. Useful if you want to add
  more lines between existing statements

    >1 GOTO 2
    >2 END
    >REN
    >LIST

       10  GOTO 20
       20  END


  -> RESTORE

  Allow DATA statements to be reread

    10  DATA 4.1, 5.6, 9.98
    20  READ A, B, C
    30  PRINT A, B, C
    40  RESTORE
    50  READ A, B, C
    60  PRINT A, B, C

     4.100          5.600          9.980
     4.100          5.600          9.980


  -> RETURN

  Return from a subroutine, for use with GOSUB.

    10  GOSUB 30
    20  END
    30  PRINT "Hello"
    40  RETURN

    Hello


  -> RIGHT$(s$, n)

  Returns the rightmost n characters of the specified string s$

    10  A$ = "Hello World"
    20  PRINT RIGHT$(A$, 5)

    World


  -> RND(n)

  If n < 0, returns a random number in the interval [0, 1] seeded by n

  If n = 0, returns a random number in the interval [0, 1]

  If n > 0, returns a random number in the interval [0, n]

    10  PRINT RND(-5)
    20  PRINT RND(0)
    30  PRINT RND(5)

     0.249
     0.912
     2.376


  -> SCRATCH

  Delete a file from the disk

    10  SCRATCH "FOOBAR.TXT"

      ARE YOU SURE? Y/n y
      FOOBAR.TXT removed.

  Any input that is not Y (case insensitive) will cancel the operation.

  Runs silently when run with variable assignment, i.e will not prompt for
  confirmation

    10  PRINT "HELLO"
    20  SCRATCH "FOOBAR.TXT" ; FOO$
    30  PRINT "WORLD"

    HELLO
    WORLD


  -> SCREEN

  Currently not implemented, does nothing


  -> SGN(n)

  Returns the sign of the specified value n

    10  PRINT SGN(5)
    20  PRINT SGN(0)
    30  PRINT SGN(-7)

     1
     0
     -1


  -> SIN(n)

  Returns the trigonometric sine of the specified value n in radians

    10  PRINT SIN(36)

     -0.991778853443116


  -> SLEEP n

  Pauses the program for n seconds

    10  SLEEP 5


  -> SOUND

  Currently not implemented, does nothing


  -> SOUNDRND

  Currently not implemented, does nothing


  -> SPACE$(n), SPC$(n), SPA(n)

  Returns n spaces

    10  PRINT "ABC" SPACE$(10) "ABC"

    abc          abc


  -> SQR(n)

  Returns the square root of n

    10  PRINT SQR(36)

     6


  -> STOP

  Halts the program and prints the current line.  Useful for debugging
  programs


  -> STR$(n)

  Returns n as a string value

    10  PRINT STR$(12345)

    12345


  -> STRING$(n, s$)

  Repeats the string s$ n times

    10  PRINT STRING$(10, "A")

    AAAAAAAAAA


  -> TAB(n), TAB$(n)

  Returns n spaces (not tabs!)

    10  PRINT "ABC" TAB$(10) "ABC"

    abc          abc


  -> TAN(n)

  Returns the trigonometric tangent of the specified value n in radians

    10  PRINT TAN(38)

     0.310


  -> TH_SYSLEVEL

  Returns the user's Telehack system level.  Optionally takes a username as
  argument.

    10  PRINT TH_SYSLEVEL
    20  PRINT TH_SYSLEVEL("quantx")

     12
     81

  The user executing the above code would evidently have 12 badges.


  -> TH_HASBADGE(badge$)

  Returns a UNIX timestamp of when the user earned badge$, or 0

    10  PRINT TH_HASBADGE("ACCT")

     1559673339

    10  PRINT TH_HASBADGE("ACCT", "doesntexist")

     0


  -> TH_HASLOGIN(host$)

  Returns 1 if the user has login on host$, otherwise 0

    10  PRINT TH_HASLOGIN("mimsy")

     1

    10  PRINT TH_HASLOGIN("ames")

     0


  -> TH_HASROOT(host$)

  Returns 1 if the user has root on host$, otherwise 0

    10  PRINT TH_HASROOT("mimsy")

     1

    10  PRINT TH_HASROOT("ames")

     0


  -> TH_HASSYSOP(bbs$)

  Returns 1 if the user has sysop on bbs$, otherwise 0

    10  PRINT TH_HASSYSOP("maccavern")

     1

    10  PRINT TH_HASSYSOP("illuminati")

     0


  -> TH_HASADMIN(sat$)

  Returns 1 if the user has admin on sat$, otherwise 0

    10  PRINT TH_HASADMIN("sat_BT 5")

     1


  -> TH_DEFGROUP$

  Returns the user's defgroup, separated by spaces

    10  PRINT TH_DEFGROUP$

     archer lorelei


  -> TH_PLAN$

  Returns the user's .plan as a string

    10  PRINT TH_PLAN$

      To write a BASIC program
      <3


  -> TH_TIME

  Returns the current UNIX timestamp

    10  PRINT TH_TIME

     1675018633.67413


  -> TH_LOCALTIME[$]

  Returns a human-readable local time for the given UNIX timestamp.

    10  PRINT TH_LOCALTIME$(TH_TIME)

    Wednesday, December 9, 2020 6:40:49 PM PST

  Returns values of time and date if options are supplied, and no sigil:

  * 0 - sec
  * 1 - min
  * 2 - hour
  * 3 - mday
  * 4 - mon
  * 5 - year
  * 6 - wday
  * 7 - yday
  * 8 - isdst

    10  FOR I = 0 TO 8 : PRINT TH_LOCALTIME(I,0) : NEXT I

     0
     0
     16
     31
     11
     69
     3
     364
     0


  -> TH_GMTIME[$]

  Returns a human-readable UTC time for the given UNIX timestamp with the same
  options as TH_LOCALTIME[$]


  -> TH_MODEM$

  Returns modem information depending on option passed:

  * 0 number
  * 1 filename
  * 2 hostname
  * 3 description
  * 4 baud rate
  * 5 administrator
  * 6 location


  -> TH_HOSTNAME$

  Returns current hostname or hostname of argument passed.  Supports OSPROBER
  plugin.

    10  PRINT TH_HOSTNAME$

    telehack


  -> TH_NETSTAT$

  Returns current netstat, or netstat of hostname passed as argument,
  separated by spaces

    adaptex cotds mimsy oddjob oracle tandem veritas


  -> TH_MD5HEX$

  Returns md5 hex of argument passed as hex

    10  PRINT TH_MD5HEX$("FOO")

    901890a8e9c8cf6d5a1a542b229febff


  -> TH_MD5BASE64$

  Returns md5 hex of argument passed as base64

    10  PRINT TH_MD5BASE64$("FOO")

    kBiQqOnIz21aGlQrIp/r/w


  -> TH_B64E$

  Returns argument encoded to base64

    10  PRINT TH_B64E$("Telehack")

    VGVsZWhhY2s=


  -> TH_B64D$

  Returns argument decoded from base64

    10  PRINT TH_B64D$("VGVsZWhhY2s=")

    Telehack


  -> TH_EXEC

  Executes a shell command and returns to the current BASIC program

    10  TH_EXEC "echo foo" : TH_EXEC "echo bar"

    foo
    bar

    10  TH_EXEC "fnord", OUT$ : PRINT OUT$

    The iguana from Austin will go to Austin.

  Note: variables assigned with TH_EXEC will have trailing CRLF characters,
  much like back-ticks in bash scripts.


  -> TH_RE(txt$,pat$,countmode,ignorecase)

  Number context, returns a boolean (1 or 0) depending on regex match

    10  IF TH_RE( "hello", "l{2}" ) THEN PRINT "it matches"

    it matches

  If countmode is true, returns number of matches:

    10  PRINT TH_RE( "HELLO", "L", 1 )

     2


  -> TH_RE$(txt$,pat$,ind,ignorecase)

  String context, returns single captured group of match

    10  PRINT TH_RE$( "hello world", "he\w+" )

    hello

  If an index n is provided, the string returned will be the nth captured
  group:

    10  PRINT TH_RE$( "FOO BAR BAZ BINGO BANGO", "BA...", 2 )

    BANGO

  In the above example, the match returned is not "BAZ B", since the "B" in
  "BAZ" has already been consumed by the first match.

  If the index supplied is 0, it will return the final match.  If no index is
  supplied, it will return the first match.


  -> TH_REV$(s$)

  Returns the string s$ in reverse order

    10  PRINT TH_REV$( "deliver" )

    reviled


  -> TH_SED$(txt$,find$,replace$,opt$)

  Stream editor, replaces matched substring with substitution

  Available options:

  * "i" = case insensitive
  * "g" = global mode

    10  PRINT TH_SED$( "foo bAR", "oo|ar", "izz", "gi" )

    fizz bizz


  -> TH_SPRINTF$(fmt$,[...])

  Returns a formatted string based on given parameters:

  * %% - A percent sign
  * %c - A character with the given decimal number
  * %s - A string of characters
  * %S - A string of characters, left aligned
  * %d - A signed integer, in decimal
  * %b - An unsigned integer, in binary
  * %u - An unsigned integer, in decimal
  * %o - An unsigned integer, in octal
  * %x - An unsigned integer, in hexadecimal
  * %a - Hexadecimal floating point
  * %n - Interprets width as positional index (see example 2)
  * %r - Returns a random value from the list as a string
  * %e - A floating-point number, in scientific notation
  * %f - A floating-point number, in fixed decimal notation
  * %g - A floating-point number, in %e or %f notation
  * %h - A floating-point number, in IEEE-754 notation
  * %i - Exactly like %d, for compatibility, or something
  * %y - Returns the decimal form of a hexadecimal unsigned int value
  * %z - Returns decimal form of IEEE-754 input value
  * %D - Like %d, but longer
  * %U - Like %u, but longer
  * %O - Like %o, but longer
  * %F - Like %f, but longer
  * %B - Like %b, but LOUDER
  * %R - Like %r, but left-aligned
  * %X - Like %x, but using upper-case letters
  * %E - Like %e, but using an upper-case "E"
  * %G - Like %g, but with an upper-case "E" (if applicable)
  * %H - Like %h, but using upper-case letters
  * %A - Like %a, but using upper-case letters


  --> Example 1:

    10  F$ = "%s likes to %s while %sing"
    20  PRINT TH_SPRINTF$( F$, "Sam", "sing", "cook" )
    30  PRINT TH_SPRINTF$( F$, "Izumi", "read", "relax" )
    40  PRINT TH_SPRINTF$( F$, "Wumpus", "tood", "tood" )

    Sam likes to sing while cooking
    Izumi likes to read while relaxing
    Wumpus likes to tood while tooding


  --> Example 2:

    10  PRINT TH_SPRINTF$( "%2n%1n%1n", "na", "Ba" )

    Banana


  --> Example 3:

    10  PRINT TH_SPRINTF$("%42R...YOU LOSE","HEADS","TAILS")

    TAILS                                     ...YOU LOSE


  --> Example 4:

    10  F$ = "I got %08b problems but leading zeros ain't %08b."
    20  PRINT TH_SPRINTF$( F$, 99, 1 )

    I got 01100011 problems but leading zeros ain't 00000001.


  --> Example 5:

    10  DATA "Name", "Car", "Country"
    20  DATA "----", "---", "-------"
    30  DATA "Bill", "Volvo", "New Zealand"
    40  DATA "Alex", "Ferrari", "Italy"
    50  DATA "Wumpus", "Tesla", "United States"
    60  FOR I = 1 TO 5
    70  READ A$, B$, C$
    80  PRINT TH_SPRINTF$("%10S%12S%12S", A$, B$, C$)
    90  NEXT I

    Name      Car         Country
    ----      ---         -------
    Bill      Volvo       New Zealand
    Alex      Ferrari     Italy
    Wumpus    Tesla       United States


  -> TH_STATUS$

  Returns the user's status as a string


  -> TH_UUD$(s$)

  Decodes a uuencoded string

    10  PRINT TH_UUD$("#9F]O")

    foo


  -> TH_UUE$(s$)

  Returns uuencoded form of input string

    10  PRINT TH_UUE$("foo")

    #9F]O


  -> TIM(n)

  Returns values of time and date depending on n

  * 0 - Current minute (0-59)
  * 1 - Current hour (0-23)
  * 2 - Current day (1-366)
  * 3 - Current year (0-99)
  * 4 - Current second (0-59)

    10  PRINT TIM(0)

     29


  -> TIME$

  Returns the local system time

    10  PRINT TIME$

    07:49:38


  -> TIMER

  Returns the number of seconds since midnight

    10  PRINT TIMER

     28210


  -> TYP(n)

  Returns the type of the next record in a file

  Return values:

  * 1 - Numeric data (not currently working)
  * 2 - String data
  * 3 - End of file

     10  REM CREATE A FILE FOR TESTING
     20  FILENAME$ = "TEST" + STR$(INT(RND(1)*128*2)) + ".TXT"
     30  OPEN FILENAME$, AS #1
     40  REM POPULATE FILE WITH TEST DATA
     50  PRINT# 1, "some text"
     60  REM SAVE FILE
     70  CLOSE #1
     80  REM TEST TYP() COMMAND
     90  OPEN FILENAME$, AS #1
    100  PRINT TYP(1)
    110  REM ADVANCE ONE RECORD
    120  INPUT# 1, DUMP$
    130  PRINT TYP(1)
    140  CLOSE #1

     2
     3

  See also EOF.


  -> TROFF

  Stops tracing of program statements.  Useful for debugging


  -> TRON

  Starts tracing of program statements.  Useful for debugging


  -> UPS$(string)

  Returns the uppercase value of the given string

    10  PRINT UPS$("hello")

    HELLO


  -> USER$

  Returns the current logged in user

    10  PRINT USER$

    archer


  -> VAL(s$)

  Returns the numeric value of s$

    10  PRINT VAL("12345")

     12345


  -> WIDTH

  Returns your terminal width


  > 6. FAQ


  -> Q: I need a NAND function, but there is none.

  A: Create the function with:

    DEF FNNAND( A, B ) = NOT ( A AND B )

  Now you can call it with:

    10  PRINT FNNAND( 0, 0 )

     1


  -> Q: How do I read from a file?

  A: Like this:

    10  OPEN "filename.txt", AS #1
    20  IF EOF(1) THEN GOTO 60
    30  INPUT# 1, A$
    40  PRINT A$
    50  GOTO 20
    60  CLOSE #1


  -> Q: How do I write to a file?

  A: Like this:

    10  OPEN "filename.txt", AS #1
    20  PRINT# 1, "Hello World!"
    30  CLOSE #1


  -> Q: How do I append a file?

  A: You have to open the file and put the file-pointer at the end of file,
  like this:

    10  OPEN "filename.txt", AS #1
    20  IF EOF(1) THEN GOTO 50
    30  INPUT# 1, DUMP$
    40  GOTO 20
    50  PRINT# 1, "We are now at the EOF, and appending stuff"
    60  CLOSE #1

  A2: The solution above (linear search) is somewhat slow for large files.
  Exponential search (https://en.wikipedia.org/wiki/Exponential_search) is
  more complicated, but finds the end of a 10000-line file in ~0.03 seconds
  instead of ~31.6 seconds (1000x faster). Below is an example subroutine:

    10 OPEN "filename.txt", AS #1
    20 GOSUB 250 : 'probe now points to the last line, but file pointer DOES
  NOT NECESSARILY.
    30 READ #1, probe; lastline$ : 'advance file pointer to probe
    40 PRINT# 1, "We are now at EOF, and appending stuff"
    50 PRINT "The previous last line", lastline$
    60 CLOSE 1
    200 END

    250 probe=2 : DIM last(2) : last(0)=0 : last(-1)=2^52-1
    255 '(0) is last good line , (-1) is last bad line (EOF), initialized to
  max int
    260 READ #1, probe
    265 ' read record at index (probe) from file #1, but not into any
  variables.
    266 ' this is slightly faster than input#.
    270 last(EOF(1)) = probe
    275 'store the probed offset as either good or bad, depending on whether
  we hit EOF or not.
    280 x = probe*2 : y = last(0) + INT((last(-1)-last(0))/2) : 'Exponential
  search for EOF
    285 'halfway between last known good and last EOF (binary search)
    290 probe = y XOR ((x XOR y) AND -(x < y))
    295 ' probe = min(x,y); picks binary search when probe overshoots
    300 IF probe > last(0) GOTO 260
    305 ' probe>good implies (bad-good)/2>=1 implies EOF may lie beyond good+1;
  keep probing.
    310 RETURN


  -> Q: How do I create a BBS?

  A: You can create a BBS by running PPPD.EXE, and pointing it at your BASIC
  program file. Your BBS will then appear in bbslist.txt.

  Your BBS baud-rate must be 115200 (11.520 kbps) in order for it to appear in
  the Telehack netstat.  To gain access to faster baud-rates requires you to
  upgrade your modem firmware (both SYSADM and BLUEBOX badges are required.)


  -> Q: How do I split a string into an array?

  A: There are two methods. The Traditional "Pure BASIC" Method, and the
  Modern RegEx Method.  Both methods are detailed below.


  --> Traditional "Pure BASIC" Method

  This method involves iterating through your string YOURSTRING$ and looking
  for a delimiter DELIMITER$.

  For every iteration put the actual character at that position in the string
  YOURSTRING$ in a temporary variable TSTR$.

  Once you have found the delimiter DELIMITER$, save the result of the
  temporary variable TSTR$ into an array. MAXSTACK tells you how many items
  are actually in the array.

  See the example below:

     10  DIM ARRAY$(2)
     20  DELIMITER$ = " "
     30  YOURSTRING$ = "Hello World"
     40  MAXSTACK = 0
     45  REM PUT YOUR PROGRAM LOGIC HERE
     50  GOSUB 100
     55  REM PUT YOUR PROGRAM LOGIC HERE
     60  END
    100  REM split
    110  TSTR$ = ""
    120  FOR I = 1 TO LEN(YOURSTRING$)
    130  IF MID$(YOURSTRING, I, 1) = DELIMITER$ THEN GOTO 200
    140  TSTR$ = TSTR$ + MID$(YOURSTRING$, I, 1)
    150  IF I = LEN(YOURSTRING$) THEN GOTO 200
    160  NEXT I
    170  RETURN
    200  REM We have found a delimiter and are pushing it into the array
    210  MAXSTACK = MAXSTACK + 1
    220  ARRAY$(MAXSTACK) = TSTR$
    230  TSTR$ = ""
    240  GOTO 160


  --> Modern RegEx Method

  Let's say, for this example, you have the string NAMES$ which is a list of
  names separated by a comma ,.  To access this as an array is very
  straightforward using Telehack language extentions:

    10  NAMES$ = "Tom,Dick,Harry,Bob,Steve,Imhotep"
    20  PATTERN$ = "[^\,]+"
    30  FOR I = 1 TO TH_RE(NAMES$,PATTERN$,1)
    40  PRINT TH_RE$(NAMES$,PATTERN$,I)
    50  NEXT I

    Tom
    Dick
    Harry
    Bob
    Steve
    Imhotep

  The above example uses both TH_RE (number context), and TH_RE$ (string
  context).


  -> Q: How can I learn how to write regular expressions?

  A: The executable GOLF.EXE contains multiple lessons on regular expressions.
  You can also find many RegEx-related challenges in the DOJO.


  -> Q: How do I generate a random number?

  A: Like this:

    10  RANDOMIZE TIMER
    20  MAXNR = 10
    20  RNR = INT(RND(1)*MAXNR)
    30  PRINT RNR

  The above example is a pseudorandom number generator, with TIMER being the
  seed.


  -> Q: I would like to code in BASIC, but all those line numbers are messy!

  A: You don't actually have to use line numbers at all in TeleBASIC!  They
  are only necessary for when using GOTO or GOSUB.

  You also don't have to put everything in uppercase, but doing so means your
  code will be more compatible with other historical flavours of BASIC.

  Here is an example of a modern TeleBASIC program:

    1 ' begin

    input "What is your name? " n$
    print "Hello, " n$ "! There are" len( n$ ) "characters in your name:"

    for l = 1 to len( n$ )
        ? l ": " mid$( n$, l, 1 )
    next : ?

    input "Again? [y/n] " ; yn$
    if yn$ = "y" then goto 1

    ? "Goodbye!"
    end

    What is your name? bob
    Hello, bob! There are 3 characters in your name:
     1 : b
     2 : o
     3 : b

    Again? [y/n] y
    What is your name? steve
    Hello, steve! There are 5 characters in your name:
     1 : s
     2 : t
     3 : e
     4 : v
     5 : e

    Again? [y/n] n
    Goodbye!


  Additionally, there is a script written by archer which allows you to use
  labels instead of numbers.

  Find it on archer's GitHub (https://p85.github.io/renumber/renumber.html).


  -> Q: How do I use COMM.EXE via BASIC?

  A: Refer to this guide by archer (https://telehack.com/r/pvELT).


  -> Q: What's with the fish?

  A: That's our mascot, Bassy the dart-mouthed bass.


  > 7. ANSI Escape Sequences


  -> General Info

  An ANSI escape sequence is a sequence of ASCII characters, the first two of
  which are the ASCII "escape" character (chr$(27)) and the left-bracket
  character [ (chr$(91)).

  The character or characters following the escape and left-bracket characters
  specify an alphanumeric code that controls a keyboard or display function.

  For example, these can be used instead of, or in addition to LOCATE (for
  locating the cursor in the window); COLOR (for setting text and background
  colours) and getting the user's arrow-key input.

  Using escape sequences can give you greater control over how your program
  displays its output.  Be aware that not all terminal types support some of
  these sequences, and your terminal must support 256-bit colours in order to
  display such colours.

  Standard escape codes are prefixed with Escape, which is represented in the
  following ways:

      FORMAT    | VALUE
  --------------+---------
    Ctrl-Key    | ^[
    Octal       | \033
    Unicode     | \u001b
    Hexadecimal | \x1b
    Decimal     |     27

  This is then followed by the command, somtimes delimited by opening square
  bracket [ known as a Control Sequence Introducer (CSI), optionally followed
  by arguments and the command itself.

  Arguments are delimeted by semi colon (;).

  For example boldred$ = chr$(27) + "[1;31m".


  -> General ASCII Codes

    NAME | DECIMAL | OCTAL | HEX  | C-ESCAPE | CTRL-KEY |   DESCRIPTION
  -------+---------+-------+------+----------+----------+-------------------
    BEL  |       7 |   007 | 0x07 | \a       | ^G       | Terminal bell
    BS   |       8 |   010 | 0x08 | \b       | ^H       | Backspace
    HT   |       9 |   011 | 0x09 | \t       | ^I       | Horizontal TAB
    LF   |      10 |   012 | 0x0A | \n       | ^J       | Linefeed
    VT   |      11 |   013 | 0x0B | \v       | ^K       | Vertical TAB
    FF   |      12 |   014 | 0x0C | \f       | ^L       | Formfeed
    CR   |      13 |   015 | 0x0D | \r       | ^M       | Carriage return
    ESC  |      27 |   033 | 0x1B | \e       | ^[       | Escape character
    DEL  |     127 |   177 | 0x7F | <none>   | <none>   | Delete character

  Note: Some control escape sequences, like \e for ESC, are not guaranteed to
  work in all languages and compilers. It is recommended to use the decimal,
  octal or hex representation as escape code.

  The Ctrl-Key representation is simply associating the non-printable characters
  from ASCII code 1 with the printable characters from ASCII code 65 ("A").
  ASCII code 1 would be ^A (Ctrl-A), while ASCII code 7 (BEL) would be ^G (Ctrl-
  G). This is a common representation (and input method) and historically
  comes from one of the VT series of terminals.


  -> Cursor Controls

          SEQUENCE       |          DESCRIPTION
  -----------------------+---------------------------------
    ESC[H                | Moves cursor to home position
                         | (0, 0)
    ESC[{line};{column}H | Moves cursor to line #, column
                         | #
    ESC[{line};{column}f | Moves cursor to line #, column
                         | #
    ESC[#A               | Moves cursor up # lines
    ESC[#B               | Moves cursor down # lines
    ESC[#C               | Moves cursor right # columns
    ESC[#D               | Moves cursor left # columns
    ESC[#E               | Moves cursor to start of next
                         | line, # lines down
    ESC[#F               | Moves cursor to start of
                         | previous line, # lines up
    ESC[#G               | Moves cursor to column #
    ESC[6n               | Request cursor position
                         | (reports as ESC[#;#R)
    ESC7                 | Save cursor position (DEC)
    ESC8                 | Restores the cursor to the
                         | last saved position (DEC)
    ESC[s                | Save cursor position (SCO)
    ESC[u                | Restores the cursor to the
                         | last saved position (SCO)
    ESC[?25h             | Show cursor
    ESC[?25l             | Hide cursor

  Note: Some sequences, like saving and restoring cursors, are private
  sequences and are not standardized. While some terminal emulators (i.e.
  xterm and derived) support both SCO and DEC sequences, they are likely to
  have different functionality. It is therefore recommended to use DEC
  sequences.


  -> Erase Functions

    SEQUENCE |          DESCRIPTION
  -----------+---------------------------------
    ESC[J    | Clears the screen
    ESC[0J   | Clears from cursor until end
             | of screen
    ESC[1J   | Clears from cursor to
             | beginning of screen
    ESC[2J   | Clears entire screen
    ESC[K    | Clears the current line
    ESC[0K   | Clears from cursor to end of
             | line
    ESC[1K   | Clears from cursor to start of
             | line
    ESC[2K   | Clears entire line


  -> Colours / Graphics Mode / Character Attributes

       SEQUENCE     | RESET SEQUENCE |          DESCRIPTION
  ------------------+----------------+---------------------------------
    ESC[1;34;{...}m |                | Set graphics modes for cell
    ESC[m           |                | Reset all modes (styles and
                    |                | colours)
    ESC[0m          |                | Same as above
    ESC[1m          | ESC[22m        | Set bold mode.
    ESC[2m          | ESC[22m        | Set dim/faint mode.
    ESC[3m          | ESC[23m        | Set italic mode.
    ESC[4m          | ESC[24m        | Set underline mode.
    ESC[5m          | ESC[25m        | Set blinking mode
    ESC[7m          | ESC[27m        | Set inverse/reverse mode
    ESC[8m          | ESC[28m        | Set hidden/invisible mode
    ESC[9m          | ESC[29m        | Set strikethrough mode.

  Note: Some terminals may not support some of the graphic mode sequences
  listed above.

  Both dim and bold modes are reset with the ESC[22m sequence. The ESC[21m
  sequence is a non-specified sequence for double underline mode and only works
  in some terminals and is reset with ESC[24m.


  -> Colour Codes

  Most terminals support 8 and 16 colours, as well as 256 (8-bit) colours.
  These colours are set by the user, but have commonly defined meanings.


  --> 8-16 Colours

    COLOUR  | FOREGROUND | BACKGROUND
  ----------+------------+-------------
    Black   |         30 |         40
    Red     |         31 |         41
    Green   |         32 |         42
    Yellow  |         33 |         43
    Blue    |         34 |         44
    Magenta |         35 |         45
    Cyan    |         36 |         46
    White   |         37 |         47
    Default |         39 |         49
    Reset   |          0 |          0

  Note: the Reset colour is the reset code that resets all colours and text
  effects, Use Default colour to reset colours only.

  Most terminals, apart from the set of 8 regular colours, also support the
  "bright" or "bold" colours. These have their own set of codes, mirroring the
  normal colours, but with an additional ;1 in their codes:

      e$ = chr$(27)

    ' Set style to bold, red foreground
      hello$ = e$ + "[1;31m" + "Hello"

    ' Set style to dimmed white foreground with red background
      world$ = e$ + "[2;37;41m" + "World"

  Terminals that support the aixterm specification provide bright versions of
  the ISO colours, without the need to use the bold modifier:

        COLOUR     | FOREGROUND | BACKGROUND
  -----------------+------------+-------------
    Bright Black   |         90 |        100
    Bright Red     |         91 |        101
    Bright Green   |         92 |        102
    Bright Yellow  |         93 |        103
    Bright Blue    |         94 |        104
    Bright Magenta |         95 |        105
    Bright Cyan    |         96 |        106
    Bright White   |         97 |        107


  --> 256 Colours

  The following escape codes tells the terminal to use the given colour:

       SEQUENCE    |      DESCRIPTION
  -----------------+------------------------
    ESC[38;5;{ID}m | Set foreground colour
    ESC[48;5;{ID}m | Set background colour

  Where ID should be replaced with the colour index from 0 to 255 of the
  following colour chart:

  Generate this table with the following BASIC code:

    10  FOR I = 0 TO 255
    20  S$ = TH_SPRINTF$( "%4S", I )
    30  ? CHR$(27) "[38;5;" STR$(I) "m" S$ ;
    40  IF NOT (I+1) MOD 16 THEN ?
    50  NEXT

  This table starts with the original 16 colours (0-15).

  The proceeding 216 colours (16-231) are formed by a 3bpc RGB value offset by
  16, packed into a single value.

  The final 24 colours (232-255) are grayscale starting from a shade slighly
  lighter than black, ranging up to shade slightly darker than white.

  Some emulators interpret these steps as linear increments (256 / 24) on all
  three channels, although some emulators may explicitly define these values.


  --> RGB Colours

  More modern terminals supports Truecolor (24-bit RGB), which allows you to
  set foreground and background colours using RGB values.

  These escape sequences are usually documented poorly, if at all.

          SEQUENCE        |          DESCRIPTION
  ------------------------+--------------------------------
    ESC[38;2;{r};{g};{b}m | Set foreground colour as RGB.
    ESC[48;2;{r};{g};{b}m | Set background colour as RGB.

  Note: ;38 and ;48 corresponds to the 16 colour sequence and is interpreted
  by the terminal to set the foreground and background colour respectively,
  whereas ;2 and ;5 sets the colour format.


  -> Common Private Modes

  These are some examples of private modes, which are not defined by the
  specification, but are implemented in most terminals.

     SEQUENCE  |          DESCRIPTION
  -------------+---------------------------------
    ESC[?25l   | Make cursor invisible
    ESC[?25h   | Make cursor visible
    ESC[?47l   | Restore screen
    ESC[?47h   | Save screen
    ESC[?1049h | Enables the alternative buffer
    ESC[?1049l | Disables the alternative
               | buffer


  -> DEC Special Graphics

  DEC Special Graphics is a 7-bit character set developed by Digital Equipment
  Corporation.

  This was used very often to draw boxes on the VT100 video terminal and the
  many emulators, and used by bulletin board software.

    SEQUENCE |         DESCRIPTION
  -----------+-------------------------------
    ESC(0    | Enable DEC special graphics
    ESC(B    | Disable DEC special graphics


  -> Colour Examples (8-bit)

    10  PRINT CHR$(27) + "[92mThe foreground is green" CHR$(27) "[m"
    20  PRINT CHR$(27) + "[103mThe background is yellow" CHR$(27) "[m"


  -> Colour Examples (16-bit)

    10  PRINT CHR$(27) + "[38;5;134mThe foreground is purple" CHR$(27) "[m"
    20  PRINT CHR$(27) + "[48;5;117mThe background is sky blue" CHR$(27) "[m"


  -> Get Arrow Key Input

    10  KEY$ = INKEY$
    20  IF KEY$ = CHR$(27) THEN KEY$ = INKEY$ : IF KEY$ = "[" THEN GOTO 40
    30  GOTO 10
    40  KEY$ = INKEY$
    50  IF KEY$ = "A" THEN PRINT "UP"
    60  IF KEY$ = "B" THEN PRINT "DOWN"
    70  IF KEY$ = "C" THEN PRINT "RIGHT"
    80  IF KEY$ = "D" THEN PRINT "LEFT"
    90  GOTO 10