Welcome to the Teletext Script Interpreter

Welcome to the Script Interpreter

Overview

My teletext software for RISC OS (!Teletext) and Windows (WinTTX) both incorporate a "script interpreter" which allows you to create 'scripts' permitting you to retrieve and process information from teletext. You may fetch frames, perform various operations on them and then store them back in the cache and/or output them in a variety of formats.

By way of example, several scripts are provided with WinTTX:

  • Retrieve the current exchange rates for various currencies (information from Italian broadcaster RAI Uno) and create a textual conversion chart for €5 to €5000.
  • Retrieve the current min/max temperatures and tomorrow's min/max (information from French/German broadcaster arte) and write a textfile with the weather/forecast in °C with a conversion to F, plus copy out the general forecast message (i.e. "Averses").
  • The biggie to beat all biggies. Reads news from BBC World and TV5 and so on, other information from RAI Uno and arte and more. This is all coupled together into a great big OvationPro document (but could easily be HTML instead) which is then autoloaded when it is completed.
    Just fire up WinTTX, let the !startup script get on with it in the background, and when it is done, information for you to read!

These are examples of the sorts of things that can be achieved with the teletext script language.

The script language itself is fairly simple, tailored to exactly what it has been designed for. Thus, it provides a way to pass messages to the user but there is no provision for, say, drawing on the screen. Such a facility would not be useful in processing teletext frames!

RISC OS vs Windows

The current RISC OS version of the interpreter (v1.07 from 2003) is a little earlier than the Windows version (v1.08 from 2008), so several newer commands are not provided in !Teletext. There are no plans at present to update !Teletext, though you could add commands yourself as the source code to the RISC OS version has been released.

Perhaps the main problem that you will encounter is differences in file naming and paths between the two systems. For example, "<Teletext$Pages>.MyPage" would be an invalid filename under Windows, and likewise "whatever.txt would be invalid under RISC OS (translating to "whatever\txt." in Win/DOS terms).

It is possible to write scripts that work equally on both systems. To do so, you should take advantage of the differences between !Teletext which offers channel presets, and WinTTX that expects a UHF channel. This, requesting the channel preset number under WinTTX will always return "-1", as this code demonstrates:

set A to status(channel)
if (A ! -1) goto("riscoscode")

; this stuff is Windows code
[...blah blah - WinTTX specific stuff...]
go("continue")

.riscoscode
; this stuff is RISC OS code
[...blah blah - !Teletext specific stuff...]

.continue
; everybody meets back here

Of course, if you only have the one platform or if you don't mind writing slightly different scripts for each, you can dispense of this and just write using the facilities relevant to your version of the teletext software you are using.

Where relevant, differences between RISC OS and Windows script commands will be noted. There is also a look-up chart of all commands and which versions of the interpreter they may be found within.

The structure of a script file

Script files are plain text files that contain statements to perform an action. With one specific exception, it is strictly one statement per line. To give you an example, consider:
A = 1 * 2 + 5 / 2

That line would set integer variable 'A' to be the result of the calculation. It is, actually, ambiguous as if we are using the rules of precedence, it is "(1 * 2) + (5 / 2)" so the answer would be 4.5 (rounded to 4); but if we read left to right, the answer is 3.5 (rounded to 3).

Such problems are impossible in the teletext script as it does not support that level of calculation. Instead, you would write:

set A to 1          ; A = 1
mul(A, A, 2)        ;   * 2
add(A, 5)           ;   + 5
div(A, A, 2)        ;   / 2
(note we are using the left-to-right interpretation here)

The script file is executed at the beginning, and continues until it reaches a quit() (normal exit), a terminate() (abandon on problem), an error, or reaching the end of the script file.

The primary difference between quit() and terminate() regards the "call stack" - which is described in just a moment. If there is an active call stack when you quit(), you will be warned. If you instead terminate(), there is no such warning. So you should use terminate() when you have to 'just give up'.

Now, you are asking, "what's a call stack?". Well, no language is useful unless it can take jumps. The example above where we determine if the machine is RISC OS or Windows, you see we used the go() command to jump to a label, that is, a line with a name beginning with a '.' character. This is all described in more detail.
Well, we can crank it up a level by jumping to our label using the command call(), and what that does it is pushes our current 'position' in the script into the 'call stack'. We jump to the label, do whatever, and then we'll use the return() command to take the last-saved position off of the call stack and go back there. In this way, simple procedures can be written. You can see an example of this in the weather script - the code to convert celsius to fahrenheit is called is just such a way. Again, this is described in more detail.

Variables

There are 26 variables, from A to Z.
This is divided so the first 16 variables (A to P) are integers that can hold whole numbers like 1, 2, 3... while the final 10 variables (Q to Z) are floats which can hold fractional numbers like 1.23, 7.4367, etc.

INTEGER | FLOAT
A | Q
B | R
C | S
D | T
E | U
F | V
G | W
H | X
I | Y
J | Z
K |
L |
M |
N |
O |
P |
The integer variables are intended to be used for status, page numbers, loop counters... while the floats are intended for calculations such as temperature conversions, currency, and anything where fractional accuracy is desired.

Speaking of accuracy, all floats are constrained to nine decimal places, so that WinTTX and !Teletext running on standard BBC BASIC V (not the FP version) should give the same results; however if you are making comparisons with floating point values, it is always best to flatten() down to the level of accuracy that is actually required.

Strings

There are no string variables or operators. If you need to read strings out of the teletext file, these should be copied byte by byte, using code such as:
set A to 30
.reportloop
  set B to char(A, 17)
  filewritebyte(B)
  A++
  if (A [ 40) go("reportloop")
(this copies the characters from position 30,17 to 40,17.

Where strings are required as input, such as to the userchoice() command, you can:

  • Replace all spaces with the '`' character.
    This is a hangover from the early days of the script interpreter where the space suppression did not cater for quoted strings; it is no longer necessary to do this, however the behaviour is still supported.
  • Use the "\n" sequence to introduce newlines into strings.
  • Use the "\"" sequence to introduce quotes into strings, without messing up the string.
For example:
message("Please set satellite receiver to \"arte\" (channel FAV:29)")

Note that the use of "\n" and "\"" are suppressed in places where filenames are expected.

Note that the RISC OS script interpreter does not support "\n" and "\"".

The view of a teletext frame

The top-left corner of a teletext frame is 1,1, leading to the lower right corner which is 40,25; hence there are 40 character cells across the display, in 25 rows.

One you have retrieved data using getframe() or getframes(), you can use selectframe() or selectframes() to make a cached frame 'current'. Only one frame can be current, but you can switch which is current as you wish, even to the extent of copying from one frame to another byte by byte.

When a frame is 'current', you can read bytes from the frame using set <var> to char(<x>, <y>); and you can write bytes to the frame using setchar().
You can also blank entire lines using omitline() (which has special significance for file output).
When you have made the necessary alterations, you can either write the frame to a file using writeframe() or writeframes(), or you can push the frame back into the cache (replacing the current cached one) using storeframe().

Page numbering

Within the script, page numbering is in 'simple' form. That is, page 101 is specified as page 101.
You should not convert page numbers into their hexadecimal forms...
Some calls exist to read various items in hex, however this is mostly facultative.
Obviously, there is no way for a script to retrieve extended pages (i.e. p3FF).

Script errors

Pretty much everything that causes an error will cause the script to be aborted. Sometimes it can be difficult trying to work out what the error means, so in WinTTX there is an option to perform an automatic LVar upon script error. This creates a status file showing what the script is up to which can be a useful debugging aid.
Under RISC OS, create a RAMdisc (at least 128K) and !Teletext will write a logfile.

Interpretation speed

The script interpreter does not execute quickly. This is because the majority of time is likely to be spent waiting for information to arrive off-air. Under RISC OS, conducting tests with the current arrangement (with polls frequently) and a system where the script was given more priority showed only seconds difference in a script taking nearly ten minutes to run. For those seconds, the system loading was deemed unacceptable - for example the rolling header does not need to be read anywhere like as often as when the viewer is active, either the page has arrived or it hasn't...

Under RISC OS, on a 40MHz ARM710 processor, the teletext software, when in use, loads the system between 15% and 60% (depending on what it is doing), with an average loading of around twenty-thirty percent. When the script is running, this may go up to around forty percent (again depending on what is happening). Some scripts may take in the order of ten minutes to execute.
The system is designed to be used multitasking, where you start a script and then forget about it for a while.
Please note that the timings were taken on my RiscPC700 with Ran Mokady's !Usage, and is subjective to the other tasks running on your system, and the system itself.

There are currently no timings for system loading under Windows; and such assessment is not terribly relevant for I am using a 450MHz machine running XP. It 'feels' comfortable, doesn't drag the machine down. The Windows process scheduling system means that it often seems to me as if other things are holding up WinTTX, rather than the other way around!

Related information


Commands

Script commands

Complete list of commands

Commands marked with † are specific to the Windows interpreter in WinTTX, and are not available in RISC OS.
Commands marked with × are specific to the RISC OS interpreter in !Teletext, and are either not supported or have no effect under Windows.

Please note the differences in file names between the two systems, and also note that quit() has rather different behaviour on RISC OS than Windows.

<blank line>
¤
@ †
;
.
abs
add
and
appendframe
appendframes
appendgivenframe
appendline
cache_coeur †
cache_flush
cache_insertfile
cache_loaddirectory
cache_loadnextentry
call
channel
channelid
[char; via set]
div
eggy ×
eor
error
execfile †
fileclose
fileextn †
filetype ×
fileupdate
filewrite
filewritebyte
filewritefloat
filewritehtmlhead †
filewritehtmltail †
filewriteovnhead
filewriteovntail
filewritestring
filewritevar
find
findany †
findend
flatten
frame_language
frame_linkedto
frame_number
frame_subnumber
getframe
getframes 		go
if
info †
keypress †
lsl
lsr
lvar
message
mod
mul
nop
not
omitline
or
oscall ×
poll_disable ×
poll_enable ×
poll_message ×
poll_nomessages ×
poll_now ×
pushkey ×
quit
readvalue
report_var
return
roundcast
selectframe
selectframes
selfexec
set
setchar
showcachelist ×
showcontrols ×
showpreferred ×
showviewer ×
sign
smartclear
sqr
[status; via set]
storeframe
sub
terminate
userchoice
version
winttx †
xor †
++
--


Program flow

Introduction

A script, like a computer program, starts at the beginning and finishes at the end. However there is a lot more to it than that. Consider:
PRINT "0"
PRINT "1"
PRINT "2"
PRINT "3"
PRINT "4"
PRINT "5"
PRINT "6"
PRINT "7"
PRINT "8"
PRINT "9"

That is one way to print the numbers from 0 to 9. It works, but can you imagine the code to print the alphabet? How much easier it would be to:
FOR num% = 0 TO 9
  PRINT num%
NEXT

What the second example does is to say: Right, we're going to go around and around with our 'num' variable going from zero to nine. This is called a loop, it is a bit like a loop of string, round and round. Each time we will PRINT what our num variable is.
In this way, ten lines of code becomes three. And, better yet, it is possible to output every single printable character - all the numbers, all the letter (upper and lower case), all the symbols, and the extra stuff and accented things - with a mere three lines of code (instead of 223 lines).

That is one aspect of program flow. The second is in making decisions. For example, what if we examine the identity of the currently tuned channel and it is not the channel ID we expect? Do we plough on regardless, or do we get the user to do something? To be able to have this sort of control requires the ability to make decisions; and this is what we shall look at first:

Making decisions

In BASIC, you can do things like:
IF ( (A = 1) AND (B = 2) AND (C = 3) ) THEN ...do something...

You can do this in script by knowing that the if() syntax is:

if( <var> <condition> <number> ) <command>

If the condition evaluates to be true, then the 'command' is executed. There is no reason why the 'command' cannot be another if() command.

So, first, the conditions:
  ! Not equal
  = Equal
  < Less than
  > Greater than
  [ Less than or equal to
  ] Greater than or equal to

All of the following examples evaluate to TRUE, so the command would be executed.

set A to 123
if(A = 123) ...
if(A ! 0) ...
if(A > 12) ...
if(A < 1973) ...
if(A [ 123) ...
if(A ] 123) ...

All of the following evaluate to FALSE. Remember, A is zero at script start.

if(A = 123) ...
if(A ! 0) ...
if(A > 12) ...

You get the idea.

Note that you can compare a float with an integer. 99.4 is less than 100, 103.2 is more...

So, that line of BASIC at the start could be written in our script as:

if(A = 1) if(B = 3) if(C = 3) ...do something...

Now let's assume you have read some data from a teletext frame, and you'd like to convert it. We shall invent an algorythm, where:
result = ( (((input << 3 ) / 4) >> 1) * 5 )
We only want to do this to numbers over 100, but we may be called with numbers less than 100. What we need is an 'if()' spanning several lines.

There are two ways to do this:

The wrong way...

if(Q ] 100) set R to Q
if(Q ] 100) lsl(R, 3)
if(Q ] 100) div(R, R, 4)
if(Q ] 100) lsr(R, 2)
if(Q ] 100) mul(R, R, 5)

The right way...

if(Q < 100) go("skipthisstuff")
  set R to Q
  lsl(R, 3)
  div(R, R, 4)
  lsr(R, 2)
  mul(R, R, 5)

 .skipthisstuff

This leads us on to...

Branching

You have the ability to branch. That means to instruct the script interpreter to jump to another location in the program.

Branches are defined as a period followed by the 'name' of the location. This is called a label, and looks like:

.branchpoint
or:
.mungecode
Labels can contain practically any printable character (except space) as they are treated as strings, however it is best to stick to upper and lower case letters and an underscore. By habit I write my labels as lower-case words run together, however you can use the style you prefer, such as:
.BranchPoint
or:
.munge_code

Under RISC OS, you can define up to sixteen labels. Under Windows, there is no limit.

All defined labels are read when the script is initialised, and subsequently you can use the go() command to jump to a label, to branch.
You can branch forwards or backwards, as all of the labels are already 'known' as the script begins execution.

Recursive code

This means code that loops around. We have already seen this in the FOR...NEXT example, and perhaps a good practical example is code to check we're tuned to the right channel:
message("Please set satellite receiver to \"TV5 FBS\" (channel FAV:46)")
.isittv5
  channelid(A)
  if (A ! &AF00) message("Please set satellite receiver to \"TV5 FBS\" (channel FAV:46)")
  if (A ! &AF00) go("isittv5")

This tactic may seem unusual, however if you think about it, more and more people will be receiving their broadcasts from a set-top box which is either digital terrestrial or digital satellite. These devices will output a multitude of channels on the one UHF 'channel' (or perhaps via a VCR if it can't output UHF by itself). Therefore it is prudent to check the channel ID and ask for a little bit of user interaction.
In any case, the above example will go around and around until the channel ID it reads is &AF00 - hence it is recursive code.

Implementing constructs - FOR...NEXT

In typical BASIC, a FOR...NEXT loop would look like:
FOR x% = 101 TO 109
  PROCget_page(x%)
NEXT

In our teletext script, we can achieve the same thing using recursive code and a loop. The only other complication is that the variable initialise and increment is not performed automatically.

set A to 101
.comebackhere
  getframes(A)
  A++
  if (A < 110) go("comebackhere")

Implementing constructs - DO...WHILE

In typical BASIC, a DO...WHILE loop is a lot like FOR loop, but instead of controlling a variable, we look for a specific event. Here's some fake BASIC:
PRINT "Please select TV5 FBS"
DO
  ch% = FNget_channel_id
WHILE (ch% <> &AF00)

We've already seen this before:

message("Please select TV5 FBS")
.isittv5
  channelid(A)
  if (A ! &AF00) message("Please select TV5 FBS")
  if (A ! &AF00) go("isittv5")

Note that, again, it boils down to recursive code and an IF test.

Implementing constructs - REPEAT...UNTIL

A REPEAT...UNTIL loop is very similar to a DO...WHILE. Indeed, the difference is mainly one of syntax. The DO...WHILE will loop while the clause is still true, like:
DO : Play Cricket : WHILE (It is still sunny)
while the REPEAT...UNTIL will loop until the clause is true, like:
REPEAT : Search for that film you haven't watched : UNTIL (You have found the DVD)

Because of this, there is no point providing an example. You are going to simply have to work out the mechanics of what you are trying to do, and then implement it using an if test and a branch. By doing this, you can implement all sorts of everything, from simple FOR...NEXT loops to SELECT CASE statements. Because of the ability to nest if statements inside other ones, you can arrange some quite complex control structures.

Call/Return

You can raise the bar one degree higher by adding 'procedural calls' to the mix. These look and feel a lot like a simple branch, however where you branched from is remembered so you can return back to that point.
In other words, you can write simple procedures.

By way of example, I have a script that reads the temperatures of today and tomorrow's weather and writes them to file as celsius and fahrenheit. This was performed as a demonstration of the maths system and procedural code because, to be honest, I don't know fahrenheit at all. Anyway, there were two possible ways to do this:

  1. Write linear code, starts at the beginning, finishes at the end, runs through instruction by instruction. This would require including the °C->F code twice.
  2. Write code with a subroutine to perform the °C->F conversion, and call that when required.

In order to perform a procedural call, you should use the command call() (instead of go()). What this does is jump to the specified label, after saving the return location on the call stack.
When you have finished with the subroutine, you can return to the line following the call() by using the return() command.

[...setup stuff...]

; read today's high and low
selectframe(201)
info("Generating report...")
readvalue(D, 14, 14)   ; D = today's high
readvalue(E, 18, 14)   ; E = today's low

filewritestring("Nantes today    : High = ")
filewritevar(D, 2)
filewritestring("°C  (")
set A to D
call("fahrenheit")
filewritevar(B, 2)
filewritestring("F)")
filewritebyte(13)
filewritebyte(10)
filewritestring("                  Low  = ")
filewritevar(E, 2)
filewritestring("°C  (")
set A to E
call("fahrenheit")
filewritevar(B, 2)
filewritestring("F)")
filewritebyte(13)
filewritebyte(10)
filewritebyte(13)
filewritebyte(10)

[...similar code for tomorrow's forecast...]

[...tidyup code...]
quit()

.fahrenheit
  ; takes a value in A, converts it to fahrenheit,
  ; places a rounded version of the result into B...
  ; CORRUPTS 'Z' and 'B'
  set Z to A
  add(Z, 40)    ; Celsuis + 40
  mul(Z, Z, 9)  ; * 9
  div(Z, Z, 5)  ; \ 5
  sub(Z, 40)    ; - 40      [isn't there a +/- 32 algorithm?]
  roundcast(B, Z)
  return()

The call stack

Every time you 'call()', the return location is placed on a "call stack". This is simply a list of return locations. When you 'return()', the most recent address is taken from the call stack and used. After being used, it is discarded - meaning for each 'call()' the call stack grows by one, and for each 'return()' the call stack shrinks by one.
A typical analogy is that of a stack of plates. Every 'call()' places a plate and every 'return()' removes the topmost plate.

There is no way to arbitrarily discard or otherwise skip entries in the call stack. Every 'call()' must have a matching 'return()'. There can be more than one return in code - i.e. in the middle of a function if it detects invalid input as well as the usual one at the end of the function - so long as programmatically only one is executed per call, depending on the conditions of trigger. For example:

set Q to 23
set R to 0
call("divide")
quit()

.divide
  set S to 0
  if (R = 0) return();
  div(S, Q, R)
  return();
What this does is to simply divide Q by R and place the result into S. However, if it detects that R is zero, it aborts early to save a division-by-zero error. So there are two possible 'return()'s, but given the circumstances, only one is ever valid. Either R is zero (hence the first one) or it isn't (hence the second one).

It is considered a failure to end a script with a call stack; this implies a mismatched call/return pair.

Under RISC OS, the call stack may be up to 16 entries. There is only one way to end a script under RISC OS (the terminate() command), so abandoning a script prematurely may result in warnings if a call stack is active.

Under Windows, there is no limit to the size of the call stack. Furthermore, the terminate() command is specifically intended for abandoning scripts, so you will not receive a warning if there is a call stack defined. The correct way to end a script (under Windows) is with the quit() command, and this will warn if there is a call stack.
The the lvar() command (under Windows) lists the call stack, the result looking like:

Call stack:
    4 --> +398   line  30
    3 --> +290   line  23
    2 --> +194   line  17
    1 --> +101   line   6
if there is a call stack active, or:
Call stack:
  -- no call stack --
otherwise.


File handling

Introduction

One of the primary features of the teletext script is in creating file output. The script itself is designed for loading teletext frame off-air and outputting them to file, either as-is or with some sort of editing.

In the teletext script, there is a "user I/O file" which may be opened, written to, and then closed. You can only have the one file open at a time, however there is nothing to stop you from creating multiple files, one after the other. There is no concept of 'file handle', as the write commands write to the open file.

When we talk of frame and page, there are some complications with this terminology, hence:

  • Page - a teletext page, i.e. p102 which may consist of multiple frames.
  • Frame - a single teletext frame. This can often be used interchangeably for 'page' in cases where there are no subframes, and most of the time we would use the terminology 'frame' as the script interpreter works one frame at a time.
  • Subframe - specifically refers to an individual frame in a page that consists of many frames. All subframes are frames, but not all frames are subframes. For example the news on BBC World (and possibly BBC analogue services) presents each item of news in a single frame. That frame is a page, but it isn't considered a subframe. On the other hand, Sky News and EuroNews teletext services present their news articles on two or three pages. The group (i.e. p107) is the page, which consists of two or three frames, which are subframes.

Opening and closing files

There are two ways to open a file. Which you pick depends on whether you wish to append information to an existing file, or create a new (empty) file.

Creating a new file is performed using the filewrite() command. It will open the output file, which is empty, and set the output pointer to the beginning of the file. If the file specified already exists, it will be erased and a new version created.

filewrite("#TEMP#\tempfile.txt")

Appending to an existing file is performed using the fileupdate() command. It will open the output file, which may already contain data, and set the output pointer to the end of the file so anything you now add will be written after previous content.

fileupdate("#PAGES#\currencylog.txt")

Closing the output file is the same in either case, you use the fileclose() command.

fileclose()

Please note that there is a difference between path specifiers on RISC OS, where the following would be quite valid:

filewrite("<Teletext$Pages>.mypage")
and Windows, where the following would be valid:
filewrite("#PAGES#\mypage.ttx")
There is no attempt at translating between the two forms, as the variety of possibilities does not make a translation viable; and furthermore filenames under Windows require a type extension while those under RISC OS require a filetype value to be applied.
You can read more about path specifiers.

As just mentioned, while Windows file 'types' are self-contained in the file extension (i.e. ".txt", etc), RISC OS requires a metadata setting. This should be performed once the output file has been closed, using the filetype() command.

filetype("<Teletext$Pages>.mypage", &FAF)
Note that the type can be applied multiple times, it won't hurt, however it really only needs to be done after a filewrite() to create the file, as files opened with fileupdate() will presumably already have a type.

General notes:

  • Under RISC OS, untyped files are given type &FFD (datafile). Attempts to run the file will usually result in an error message saying that there is no program capable of opening that sort of file; so be sure to use an appropriate filetype.
  • Under RISC OS, there are few controls over the type of file that may be created and what these files may be called; it is valid to attempt to create something like <OvationPro$Dir>.OvnPro, and I'm sure you can guess the result of that. It is wise to check over scripts from unknown sources to be sure that there is nothing malicious.
  • Under Windows, there are stricter controls. You are blocked from creating files with extensions such as .exe and .dll, you cannot create files within the Windows directory, etc etc. [there is special handling for if #TEMP# is within Windows]
  • Under Windows, the filetype() command works but accepts a strict few types, and its use is strongly discouraged as it is better to apply a correct file extension in the beginning.
  • Under Windows, there is no oscall(); getting a file to load itself is performed using execfile() which takes no parameter, it will use the name of the last user file accessed. You cannot run arbitrary files or perform arbitrary commands under Windows.
  • Opening a file with no path specifier may leave the file in an undefined location. Under Windows, this is likely to be the WinTTX application directory; under RISC OS it is likely to be the root of the default drive (your CSD, which is totally different to where the application 'lives').
  • In either case, attempting to write to a file with no write permission, no write access, a read-only media, or insufficient user privileges to write is all classed as an "undefined" error and how the interpreter handles this situation is not explicitly specified.
  • Creating a file and outputting multiple teletext format frames to this file will create an invalid file which will not be able to be loaded properly.

Tidying up teletext frames

Before writing to some types of file (details of available formats are provided further down), you can 'tidy' the frame by removing unwanted mosaic codes and/or unwanted lines.

The removal of unwanted mosaic codes is performed using the smartclear() command. This is because only the creation of teletext files is able to preserve the mosaic characters. They cannot be represented in text.
You can smartclear() individual lines, or you can under Windows pass the line number -1 to smartclear the entire frame.

The removal of blank lines is more useful. With the exception of teletext files, the output methods permit the complete omission of lines marked as 'blank', so you can only output the content you want and the rest will be discarded. This is acheived with the omitline() command.
Note that you must omit the header (line 1) for any other omissions to take effect. If the header is present, omitted lines will be retained, and this might have some odd side effects under Windows - namely lots of "OMITTHIS" markers!

You can also read characters from the frame using set <var> to char(<x>, <y>) and write characters to the frame using setchar().

When a frame has been modified, you must push it back to the cache, as attempts to write the frame to file will cause the frame to be loaded from the cache, and hence the older cached version would overwrite the one you just amended. Don't worry if that sounds confusing, just be sure to call storeframe() after any alteration to the frame's content.

Writing to files - different options

There are a number of ways you can write to the file.

To output entire frames (with optional omission of unwanted lines), you can use appendframe() or appendframes(); the difference being that the former will write the frame specified and the latter will write all the integral subframes of the page specified.

To write individual bytes to the file, you would use filewritebyte(). This is perhaps most useful for outputting newlines.

You can write string literals (that is a fixed string that you specify in the script) using filewritestring(). You cannot copy strings from teletext frames, this can be achieved using a roundabout method (described below).

Floating point values (either literal or from a variable) may be written using filewritefloat(), and variables (either integer or float) may be written using filewritevar().
It may seem as if when we are speaking of a float variable, that filewritefloat() and filewritevar() may do much the same thing. This is mostly correct, however there are slight differences in the control of output style.

Writing to files - different formats

You can write to the output file in one of four different formats (three under RISC OS).

1 | Teletext frame | This will output a teletext frame. It is perhaps the least useful option as only WinTTX would be able to reload this sort of file, and if you write more than one frame to a file it will be a file that could not be correctly loaded.
2 | ASCII text | This will output in plain ASCII text. This is useful for simple tables and charts and things where the information content is more important than any visual aspect.
3 | OvationPro DDL | This will create a document script file suitable for loading into the OvationPro desktop publisher by David Pilling (more details on his website). It will attempt to recreate the look of the teletext page, complete with colours and black background. Italicised text will be used in place of flashing.
4 | HTML document (Windows only) | This works in much the same way as the aforementioned OvationPro output, only the type of file created is a web document. It is fairly abusive regarding styles and effects in order to generate a good representation of a teletext frame, however it has been tested and shown to render correctly on both MSIE6 and Firefox. Correct display on other browsers, especially those of more minority platforms, is not guaranteed.

OvationPro DDL output hints

To output an OvationPro DDL file, you would...

filewrite("<filename>")  ; "filename.dpd" under Windows
filewriteovnhead()       ; must be the FIRST thing you output

; output the frames, ie:
;  appendframe(x, 3)
; in a loop, or whatever

filewriteovntail()       ; must be the LAST thing you output
fileclose()

filetype("<path>", &B25) ; only under RISC OS

The filewriteovnhead command outputs (with small modifications depending on platform):

// minimal OvationPro DDL script created by Teletext (1.49)

COL_00={colour "Ttx Black" {rgb 0x0 0x0 0x0}}
COL_01={colour "Ttx Red" {rgb 0x10000 0x0 0x0}}
COL_02={colour "Ttx Green" {rgb 0x0 0x10000 0x0}}
COL_03={colour "Ttx Yellow" {rgb 0x10000 0x10000 0x0}}
COL_04={colour "Ttx Blue" {rgb 0x0 0x0 0x10000}}
COL_05={colour "Ttx Magenta" {rgb 0x10000 0x0 0x10000}}
COL_06={colour "Ttx Cyan" {rgb 0x0 0x10000 0x10000}}
COL_07={colour "Ttx White" {rgb 0x10000 0x10000 0x10000}}

STORY_001={story

You can replace this with your own header if you wish, however you must define the colours as above, because the output frames will expect them to be present.

The append[given]frame[s] commands, with type 3 output, write the frames exactly as for the OvationPro DDL output from the Save dialogue. Please refer to any saved file for an example.

The filewriteovntail command outputs:

{endoftext}
}

This tells OvationPro that the DDL file has finished. The minimum you can get away with is a single '}' character, but you might as well call this function and end properly...

A suggestion is to 'centre' the output. For this, you should:

filewrite("<filename>")
filewriteovnhead()
filewritestring("{align 1}")

; output follows...

The alignment types are:

left | 0
centre | 1
right | 2
justified | 3

You might like to output headings before each group of pages. The example below shows outputting a heading, and then outputting the pages 101 to 110.

; NEWS
filewritestring("{newpara}{textsize 16000}{bold 1}{underline 1}")
filewritebyte(34)
filewritestring("Headlines")
filewritebyte(34)
filewritestring("{bold 0}{underline 0}{textsize 12000}")
filewritebyte(34)
filewritestring(" (from CNN)")
filewritebyte(34)
filewritebyte(10)   ; or you can output <13><10> under Windows
filewritestring("{textsize}{bold}{underline}{newpara}")

set A to 101
.writenews
  appendframe(A, 3)
  A++
  if (A [ 110) go("writenews")

You have various commands at your disposal. A command with no parameter will restore the option to the default for the current style (which will probably be Trinity.Medium, 12pt, left aligned, no bold/italic/underline).

{align #} | Sets the alignment to that specified (0-left, 1-centre, 2-right, 3-justified).
{bold #} | Use {bold 1} to switch bold on, and {bold 0} to switch it off.
{italic #} | Use {italic 1} to switch italics on, and {italic 0} to switch it off.
{newpara} | If you want a line break, use {newpara}.
{textsize #} | The text size is 'pointsize * 1000', so 12000 is 12pt, and 24000 is 24pt...
{underline #} | Use {underline 1} to switch underline on, {underline 0} for off...

All text must be enclosed in "quotes", including spaces between items. The following is valid:

{bold 1} "this text is in bold" {bold 0}

Even the following would work:

{bold 1}
"this "
"text "
"is "
"in "
"bold"
{bold 0}

This, however, won't work:

{bold 1} this text is in bold {bold 0}

If you need to include the characters '{', '\', or '"' in the DDL, you will need to escape them, as shown:

For: Use:
{ \{
\ \\
" \"

There are all sorts of nifty things possible, such as tab-aligned results from a calculation, but these things require a deeper knowledge of the OvationPro DDL script, and that is outside of the scope of this document.

Remember, you can always 'fake' what you'd like to see in OvationPro, then save the document in DDL format to an editor such as !Edit (Notepad in Windows). This will allow you to see how something was achieved, and thus allow you to use it in your own generated output.

A useful suggestion is to save a number of 'desired' frames to a directory, and then load them in using the cache_loaddirectory() command. This will save you waiting for each frame fetch while testing and tweaking your teletext script to produce exactly the DDL script that you want.
(this command has not been implemented under Windows, however you can use the cache_loadfile() command to load files individually to acheive the same result.

And for HTML?

To output an HTML file, you would...

filewrite("<filename>")  ; "filename.html" under Windows
filewritehtmlhead()      ; must be the FIRST thing you output

; output the frames, ie:
;  appendframe(x, 4)
; in a loop, or whatever

filewritehtmltail()      ; must be the LAST thing you output
fileclose()

filetype("<path>", &FAF) ; only under RISC OS

All of the remaining comments are much the same as already given for the OvationPro output. If you know HTML mark-up, you can patch in a lot of custom HTML.

Copying strings from a teletext page

It is not possible to copy strings out of the teletext page. This action should be performed by reading the frame character by character and writing bytewise to file, as this example shows:
filewritestring("                  Sky  = ")
set A to 30
.reportloop
  set B to char(A, 17)
  filewritebyte(B)
  A++
  if (A [ 40) go("reportloop")
filewritebyte(13)
filewritebyte(10)
This example copies the weather 'forecast' word (cloudy, rain, snow, etc) from the frame.


Path specifiers

Introduction

In order to read a teletext frame from file, or write to the user I/O file, you need a 'path'. This is the location where the file will be created.
It is not advised to specify a file using only the filename as there is no guarantee as to where the file could end up.

Unfortunately, the naming conventions between RISC OS and Windows are completely different, so you will need to either write system-specific code (and include a check to reject the wrong system) or write dual-system code.

Paths under RISC OS

Paths under RISC OS are best expressed using system variables. For specifics of path construction, please refer to your RISC OS user guide.

<Teletext$Pages> | Where your teletext pages are stored. Usually "!Teletext.Pages".
<Teletext$Temp> | Where teletext temporary files are placed; either within !Teletext or within Wimp$Scrap.
<Teletext$Script> | Where your teletext scripts are kept. Usually "!Teletext.scripts".
<Teletext$Cache> | Points to where your cache data is stored.
<Teletext$Config> | The name of your Teletext configuration file (not a path).
<Teletext$Prefer> | The name of your Teletext preferred pages file (not a path).

A valid path could therefore be something like:

filewrite("<Teletext$Temp>.outfile")

Paths under Windows

Windows does not offer anything like the same degree of flexibility as RISC OS system variables, so we fake a little bit of it. You can specify 'paths' in between hash characters at the start of a filename:
#PAGES# | Where your teletext pages are stored. See below.
#APP# | Where your WinTTX is installed.
#CACHE# | Where your cache is stored, usually the same as "#APP#".
#TEMP# | Your temporary folder; often "C:\Temp" or "C:\Windows\Temp" on older systems, but hidden away on a per-user basis on XP (etc).

A valid path could therefore be something like:

filewrite("#TEMP#\outfile.txt")

When WinTTX starts, it will look for:

  My Documents\Teletext pages
and if it does not exist, it will be created and set as the default path for saving frames.

The teletext script has a wider search, and will search in this order, stopping at the first that exists:

  My Documents\Teletext pages
  My Documents\Teletext frames
  <APPPATH>\Pages
  <APPPATH>

The application install path ('<APPPATH>') is, by default:

  C:\Program Files\HeyRick\WinTTX

Writing dual-system script

As discussed in the introduction:

It is possible to write scripts that work equally on both systems. To do so, you should take advantage of the differences between !Teletext which offers channel presets, and WinTTX that expects a UHF channel. This, requesting the channel preset number under WinTTX will always return "-1", as this code demonstrates:

set A to status(channel)
if (A ! -1) goto("riscoscode")

; this stuff is Windows code
[...blah blah - WinTTX specific stuff...]
go("continue")

.riscoscode
; this stuff is RISC OS code
[...blah blah - !Teletext specific stuff...]

.continue
; everybody meets back here

OvationPro and HTML do not care how their lines are terminated. Things are trickier with ASCII files as some software (such as Notepad) cannot cope with files where lines are not CRLF terminated.

In either case, you will need system-specific code at the start of the script (opening the output file) and at the end (RISC OS - assigning filetype; both - running the file). For ASCII you may need to insert <13> codes before <10>s for correct newlines.
My suggestion, therefore, is to use an integer variable (how about 'O' for OS?) which is set to a value for RISC OS, and something else for Windows. Then you can test, for example:

set O to 0
set A to status(channel)
if (A ! -1) set O to 1       ; 1 = RISC OS, 0 = Windows

if (O = 0) filewrite("#TEMP#\MyFile.txt")
if (O = 1) filewrite("<Teletext$Temp>.MyFile")

[...blah blah - some code...]

if (O = 0) filewritebyte(13) ; correct newline on either OS
filewritebyte(10)

[...blah blah - more code...]

fileclose()
if (O = 1) filetype("<Teletext$Temp>.MyFile", &FFF)

if (O = 0) execfile()
if (O = 1) oscall("%Filer_Run <Teletext$Temp>.MyFile")

if (O = 0) quit()
terminate()


Mathematics

Introduction

The script interpreter understands numbers, both real numbers (fractionals or floats, such as 1.23) and whole (integers such as 68).

With these numbers, which may be either literals (hard-coded in script) or read from a teletext frame, you can perform a variety of actions and also you can use the numbers in decision-making.

There are 26 variables available for use; that is, there are twenty six bits of memory in which you can store numbers. They are called A to Z, each letter of the alphabet is a variable.
The first sixteen (A through P) are integer variables and can store only whole numbers. The remaining ten (Q through Z) are float variables and can store numbers with up to nine decimal places of precision.

Specifying numbers

You can specify numbers in basic form just by writing it:
set R to 123.45
add(R, 32)

You can specify integer numbers in hex (base 16) by prefixing with an ampersand '&' symbol:

channelid(A)
if (A ! &EF01) error("Wrong channel!")

You can specify integer numbers in binary (base 2) by prefixing with a percent '%' symbol:

set M to %11110000
and(A, %1111)

The following examples all set 'A' to 123:

set A to 123
set A to &7B
set A to %1111011

For negatives, simply prefix with a minus symbol:

set A to -123
set A to -&7B
set A to -%1111011

All variables are zero when the script begins.

Basic mathematics

Maths plays a part in all scripting when you get beyond the really basic things.

You have a number of mathematical possibilities:

Addition | C = A + B | set C to A add(C, B) | For increments, you could use "C++".
Subtraction | C = A - B | set C to A sub(C, B) | For decrements, you could use "C--".
Multiplication | C = A × B | mul(C, A, B) |
Division | C = A ÷ B | div(C, A, B) |
Modulus | C = A MOD B | mod(C, A, B) |
With these, most calculations can be performed.

More complex maths

More complicated maths requires more complicated commands:
  • To determine the 'absolute' value of a number, that is the number in positive form (i.e. 123 is 123 and -456 is 456), use:
    abs(C, A)
  • To 'flatten' a variable to a specific number of decimal places, use:
    flatten(C, 2)
    where the second value is the number of decimal places to retain. This does not round.
  • To round and optionally cast one type of variable to another, use: roundcast(C, R)
    Unlike set C to R, assigning 8.7 will result in '9' (using set would result in 8); it rounds-to-nearest.
    RISC OS: There is a bug in that assigning to a float or assigning a float to a float will result in 0.5 being added.
  • To determine the 'sign' value of a number, use:
    sign(C, A)
    The result variable (in this case 'C') will be -1 if the number is negative, 1 if the number is positive, and zero if it is zero.
  • To determine the 'square' value of a number, use:
    sqr(C, A)
    And then 'C' will be the square of 'A'.

Boolean logic

And | C = A & B | and(C, A, B) |
Exclusive Or | C = A % B | eor(C, A, B) | Windows: you could use "xor(C, A, B)".
Left shift | C = A << B | lsl(C, A, B) |
Right shift | C = A >> B | lsr(C, A, B) |
Not | C = NOT A | not(C, A) |
Or | C = A | B | or(C, A, B) |

Rounding

The set command does not round.
set R to 12.75
set A to R
will result in A being set to 12.

The roundcast command rounds to nearest.

set R to 12.75
roundcast(A, R)
will result in A being set to the expected 13.

Internal accuracy

Some languages (Psion OPL, Microsoft VisualBasic) try to work with integer maths for speed unless certain rules suggest otherwise. The teletext script interpreter is different in that all internal calculations are floating point.

Windows: All calculations are performed to 'double' floating point accuracy, and are then clipped to nine decimal places (with rounding) to try to ensure the same results as the RISC OS version.
RISC OS: All calculations are performed with floating point accuracy.

If you specify floats as the destination variable, the internal result is copied across. If you specify integers as the destination, the internal result is rounded to the nearest whole number.


Debugging

Description

Judicial use of if() and two special commands can greatly assist you in debugging your programs.

report_var(var)

This command will pop up a message box telling you the value of the specified variable.
Read more.

lvar()

This command will insert a variables list into the debug log (RISC OS), or create a file listing the state of the script interpreter (Windows).
Read more.

Trace log (RISC OS)

If you have a RAMdisc defined, then the script interpreter will create a file called "ttxscrplog". Everything on line 2 of the report window will be written to this log. Ensure your disc is large enough, as running out of space for the log is classed as a script error (not intentionally, the script error handler picks it up).
To give you an idea, "movietest" generated a 66K log.
Line one (the upper line) is not logged, so you are spared loads of lines saying "Executing script - 69% (64)".

One thing to note, the line number reporting is not totally accurate. I patched this facility into the existing script interpreter to aid me in debugging (as percentages were a pain to figure out). It can get confused by lots of branching. :-)

Windows: The core functionality of the trace log is available, but it is not presented in the released versions of WinTTX because, to be honest, I found that a couple of report_var()s and an lvar() was all I really needed.

Because the Windows script interpreter was written with reporting in mind, the line numbers given are correct; and are correct for both RISC OS (LF only) and Windows (CRLF) format files.


Differences

Script interpreter differences

This document describes the differences present in the Windows interpreter, relative to the RISC OS version.

The script interpreter identifies itself as v1.08.

Commands

Control statement
  • The RISC OS style begins "¤", while under Windows you can also use "@".
  • Windows uses:
    ¤script "<title>"
    when building the menu of available scripts. Refer to the test scripts supplied, you'll see...

Labels

  • There is no limit to number of labels that may be defined (RISC OS limit is 16).

appendframe( <num>, <type> )

  • Windows can take type = 4, for HTML output.

appendframes( <var>, <type> )

  • Windows can take type = 4, for HTML output.

appendgivenframe( <num>, <num>, <type> )

  • Windows can take type = 4, for HTML output.

appendline( <var>, <type> )

  • Deprecated, can only accept type = 2, for ASCII output.

channel( <var> )

  • RISC OS expects value from 1 to 9 for channel preset.
  • Windows expects value from 21 to 69 for UHF channel.

cache_coeur( <set> )

  • New to WinTTX: If <set> is 1, then all cache entries will be flagged as being available to the script; and if <set> is 0, all cache entries will be flagged as not available (the script interpreter won't see them).

cache_loaddirectory( <path> )

  • Windows: - Not currently implemented.

cache_loadnextentry( <var> )

  • Windows: - Not currently implemented.

call( <"label"> )

  • No limitation on how big the call stack may be (RISC OS limit is 16 calls).

eggy()

  • Windows: - Not supported.
  • RISC OS: - Note, uses assembler code that is not 32 bit compliant.

execfile()

  • The Windows exquivalent of "selfexec()", only the last user file created is loaded into its respective handler, such as:
        .dpd  --> OvationPro
    .html --> MSIE / FireFox / Opera...
    .txt  --> Notepad
    Asks the system, so if you have replaced MSIE then the HTML files will open in your chosen browser.

fileextn( <extension> )

  • Windows: Appends an extension to a filename. Very restrictive, it is best to open the file with a good extension in the first place instead of fixing it later.

filetype( <"name">, <type> )

  • Under Windows - Only supports and converts filetypes for OvationPro documents (&B25), HTML documents (&FAF), and text files (&FFF).

filewritehtmlhead()
filewritehtmltail()

  • New to WinTTX: Write the prefix/postfix to the HTML file; akin to how 'filewriteovnhead()' (...tail()) works.

findany( <line>, "<string>" )

  • New to WinTTX: Looks for 'string' from the line specified, returns line number where where found.

info("<message>")

  • New to WinTTX: Writes <message> to the lower line of the status window; akin to 'poll_message()'.

keypress( <"keystring"> )

  • New to WinTTX: Like 'pushkey()' but takes a Windows-style keypress specifier.

lvar()

  • A lot more detailled under Windows.

message( <"message"> [, <type>] )

  • Under Windows, optional 'type' can be:
        0 - Plain message popup
    1 - Message is informative (adds '?' icon)
    2 - Message is a warning (adds '!' icon)
    3 - Message is an error (adds 'X' icon)

oscall( <"command"> )

  • Will cause an error. No OS access is permitted under Windows.

poll_disable()

  • Has no effect under Windows (for Windows multitasks differently).

poll_enable()

  • Has no effect under Windows.

poll_message()

  • Has no effect under Windows (use 'info()' to write a status message).

poll_nomessages()

  • Has no effect under Windows (Windows has no iconbar so we cannot hide away).

poll_now()

  • Has no effect under Windows (actually it busy-waits a few mS).

pushkey( <num> )

  • Not supported, Windows key codes are different, use 'keypress()' instead.

quit()
Note the difference in use between RISC OS and Windows.
Any future versions of the RISC OS interpreter will follow the new behaviour.

  • Windows: Exit the script tidily (use 'terminate()' to abort early, esp. if a call stack is defined).
  • RISC OS: Exit !Teletext !!! - you can only use 'terminate()' to finish scripts; there is no distinction between aborting upon a problem and clean exit.

selfexec( <"command"> )

  • Command is discarded, script file is loaded into Notepad. There are no alternatives.

set <var> to <num>

  • Mostly the same, except:
        set <var> to status(channel)
    will ALWAYS return -1 because WinTTX uses UHF tuning, not channel presets.
  • Also:
        set <var> to status(riscos)
    always returns zero, and:
        set <var> to status(windows)
    always returns one.
  • Note that:
        set <var> to status(altkey)
    set <var> to status(ctrlkey)
    set <var> to status(shiftkey)
    are implemented as described in the Windows API document, but they don't work, neither on XP nor Windows 98SE. Have I missed something?

showcachelist()

  • Has no effect under Windows.

showcontrols()

  • Has no effect under Windows.

showpreferred()

  • Has no effect under Windows.

showviewer()

  • Has no effect under Windows.

userchoice( <var>, "<message>" [,<yesno>] )

  • Windows: If optional value <yesno> is 1, then the "Yes" button will be highlighted, otherwise the "No" button will be highlighted - this effects the response that is returned if the user idly presses 'Enter', and may be used to auto-select the recommended response.

winttx( <var> )

  • New to WinTTX, sets <var> to 1.

xor( <var>, <num>, <num> )

  • Specific to WinTTX. Identical to 'eor()', only it seems that a lot of PC terminology uses 'XOR'...

Files

You are trapped from creating files in Windows with extensions like ".exe" and so on.

The RISC OS paths are invalid. You can, however, prefix with specific codes in order that you can choose the path - refer to specifics.

Under Windows, if anything is wrong or misunderstood, there will either be an error message, or the filename will simply be discarded and replaced with "...\Temp\ttxiofile.txt" (or wherever your Temp folder is).

Detecting WinTTX vs !Teletext

Easy!
set A to status(channel)
if Windows, 'A' is -1.
This method is recommended because it works on both WinTTX and !Teletext.


Versions

v1.00

Identifies itself as version '1'.
Released with !Teletext v1.38 (2001/08/08).
  • Basic script interpreter

v1.01

Incorrectly identifies itself as version '1'.
Released with !Teletext v1.41 (2007/01/07).
  • New commands:
    • poll_disable()
    • poll_enable()
    • poll_now()
    • poll_message()
    • poll_nomessages()
  • This is the first version to allow script control over polling.

v1.02

Incorrectly identifies itself as version '1'.
Released with !Teletext v1.43 (2003/01/08).
  • Bugfix:
    • setchar()
  • New command:
    • filewritestring()

v1.03

Incorrectly identifies itself as version '1'.
Released with !Teletext v1.44 (2003/04/18).
  • Some internal modifications, a few bits recoded (optimised).
  • No changes to the API.

v1.04

Identifies itself as version '104'.
Released with !Teletext v1.47 (2003/05/05).
  • Added float variables Q to Z.
  • Script returns a true version now, instead of just '1'.
  • go() can branch to ANY location in the script, from any location.
  • New commands:
    • abs()
    • appendline()
    • channelid()
    • fileupdate()
    • filewritevar()
    • find()
    • findend()
    • flatten()
    • mod()
    • quit()
    • readvalue()
    • roundcast()
    • showcachelist()
    • showcontrols()
    • showpreferred()
    • showviewer()
    • sign()
    • sqr()
    • userchoice()
    • version() - duplicates "set <var> to status(scriptver)"
  • This is the first version to include floating point support.

v1.05

Identifies itself as version '105'.
Released with !Teletext v1.48 (2003/05/09).
  • New commands:
    • cache_loadnextentry()
    • frame_number() - more flexible than "set <var< to status(pagenum)"
    • frame_subnumber() - more flexible than "set <var> to status(pagenum)"
    • frame_language()
    • frame_linkedto()

v1.05bis

Identifies itself as version '105'.
Released with !Teletext v1.49 (2003/05/13).

As there has been no public release of the version 1.05 script interpreter, I have kept the version number at 1.05 for the following modifications.

  • Modifications:
    • appendframe()
    • appendframes()
    • appendgivenframe()
    all now accept output type '3', OvationPro.
  • New commands:
    • call()
    • filewritefloat()
    • filewriteovnhead()
    • filewriteovntail()
    • return()
  • This is the first version to include OvationPro support.
  • This is the first version to include procedural branch support.

v1.06

Identifies itself as version '106'.
Released with !Teletext v1.51 (2003/06/22).

  • Bugfix:
    • Modifications in space stripping of input.
    • appendgivenframes() now correctly exports OvationPro format.
  • Modifications:
    • getframes() now copes with broadcasters that send subframes twice in succession.
  • New commands:
    • set status macro "day"
  • Support for "!startup" script.
  • Previous script pages are no longer deleted from the cache, just reflagged as non-script.
  • Script user-requested abort sped up.

v1.07

Identifies itself as version '107'.
Released with !Teletext v1.52 (2003/06/29).

    New command:
    • "set <var> to status( <blah> )" can now accept:
      • shiftkey
      • ctrlkey
      • altkey
  • Status can now be assigned to floating point variables.

v1.08

Incorrectly identifies itself as version '107'.
Released with WinTTX v1.50 (2008/08/08).

  • Ported to Windows.
  • Modifications:
    • HTML output option for appendframe() and the like.
    • smartclear can accept line -1 to mean "whole frame".
    • IMPORTANT change of use for quit() command.
    • message() can take optional 'type of message' value.
    • userchoice() can take optional 'highlight which' value.
    • A myriad of little bits and pieces, like path support, etc.
    • WinTTX does not support channel presets, must be given a UHF channel. This can be used as a 'safe' Windows/RISC OS detector as WinTTX will ALWAYS return -1 when asked the channel (!Teletext will return 1 to 9).
  • New commands:
    • @ for control statements()
    • cache_coeur()
    • execfile()
    • fileextn() (though its use is strongly discouraged)
    • filewritehtmlhead()
    • filewritehtmltail()
    • findany()
    • info() (instead of poll_message())
    • keypress() (instead of pushkey())
    • winttx()
    • xor() (duplicates eor())
  • Removed:
    • eggy() [deprecated and no longer supported]
    • filetype() [deprecated under Windows]
    • oscall [rejected under Windows]
    • poll_*** [Windows only - poll control has no effect]
    • pushkey [Windows only - keycodes are totally different, use keypress()]
    • show*** [Windows only - these have no effect]
    Many of these have been removed only from the Windows interpreter due to system differences (i.e. no access granted to command line, different multitasking system, etc); they will mostly remain as-is under any future versions of the RISC OS interpreter.
  • Outstanding:
    • cache_loaddirectory
    • cache_loadnextentry
    These were included for testing the script at a time when I did not have the ability to receive off-air signals. I will probably get around to it sometime, but these are considered non-essential.

v1.08bis

Identifies itself as version '108'.
Released with WinTTX v1.51 (2008/08/15).

  • Modification:
    • Reaching the end of a script file without a 'quit()' command is not a serious enough problem to warrant a warning (!Teletext would report this as a problem).
  • cache_loaddirectory / cache_loadnextentry still unimplemented.

End of versions list.

The most recent...

RISC OS interpreter is v1.07 in !Teletext 1.52 (2003/06/29).
Windows interpreter is v1.08bis in WinTTX 1.51 (2008/08/15).


Cache

Cache utilitisation

Description

The script interpreter uses the cache to store pages between retrieval off-air and saving out to a file.
The script system ignores references to expiry times.

If no cache is defined, you will receive a message and the script will not run.

Specifics - RISC OS

The script interpreter builds a virtual cache within your existing cache setup. It does this by simply setting bit 7 of the "Request count" in the cache index. It will ONLY respond to this bit, if set. Anything previously in the cache will be ignored.
When a script is started, the cache is scanned and ALL frames with bit 7 set are marked as unavailable to the script (the bit is unset; frames are NOT deleted).
Any frames fetched from the script are pushed into the cache with this bit 7 set. Any frames later required are reloaded loaded if they have bit 7 set.

Specifics - Windows

The script interpreter builds a virtual cache within your existing cache setup. It does this by simply setting a 'ForScript' accessibility flag. It will ONLY respond to this flag, if set. Anything previously in the cache will be ignored.
When a script is started, the cache is scanned and ALL frames with this flag set are modified to not have this flag set (the frames are NOT deleted).
Any frames fetched from the script are pushed into the cache with the flag set. Any frames later required are reloaded loaded if they have the flag.

You can use cache_coeur() to set/unset the accessibility flag for the entire script.

What this means

Basically, the script interpreter will not touch what is already present in the cache, unless it was put there by the script interpreter during that runtime...

However, the main viewer cache facility has no such discrimination, so if you happen to load a newer frame in a script, the viewer will, later, recall it.

Everything fetched is pushed to the cache. Windows: The regular teletext fetching is only frame-accurate, however for obvious reasons the script is subframe-accurate. A later version of WinTTX will permit the viewer to step through available subframes too.

Reloading frames

You need to selectframe() or selectframes() to reload a frame and make it current. Additionally, the last fetched frame is 'current'; though it is always safer to use selectframe[s]().

Once you have finished with the frame, if you have modified it then use storeframe() to write it back into the cache; otherwise the next time you access cached data the original frame will be loaded, not your modified one.

RISC OS: Frames are not deleted when the script starts or terminates, only when your cache is expired and/or deleted by !Teletext as part of your normal chosen cache configuration.
Windows is similar, except the 'ForScript' accessibility flag is altered, as few frames as possible are detailed outside of actual page expiry.

Cache index format - RISC OS

The cache index is a series of 20 byte entries as follows:
       Byte 0 : Channel.
  Bytes 1 - 4 : Frame and subframe number, in hex.
                If 'deleted', bytes 6-10 are zero.
       Byte 5 : Currently unused.
 Bytes 6 - 10 : RISC OS 5-byte time value when frame
                written to cache. If bytes 6-10 are
                zero, the page is flagged as to be
                deleted).
Bytes 11 - 14 : Word giving offset into data file.
      Byte 15 : 128 (bit 7 set)
Bytes 16 - 19 : Reserved for future expansion.

This is the same as the original index, the only difference being ?15 set to 128.
If you use the cache list option, then the "Rqs" column will say 128. This means it is a script-cached-frame.

Cache index format - Windows

The cache index file is not expected to be read by third-party software; especially since the script interpreter offers no mechanism to launch third-party programs.

However, for completeness:
The cache file starts with two signed integers (16 bit). The first is either '1' or '2' and it specifies the file version. The second is the count of entries. Zero is a valid amount.

Then follows zero or more cache entries:

  Integer    Channel number (21-69)
  Long       Frame number
  Long       Subframe number   - type 2 files only
  Date       Last refreshed
  Boolean    ForScript         - type 2 files only
  String     1024 bytes for teletext page
  String     1024 bytes for extension data

Versions of WinTTX prior to v1.50 use the type 1 file. Versions of WinTTX from v1.50 onwards use the type 2 file; they can also load the older format and will silently recreate the cache in the newer format.

A hidden little thing - to see what is in your teletext frame cache, double-click the space just below the "Mini viewer" button...

Related information
cache_coeur()


( blank lines! )

Description

Blank lines have no effect. It takes a tiny amount of time to read a blank line and work out that it is a blank line, however this cost is far outweighed by having scripts which are readable.
Don't be afraid of blank lines. Use them liberally to break your script into logical sections, like the paragraphs of a book...

Notes

A blank line may contain spacing characters if, for example, your software auto-indents for you. These will be stripped as part of the line pre-processing and the end result will be... a blank line.

Specifics

The RISC OS script interpreter does not handle stripping out TAB characters. Under Windows, Space (32) and Tab (09) are treated equally.


Control statements

¤statement
@statement

Description

These are control statements which pass information to the script interpreter before the script is executed.

The RISC OS convention is to use the 'eggy' character '¤', however this is not so easy to do on a Windows computer, so the Windows script interpreter will also accept lines beginning '@'.

Under Windows, you can obtain the '¤' by holding down the Alt key while you tap out 0 1 6 4 on the numeric keypad.

¤script...

The only currently defined control statement is:
¤script "<description string>"

This passes a description to the script interpreter which is then made available - by description - in the script menu.
The picture on the right shows how this works. The "!startup" script has no description embedded, so it is listed by its filename (extension omitted), while the other scripts have descriptions and, hence, they are listed according to what they do.
Up to twenty scripts can be listed in the menu.

Specifics

You cannot use the '@' form under RISC OS.

Script descriptions are only partially utilised under RISC OS; the menu lists scripts by filename.


; blahblah

; <something or other>

Description

Lines beginning ';' are comments and are thus ignored.

Because of how the parser works, you can also add comments at the end of lines.

Example

Here is an example of commenting:
  ; ## Jay Leno / Conan O'Brien on CNBC [channel &714E]
  .isitcnbc
    channelid(A)   ; channel ID is &714E
    if (A ! &714E) message("Please select CNBC (ch. F31)")
    if (A ! &714E) go("isitcnbc")

  getframes(340)   ; Jay's guest list, frame 340.1
  getframes(341)   ; Conan's guest list, frame 341.1


.<label>

Under RISC OS, you may only define a maximum of 16 labels. The Windows script interpreter has no such limitation.

Description

Labels permit you to assign a specific line as a branch point, a sort of bookmark to which your script code may jump.

Notes

The actual pointer of a label is the line following the label. So in the example below, the label scanloop, when jumped to, would have execution start with the cache_loadnextentry() line.
This behaviour is by design (to avoid wasting time interpreting the label line), and is documented purely for completeness.

Examples

Labels are an essential part of looping, as this example demonstrates:
  set A to 0
  .scanloop
    cache_loadnextentry(A)
    if (A = -1) go("scanend")
      [code to fiddle with the frame data goes here]
    if (A ! -1) go("scanloop")

  .scanend
    [and so on...]

There is a more powerful form of control where you may call() and return() to create simple functions, as this brain-dead example demonstrates:

  set A to 1
  call(writebyte)
  set A to 2
  call(writebyte)
  set A to 3
  call(writebyte)
  [etc etc more code etc etc]

  .writebyte
    file_writebyte(A)
    return()

Specifics

Under Windows, multiple definitions of the same label will be faulted. Under RISC OS, subsequent definitions would be ignored.

Quirk

Under RISC OS, jumping to labels tended to mess up the line counter and the 'how much has been done' percentage counter.


abs()

abs( <dest-var>, <src-var> )

Description

This will place, into dest-var the 'absolute' of the value specified in src-var. What this means is that the destination will contain a 'positive' version of the source value, hence:
123 | = | 123
0 | = | 0
-123 | = | 123

Related information
Mathematics


add()

add( <variable>, <number> )

Description

This will add the number given to the variable specified.

Examples

Adding a constant to a variable:
add(A, 25)

Adding a variable to another variable (add B to A, result written to A):
add(A, B)

Related information
Mathematics


and()

and( <var>, <num1>, <num2> )

Description

This will perform a logical AND as follows:
Take num1 and AND it with num2, write the result to var.

Example

A = B AND 15
and(A, B, 15)

Notes

AND is useful for restricting information to be processed. For example, if you are looking at a byte but you are only interested in the lower nibble, you could:
and(A, A, %1111)
Likewise, if you wanted the upper nibble, you could:
and(A, A, %11110000)
Likewise, you can use AND to mask out everything except specific bits that you wish to check, such as:
and(A, A, %100)
which means discard everything except the third bit (b2).

Related information
Mathematics


appendframe()

appendframe( <page>, <format> )

Description

This appends the first frame of the specified page to the output file, in the format specified.

Notes

If the output type is ASCII, OvationPro, or HTML and the frame has no header (line 1), then all blank lines will be removed as the frame is copied out. You should blank lines using the omitline() command.

If the output type is OvationPro, you should have either created your own DDL header, or output the standard one with filewriteovnhead().
Likewise, if the output type is HTML, you should have either created your own HTML header, or output the standard one with filewritehtmlhead().

This command reads the cached frame, thus you must call storeframe() after modifying the frame contents in order to ensure the cache is up to date with respect to your modifications.

Related information
appendframes()
appendgivenframe()
filewritehtmlhead() / filewritehtmltail()
filewriteovnhead() / filewriteovntail()
omitline()
storeframe()

File handling


appendframes()

appendframes( <page>, <format> )

Description

This appends all of the frames of the specified page to the output file, in the format specified.
Frames are written in numerical order, and missing frames are skipped over.

Notes

If the output type is ASCII, OvationPro, or HTML and the frame has no header (line 1), then all blank lines will be removed as the frames are copied out. You should blank lines using the omitline() command.

If the output type is OvationPro, you should have either created your own DDL header, or output the standard one with filewriteovnhead().
Likewise, if the output type is HTML, you should have either created your own HTML header, or output the standard one with filewritehtmlhead().

This command reads the cached frame, thus you must call storeframe() after modifying the frame contents in order to ensure the cache is up to date with respect to your modifications.

Specifics

Under RISC OS, this process does not multitask.

Related information
appendframe()
appendgivenframe()
filewritehtmlhead() / filewritehtmltail()
filewriteovnhead() / filewriteovntail()
omitline()
storeframe()

File handling


appendgivenframe()

appendgivenframe( <page>, <frame>, <format> )

Description

This appends the specified frame of the specified page to the output file, in the format specified.

Notes

If the output type is ASCII, OvationPro, or HTML and the frame has no header (line 1), then all blank lines will be removed as the frame is copied out. You should blank lines using the omitline() command.

If the output type is OvationPro, you should have either created your own DDL header, or output the standard one with filewriteovnhead().
Likewise, if the output type is HTML, you should have either created your own HTML header, or output the standard one with filewritehtmlhead().

This command reads the cached frame, thus you must call storeframe() after modifying the frame contents in order to ensure the cache is up to date with respect to your modifications.


appendline()

appendline( <line>, <format> )

Description

This will write the specified line from the current frame to file. The format must be 2 (i.e. ASCII text).

Notes

This command is largely deprecated, however it still has uses for creating textual reports and debugging hence it remains; but you can only output in ASCII text - format 2.

For writing a number of specific frames to file, you may find a combination of omitline() and appendframe() (etc) will be more flexible.


cache_coeur()

cache_coeur( <setflag> )

This command is not available in
the RISC OS script interpreter.

Description

This sets or unsets the state of the cache entries depending upon the value of setflag, which in turn controls the availability of that frame to the script interpreter. If this is not clear to you, read up on cache control. This command is primarily intended for use as a debugging aid.

0 | All cache entries are marked as not being script-related, so the script will not be able to access anything that is cached.
1 | All cache entries will be marked as available for use by the script. This is a quick'n'easy way to make a variable amount of data (i.e. the existing cache contents) available for use in cache code without having to wait for page loads.

Specifics

Current versions of WinTTX do not store fetched pages with a subframe number, so requesting specific frames may fail even if that frame is available (re. appendgivenframe() etc). This command is better used prior to 'walking' the cache (re. cache_loadnextentry()).


cache_flush( )

Description

This erases the cache contents. Totally. Everything. Forever.

It is designed as a debugging aid. Do not use it liberally in scripts you create which may be used by others, they may not appreciate their cache being cleared.

Notes

If, for some reason, you wish to clear the cache insofar as previous script-cached-frames will no longer be available, you should use cache_coeur(0) - i.e. the cache_coeur command with a value of zero.


cache_insertfile()

cache_insertfile( <"path">, <frame>, <subframe> )

Description

This causes a teletext frame to be loaded from disc and inserted into the cache, as if it had been fetched off-air. You can specify particular frame/subframe numbers, or set both to -1 in order to use the values stored within the frame.

This is a useful debugging aid for scripts that fetch a number of pages and then process them. If the processing part needs debugging, you can simply fetch the pages manually and store them on disc. Then simply amend your script to temporarily load the frames from disc instead of off-air. Instant speed saving!

Notes

If you provide specific frame and subframe numbers, these will be written into the frame data so that they are available for future reference. This means the frame data is altered.

Specifics

Please note the difference in file paths and names between RISC OS and Windows - refer to path specifiers for further information.


cache_loaddirectory()

cache_loaddirectory( <"path"> )

This command has not yet been implemented in WinTTX.

Description

This is like a souped up version of cache_insertfile(), where an entire directory will be scanned and every teletext frame (RISC OS: type &112; Windows: extension .ttx) that it finds will be inserted into the cache, with frame numbering read from the contents loaded; and the expiry time set to the time of loading.

RISC OS: An hourglass will appear, the percentage counter reflecting how many files have been checked (not a true percentage!).
This procedure does not poll, and is not very fast.

Notes

Behaviour is 'undefined' if multiple frames evaluate to the same frame and subframe reference.

File scanning does not recurse into subdirectories.

Specifics

Please note the difference in file paths and names between RISC OS and Windows - refer to path specifiers for further information.


cache_loadnextentry()

cache_loadnextentry( <offset (var)> )

This command has not yet been implemented in WinTTX.

Description

This permits you to 'walk the cache', though note that behaviour is different for RISC OS and Windows. In either case, the offset must me a variable and not a simple number.

RISC OS: The offset is a pointer into the cache index file, and hence must be a number divisible by twenty (starting from zero).
The value returned in offset is the file pointer after the cache entry has been read, i.e. either EOF or the next one to read.
If there was a problem or nothing to read, then offset will be set to -1.

Windows: The offset is a pointer into the cache index, which nominally starts at 1, though 0 will be accepted for compatibility with RISC OS.
The return value is an array index so can be any number, not just multiples of 20; and the value returned is the current array offset plus one, or -1 if there was a problem or no more cache entries.

In both cases: If offset is not -1, then the current frame data will have been updated.
Because the script can only access frames that it saved into the cache, note that the return value may well skip or be in no particular sequence. The only guarantee is the value returned will be higher (if a frame was found) or -1 (if not).

Example

Here is an example of script code to walk the cache on both operating systems:
  set A to 0
  .scanloop
    cache_loadnextentry(A)
    if (A = -1) go("scanend")
      [code to fiddle with the frame data goes here]
    if (A ! -1) go("scanloop")

  .scanend
    [and so on...]


call()

call( <"label"> )

Description

This branches to the specified label (much like the go() command), however it remembers the location that you 'called' from in order that you can later return() back to that location. In this way, you can implement basic subroutines.

Example / explanation

Consider:
[...file opened...]
set F to 101
call("outputpage")

set F to 102
call("outputpage")

[...file closed...]
terminate()

.outputpage
  selectframe(F)
  set B to status(frames)
  if (B = 0) appendframe(F)
  if (B ! 0) appendframes(F)

  return()

What will happen, is...

Set 'F', our frame number, to 101.
Call 'outputpage'.
Outputpage: Select the given frame, in this case 101.
Outputpage: Are there any subframes?
Outputpage: If there are NO subframes, write the frame to the file.
Outputpage: If yes, write the frames (all of them) to the file.
Outputpage: Return to caller.
Set 'F', our frame number, to 102.
Call 'outputpage'.
Outputpage: Select the given frame, in this case 102.
Outputpage: Are there any subframes?
Outputpage: If there are NO subframes, write the frame to the file.
Outputpage: If yes, write the frames (all of them) to the file.
Outputpage: Return to caller.

Specifics

Under RISC OS, you may only call() to a maximum of 16 levels deep. The Windows script interpreter has no such limitation.
Note, also, that the RISC OS script interpreter only permits up to 16 labels to be defined, which may prove more restictive.


channel()

channel( <channel / tuning> )

Description

This instructs the teletext receiver to switch to the specified channel.

Specifics

RISC OS uses 'channel presets' where the channel settings are made in the !Teletext configuration, and then you choose the channel as a number from 1 to 9. It is not possible to select a specific UHF channel; and values outside of the permitted range will be faulted.

Windows does not offer 'channel presets', so you should specify an absolute UHF channel in the range 21 to 69; and other values will be faulted.

Undocumented...

The television broadcasting frequencies are split into three 'bands'. The first of these is BAND I which is 47-68MHz (nominally channels 2 to 4). The second of these is BAND III which is 174-230MHz (nominally channels 5 to 12). The latter, and the only frequencies available in the UK is BAND IV-V which is 470-862MHz (channels 21 to 69).

It is with apologies to European viewers that WinTTX does not specifically support frequencies outside of the 21-69 range. To be honest, I am not certain if the tuner is physically capable of receiving such frequencies.

If you are Belgian and you are willing to give this a try, WinTTX (v1.50) will accept three special channels as follows:

75 | 175.25MHz | Corresponds to La Une in Dinant / Houffalize / Malmedy
89 | 189.25MHz | Corresponds to La Une in Bruxelles
96 | 196.25MHz | Corresponds to La Une in Wavre
Please note that this is acheived purely by synthesising the data to instruct the tuner to tune to those frequencies. I will not be held liable for damage incurred as a result of trying this; however if you do try this, please let me know how you get on.

Why Belgium? Because RTBF Sat teletext listed the frequencies.

Why is there no sound in Europe?
If you connect a lead to the Aux port (audio/video output), you will not hear any sound in Europe using a Ground Control/Octopus receiver (and probably not with others, either). This is because the UK uses PAL I where the sound carrier is +6MHz from the tuned channel; however Europe uses PAL B/G where the sound carrier is only +5.5MHz. A good television engineer may be able to rectify this by altering something inside your tuner.

Related information
channelid()
set() for "status(channel)"
La une: 5 175.25 Dinant / Houffalize / Malmedy 7 189.25 Bruxelles 8 196.25 Wavre


channelid()

channelid( <variable> )

Description

This sets the specified variable to the channel ID as broadcast in the TSDP packet.

Each channel is supposed to broadcast their identity, however a number (such as the BBC on digital satellite) either don't broadcast a TSDP packet or they broadcast a null identity (which is either &2020 or &0000).

Notes

I do not have IDs for the UK terrestrial channels. If you can help, please get in touch.

Here are the identities of some FTA channels from the SkyDigital platform (Astra 2 at 28.2°E and EuroBird at 28.5°E):

BBC One South | No ID |
BBC Two England | No ID | Very reduced service, go to p199 for index.
Channel Four | &3F8B | Only carries subtitling?
S4/C Digidol | &2DE3 | Index is on p400.
Sky News | &3F5F | Mostly 'betting' information.
EuroNews | &0000 | Invalid identity.
Sky News UK/Eire (Cable) | &3F9F | A better Sky teletext service!
Travel Channel | &8888 | Doesn't sound like a real ID.
There are other teletext services available, but generally these are only for subtitling, such as ITV, E4/More4/Film4...

Here are the identities of some FTA channels from the Astra1 platform (Astra 1x at 19.2°E):
(note that the third column lists the language, not the country of origin)

3sat | &92E3 | German
Andalucìa TV | No ID | Spanish
arte (French) | &CC50 | French/German
arte (German) | &9250 | German/French
BBC World | &22EA | English
BR-alpha | &9222 | German
BVN | &8C80 | German
Bayerisches | &92D3 | German
CNBC Europe | &714E | English
Comedy Central | &0000 | Invalid ID, German
CT24 | &4250 | Polish (partial charset in WinTTX)
Das Vierte | No ID | German
dhd24 | &7315 | German teleshopping
DMAX | &0000 | Invalid ID, German
DSF | No ID | German
Eins / ARD1 | &9280 | German
EinsFestival (ARD1) | &9282 | German
EinsPlus (ARD1) | &9242 | German
EuroSport (DE) | No ID | German
hr fernsehen | &92FF | German
HSE24 | No ID | German teleshopping
K-TV | No ID | German
Kabel-1 (either) | &0000 | Invalid ID, German
KI.KA | &9293 | German
MDR (any) | &927F | German
MTV (DE or CH) | &0000 | Invalid ID, German
N24 | No ID | German
NDR (any) | &0000 | Invalid ID, German
NICK(elodeon) | &0000 | Invalid ID, German
n-tv | No ID | German
Phoenix | No ID | German
ProSeiben (either) | No ID | German
RAI Uno | &9C80 | Italian
rbb | &9241 | German
rhein main tv | No ID | German
RTBF | &4CE0 | French (Belgian)
RTP | &AC08 | Portuguese
RTL (any) | &8C00 | German
RTL II (any) | &0000 | Invalid ID, German
Sat.1 (either) | No ID | German
Sky News | &3F9F | English
SRF | &0000 | Invalid ID, German
SWR - Baden/Württemburg | &9287 | German
SWR - Rheinland/Pfalz | &9227 | German
Sonnenklar | &0000 | Invalid ID, says it is "MTVText"! German
SuperRTL (any) | &0000 | Invalid ID, German
Tele5 | &927F | German
TeleMadrid | &0000 | Invalid ID, Spanish
TRT | &0980 | Turkish (no charset in WinTTX)
TRWAM | &0000 | Invalid ID, Polish (partial charset)
TV3 | &0C1E | Spanish
TV5 (FBS) | &AF00 | French (Swiss)
TV5 (Europe) | &AF00 | Service identical to TV5 FBS
TVE Internacional | &4700 | Spanish
TV Galicia | &482C | Galician (Spanish)
TVP Kultura | &1205 | Polish (uses UK charset!)
TV Polonia | &1208 | Polish (uses UK charset)
TW1 | &C220 | German
Viva | &0000 | Invalid ID, German
VOX (any) | &0000 | Invalid ID, German
WDR (any) | &0000 | Invalid ID, German
ZDF (any) | &9240 | German
Note that many German services put the programme name in the channel name area, so that televisions equipped to display the channel name when changing channel (my Daewoo did that) will instead tell you what you are watching.

Related information
channel()
set() for "status(channel)"


set()

set <variable> to <value>

Description

This sets the specified variable to the value provided.

Setting to a constant

You can specify a constant or an alternative variable by using the following:
set A to 123
set R to 12.34
set B to %1100
set M to A

When assigning a float to an integer, the value is rounded down. You should use roundcast() to round to the nearest value.

Reading from the teletext frame

You can use the syntax char( <x>, <y> ) to provide a byte read from the currently selected teletext frame.
The X value is in the range 1 to 40, and the Y value is in the range 1 to 25. The following returns the second character of the header line (usually a 'P' (ASCII 80)):
set A to char(2, 1)

setchar() is the logical opposite of this.

Setting to a status value

You can use the syntax status( <option> ) to provide information on various miscellaneous items that may be of use.

Note that the status parameters are macros, not strings, therefore they are not quoted. For example:

set A to status(channel)

The available status options are:

  • set A to status(cachesize)
    This will return how many cache entries are available for use by the script interpreter.
    RISC OS: This returns the entire 'size' of the cache, not how many the script can access.
  • set A to status(channel)
    This returns the current channel preset, in the range 1 to 9.
    Windows: This always returns -1; and hence is a simple way to detect which operating system the script is running on.
  • set A to status(file)
    Windows: This returns the file handle of the user I/O file, or -1 if the file is not open. There is little you can do with this information as it is not a system-wide handle.
    RISC OS: This returns the file handle of the user I/O file, or 0 if the file is not open. This is a system-wide handle and may be passed to other programs (though doing so will be tricky!).
  • set A to status(framenum)
    This returns the true frame number, in the form &ppp00ss. There is not much use for this!
  • set A to status(frames)
    This will interrogate the cache and return the highest subframe number of the currently loaded page, or 0 if no frames exist.
    selectframe(123)
set A to status(frames)
if (A = 0) error("Frame 123 is not cached.")
  • set A to status(pagefound)
    This returns 1 if the specified frame was found and cached, or 0 if the getframe() / getframes() command timed out.
  • set A to status(pagenum)
    This returns the page number of the currently selected page, in the range 100 to 899 (i.e. as a decimal number).
  • set A to status(progver)
    This returns the program version multiplied by 100; so WinTTX v1.51 is given as 151.
  • set A to status(scriptver)
    This returns the script interpreter version multiplied by 100. At time of writing, the latest RISC OS interpreter is 107 (v1.07) and the latest Windows interpreter is 108 (v1.08).
  • set A to status(channel)
    This returns the current channel preset, in the range 1 to 9.
    Windows: This always returns -1.
  • set A to status(ttxon)
    This returns 1 if the teletext receiver is connected and operational, otherwise it returns 0.
  • set A to status(uhftune)
    This returns the current UHF tuning, in the range 21 to 69.
    Windows: This should be used instead of channel.
  • set A to status(riscos)
    Windows: This always returns 0.
    RISC OS: This option has not been implemented.
  • set A to status(windows)
    Windows: This always returns 1.
    RISC OS: This option has not been implemented.

Specifics

Refer to the individual descriptions for information on variations between the RISC OS and Windows interpreters and their respective capabilities.


div()

div( <var>, <num1>, <num2> )

Description

This will set the specified var to the result of num1 divided by num2.

Example

A = B ÷ 2 (result will be an integer):
div(A, B, 2)
R = T ÷ Z (result will be a float):
div(R, T, Z)

Related information
Mathematics


eggy( )

This command is not available in
the Windows script interpreter.

RISC OS: Warning - not 32-bit clean.

Description

"Easter egg" command. Takes a random page of the page buffer and disassembles it...
DEPRECATED. (and not documented until now!)


eor()

eor( <var>, <num1>, <num2> )

Description

This will perform a logical Exclusive OR as follows:
Take num1 and EOR it with num2, write the result to var.

Example

A = B EOR 255
eor(A, B, &FF)

Notes

EOR inverts the specified bits. It is algorythmically regular in that a byte, when EORed with a specific value, can be restored by EORing it with that same value again.

The difference between this and not() is that you can control which bits you with to invert, while not() inverts them all.
A 'not' operation is equivalent to exclusive ORing with all bits set. Both of these commands perform the exact same action:

eor(A, B, -1)
not(A, B)

Specifics

Because so much PC-related software uses the parlance "Xor", this version is also accepted by the Windows interpreter.
Related information
Mathematics


error()

error( <"message"> )

Description

This reports an error message to the user, and then aborts script processing.

Example

set A to status(channel)
if (A ! -1) error("Sorry, this script is not RISC OS compatible.")

Related information
Program flow


execfile( )

This command is not available in
the RISC OS script interpreter.

Description

This will look at the last file that the script wrote to and attempt to find a handler for it according to its type, namely:
.txt | Text file | Loads into Notepad
.htm or .html | Hypertext file | Loads into Internet Explorer
.dpd | OvationPro file | Loads into OvationPro

When a handler is found, the file will be loaded into that program.

This command asks the system, so it will detect if OvationPro is not present, and also if you have set up to use Firefox (etc) instead of MSIE.

Notes

The file verification stage, which takes place as the file is opened/created will block attempts to overwrite system files, to create .EXE or .DLL (etc) files.
While I cannot guarantee this system is completely secure, I have taken a number of steps to prevent scripts from performing destructive actions.

Related information
File handling


fileclose( )

Description

This will close the user file which was earlier opened with filewrite() (create) or fileupdate() (append).


fileextn()

fileextn( <"extension"> )

This command is not available in
the RISC OS script interpreter.

Description

This is the Windows equivalent of filetype(). It is provided for completeness, and should not really be used.

Notes

You are restricted to dpd, html, and txt being appended to the name of the last created/opened file.

It is much better to set the correct filename (with extension) when the file is opened.

Related information
File handling


filetype()

filetype( <"name">, <type> )

Description

This RISC OS command sets the specified file to the specified type. Type is usually &FFF for ASCII text files.

Under RISC OS, a side-effect of this command is the output file, if open, will be closed.

Specifics

Under Windows, this command will recognise &B25 (.dpd), &FAF (.html), and &FFF (.txt) and it will convert this to an extension and set this extension to the correct type.

It is much better to set the correct filename (with extension) when the file is opened.
This command is necessary under RISC OS where the filetype is metadata separate to the filename, however Windows works differently.

Related information
File handling


fileupdate()

fileupdate( <"filename"> )

Description

This opens the specified file for update. You can only have one file open at any given time.

If the file exists, it is opened and the file pointer set to the end of the file so your output is appended to the end of the file. If the file does not exist, it is created.

This has the same behaviour as BASIC's OPENUP command (OS_Find &Cx); or in C, the "rw+" options to fopen().

If you want to create a new file, overwriting previous contents, refer to filewrite().

If a file is already open, an error will be generated and script processing terminated.

Specifics

Please remember that paths are completely different under Windows and RISC OS.


filewrite()

filewrite( <"filename"> )

Description

This opens the specified file. You can only have one file open at any given time.

If the file exists, it is erased and a new blank file created in its place. If the file does not exist, it is created.

This has the same behaviour as BASIC's OPENOUT command (OS_Find &8x); or in C, the "w" options to fopen().

If you want to update an existing file, appending to previous contents, refer to fileupdate().

If a file is already open, an error will be generated and script processing terminated.

Specifics

Please remember that paths are completely different under Windows and RISC OS.


filewritebyte()

filewritebyte( <value> )

Description

This outputs the byte given to the file, which must previously have been opened.

Example

This RISC OS example creates a file and writes all byte values from zero to 255:
filewrite("<Teletext$Temp>.temp")
set A to 0
.loop
  filewritebyte(A)
  A++
  if (A [ 255) go("loop")
fileclose()
filetype("<Teletext$Temp>.temp", &FFF)
oscall("%Filer_Run <Teletext$Temp>.temp")

Or, in Windows style:

filewrite("#TEMP#\temp.txt")
set A to 0
.loop
  filewritebyte(A)
  A++
  if (A [ 255) go("loop")
fileclose()
execfile()

A more useful application is to output newlines between frames to space things out better.

Specifics

Some Windows software (i.e. Notepad) is unable to correctly cope with text files that do not have CRLF line termination.
Hence where you might use the following under RISC OS:
filewritebyte(10)
You would need to use the following in Windows:
filewritebyte(13)
filewritebyte(10)


filewritefloat()

filewritefloat( <var>, <left>, <right> )

Description

This writes the specified floating point variable to the file, with left and right specifying how many digits are on the left and right of the decimal point.

Notes

Left value - if there are fewer actual digits then the leftmost positions are space-padded, and if there are more digits, the leftmost are clipped.
Right value - if there are fewer digits after the decimal place, the rightmost positions are zero-padded, and if there are more, the rightmost are clipped (NOT rounded).

If you pass an integer variable, it is displayed in the same way.

Example

If Z is 1234.5678, then:
filewritefloat(Z,4,2)
outputs "1234.56".
filewritefloat(Z,2,2)
outputs "34.56".
filewritefloat(Z,3,3)
outputs "234.567".
filewritefloat(Z,5,5)
outputs " 1234.56780".

If A is 123, then:

filewritefloat(A,4,2)
outputs " 123.00".
filewritefloat(A,2,2)
outputs "23.00".
filewritefloat(A,3,3)
outputs "123.000".


filewritehtmlhead() / filewritehtmltail()

filewritehtmlhead( )
filewritehtmltail()

HTML output is not available in
the RISC OS script interpreter.

Description

If you choose to output an HTML file, you will need a valid 'header' to tell your browser that it is a valid marked-up document; plus a valid 'footer' to correctly close the document.

Example

Thus, to output an HTML file, you would:
filewrite("news/html") ; "news.html" under Windows
filewritehtmlhead() ; must be the FIRST thing you output
; output the frames, ie:
; appendframe(x,4)
; in a loop, or whatever
filewritehtmltail() ; must be the LAST thing you output
fileclose()
filetype("news/html", &FAF) ; not under Windows...
In the commented middle section, you can output entire pages, partial pages (via omitline()), or custom HTML.

Notes

The header and footer output are fairly minimal header.

If you would prefer something better (perhaps a custom background graphic), then you'll need to NOT use the "filewritehtmlhead()" command, and instead output your own header.

Specifics

There is no support for HTML output in the RISC OS !WinTTX.


filewriteovnhead() / filewriteovntail()

filewriteovnhead( )
filewriteovntail()

Description

If you choose to output an OvationPro DDL file, you will need a valid 'header' to tell OvationPro that it is a DDL file, and the colours that'll be used; plus a valid 'footer' to correctly close the document.

Example

Thus, to output an OvationPro DDL file, you would:
filewrite("myddlfile")
filewriteovnhead() ; must be the FIRST thing you output
; output the frames, ie:
; appendframe(x,3)
; in a loop, or whatever
filewriteovntail() ; must be the LAST thing you output
fileclose()
filetype("myddlfile", &B25) ; not under Windows...
In the commented middle section, you can output strings and bytes if you know the OvationPro DDL script.

Notes

The header output is a minimal header. It basically says "this is a DDL script, and these are our colours". Everything else: page size, styles, etc is left to OvationPro, which will take them from the 'default' document.

If you would prefer a better format (like a page that fits the frames) then you'll need to NOT use the "filewriteovnhead()" command, and instead output your own header; which will be possible but non-trivial.


filewritestring()

filewritestring( <"string"> )

Description

This writes the specified string literal to the file.

Example

filewritestring("BBC World news headlines")
filewritestring("========================")
filewritebyte(13)
filewritebyte(10)
filewritebyte(13)
filewritebyte(10)

Specifics

It is not possible to copy strings out of the teletext page. This action should be performed by reading the frame character by character and writing bytewise to file, as this example shows:
filewritestring("                  Sky  = ")
set A to 30
.reportloop
  set B to char(A, 17)
  filewritebyte(B)
  A++
  if (A [ 40) go("reportloop")
filewritebyte(13)
filewritebyte(10)
This example copies the weather 'forecast' word (cloudy, rain, snow, etc) from the frame.


filewritevar()

filewritevar( <var>, <num> )

Description

This writes the specified variable to the file.

For float variables... The number specifies how many decimal places the output is written as. For example, if Z is 0.123456, then:

filewritevar(Z,2)
outputs 0.12.

For integer variables... The number specifies an alignment. The output is padded to this size, with spaces on the left. For example, if A to 47, then:

filewritevar(A,5)
outputs " 47".


find() / findend()

find( <var>, <"findstr">, <num> )
findend( <var>, <"findstr">, <num> )

Description

The specified numerical value 'num' gives the line number in which to look for 'findstr', and if it is found, then the variable 'var' is updated to show the offset into the line where the string was found.
You can then use readvalue() to extract information, or copy text byte-by-byte.

Searching is not case sensitive.

Example

If we assume that the 16th line of a teletext page reads:
The average precipitation in January is 17mm/day
We can use the find() or findend() commands to search for offsets in this line.

If we look for precipitation:

find(A, "precipitation", 16)
then:
The average precipitation in January is 17mm/day
            |            |
  find points here       findend points here

Related information
findany()


findany()

findany( <var>, <"findstr"> )

This command is not available in
the RISC OS script interpreter.

Description

This looks for the specified string 'findstr' in the frame, starting with the line passed in 'var'. If a match is found, then 'var' is updated with the matching line, else it is set to 0.

Notes

While find()/findend() look for offsets of strings in a line, this looks for the lines of strings in a frame.

Example - findany() vs find()

Read the following amusing report from BBC World (available as "testpage0.ttx" in with the scripts):

We are going to step through and look for each occurance of the word "sheep". Using the find() command, the code would look like:

; ...set up stuff...
; Look for "sheep"! [NOT case sensitive]
set A to 1
.loop
  find(B,"sheep",A)
  if (B = 0) goto("carryon")

  ; this code called when there is a match
  ; ...code here...

.carryon
  A++
  if (A [ 24) go("loop")

; ...done, tidy up...

Now for a version using the findany() command:

; ...set up stuff...
; Look for "sheep"! [NOT case sensitive]
set A to 1
.loop
  findany(A, "sheep")
  if (A = 0) goto("finish")

  ; this code called when there is a match
  ; ...code here...

  A++
  go("loop")

.finish
; ...done, tidy up...

While it may look substantially similar, we can observe that A steps through each line and calls find() twenty four times in the first example; looking for a non-zero result (i.e. a match).
However, in the second example, A starts at 1, jumps to 5, then 7, 10, 19, and finally 0 (i.e. no more). In all, findany() is called five times.
Furthermore, if the chosen word was not present on the page, then findany() would immediately return 0; while with find() you would need to search each line.

Specifics

This command is not available under RISC OS.

Under Windows, both of the above examples are available as full scripts - Test_Find and Test_FindAny respectively.

Related information
find() / findend()


flatten()

flatten( <variable>, <number> )

Description

This 'flattens' the specified floating point variable to a given number of decimal places.

Sometimes a calculation can result in an annoying recursive number, for example '15 / 9' results in 1.66666667. To keep things sane, you can flatten to two decimal places to convert that into 1.66.
Note that this simply chops off the end of the variable, no rounding is performed.

Notes

One of the biggest causes of failure of if() statements is overzealous accuracy - keep to the degree of accuracy that is necessary, and no more, for 1.2345678 is not 1.234567.

Nothing should happen, but technically "behaviour is undefined" if you request an invalid degree of accuracy (like 20dp), request a higher accuracy then your input (i.e. 1.23 to 5dp), or try to flatten() an integer variable.

Specifics

Under RISC OS, !Teletext runs under the integer maths BBC BASIC V, which offers IEEE-like floating point precision to nine decimal places (the FP version offers true IEEE FP; but we don't require that).
Under Windows, WinTTX actually works to a higher degree of accuracy, however at all points of transferring or storing numerical values, the script interpreter will implicitly round down to nine decimal places.

Related information
Mathematics


frame_language()

frame_language( <variable> )

Description

This sets 'variable' to the language of the current frame.

0 | English
1 | French
2 | Swedish
3 | Czech
4 | German
5 | Spanish
6 | Italian
7 | undefined

Specifics

The Czech language will be reported under RISC OS, however there is no character set support for Czech pages.

This relates to pages which are compliant with Western European teletext hardware. Pages in Turkish (such as TRT on Astra 19.2°E), Hebrew, Arabic, etc will appear to misreport their language because they are aimed at teletext hardware with different character sets. There is no support for non-Western languages in either !Teletext or WinTTX.

There are certain (rare) times when the header and the page use different languages. This is supported by the teletext system (and !Teletext under RISC OS) but not by WinTTX. However, for the purposes of the script, the frame language is the language that is returned.


frame_linkedto()

frame_linkedto( <variable> )

Description

This sets 'variable' to the page number of the specified link.

On entry, 'variable' should be:

1 | RED link
2 | GREEN link
3 | YELLOW link
4 | CYAN link

Specifics

The page numbers are returned in base ten (i.e. p101 is 101), which may be used with the majority of the script commands which also work in base ten.
If you would like actual hex values returned (i.e. p101 is 257), add '16' to the value set in variable on entry.


frame_number()

frame_number( <variable> )

Description

This sets 'variable' to the page number of the current page, in p### form.

On entry, 'variable' should be 16 to have the page number returned in hex.


frame_subnumber()

frame_subnumber( <variable> )

Description

This sets 'variable' to the subframe page number of the current page, in p###.# form, a number between 0 and 15.

On entry, 'variable' should be 16 to have the page number returned in hex.

Notes

If a page has no subframes, then this may validly return 0.

Technically, this returns the value of the Minutes-Units byte (which is a four-bit value); thus pages with more than 15 subframes will be reported incorrectly; however it is rare to have a page with so many subframes.
If you require handling for larger values, please get in touch with me.


getframe()

getframe( <page> )

Description

This requests the next broadcast frame of the specified page. The frame, when retrieved, is stored in the cache.

Frame searching will time out after 90 seconds, if nothing is found.

Notes

If you want to retrieve all the frames of a cycling page (ie, TV guide or 'letters'), you'll want to use getframes() instead.

Specifics

RISC OS will time out a frame request after 60 seconds.


getframes()

getframes( <page> )

Description

This requests the next broadcast frame of the specified page. The frame, when retrieved, is stored in the cache, and this process will repeat until all subframes of the specified page have been retrieved and stored.

There is special handling to cater for some teletext services which broadcast each subframe twice.

Frame searching will time out after 90 seconds, if nothing is found.

Notes

If you want to retrieve only a specific single-frame page, you should use getframe() instead.

Specifics

RISC OS will time out a frame request after 60 seconds.


go()

go( <"label"> )

Description

This branches to the specified label; which means that the execution of the script 'jumps' to the specified location.
You can branch to any label, forwards or backwards.

Examples

This example following shows a simple loop:
set A to 0
.loop
  A++
  go("loop")

Remember, you can branch forwards and backwards. This can be used to implement platform-specific code selection, such as is shown in this example:

; are we running under RISC OS or Windows?
set O to status(channel)
if (O = -1) go("initwin")   ; channel is ALWAYS "-1" under WinTTX

; here? we're running under RISC OS
filewrite("<Teletext$Temp>.Report")
go("initcontinue")

.initwin
; else it is WinTTX
filewrite("#TEMP#\report.dpd")

.initcontinue
[and the commands to write to the file go here...]


if()

if( <var> <cond> <num> ) <command>

Description

In an if() statement, the clause specified is evaluated. If it evaluates to be true then the following command is executed, otherwise script processing picks up on the next line.

  • 'var' is a variable.
  • 'cond' is a condition code (described below).
  • 'num' is either a constant number or a variable.
  • 'command' is any valid line of code.

The available condition codes are:

= | Equal
! | Not equal
< | Less than
> | Greater than
[ | Less than or equal to
] | Greater than or equal to

Notes

There is no restriction on what follows an 'if()' except that it cannot be a control statement or a label.

If A is zero, make it one:

if (A = 0) set A to 1

You can even chain if() statements:

set A to 1
set B to 2
set C to 3
if(A = 1) if(B = 2) if(C = 3) message("Three times a lady!")
quit()

Specifics

There are internal differences in the way if() statements are handled under RISC OS and Windows, though the end result is the same.
The RISC OS implementation does not poll between processing, though it is not anticipated that this would make much difference.
The Windows version is internally recursive, however it has been tested and proven with a line of code consisting of 1024 chained if() statements (the "IfInsane" test script)... this test script will not work under RISC OS as the maximum line length is 256 characters.

Related information
Program flow


info()

info( <"message"> )

This command is not available in
the RISC OS script interpreter.

Description

This will output the specified message to the lower line of the status window.

Specifics

If you wish to write custom messages to the status message window under RISC OS, use the poll_message() command.


keypress()

keypress( <"key specifier"> )

This command is not available in
the RISC OS script interpreter.

Description

This will send a keycode to the currently active process.
For a list of available keycodes, refer to relevant Windows API (re. SendKeys).

Notes

It is dangerous to perform this command, as the Windows process scheduling does not offer any definite guarantees as to how processes are executed and how/when they run.

For example, under RISC OS it is possible to Filer_Run a textfile, and you know that the system will be locked as !Edit loads. One poll (for !Edit to clear its own backlog of init messages) and we can then output a Ctrl-Down keypress to jump to the bottom of the document...
If we load a file into Notepad, how many times will the script interpreter be scheduled as this happens? How about on a slower computer with a busy workload (where it seems XPs scheduling can be a bit erratic). What if tasks are set to not steal the application focus? Who/what will receive the keypress in that event?

However... this command is provided in case you want to play, but note that getting something to work on your system is no guarantee it'll work on others.

Example

This theoretically does the same thing as the RISC OS version... load the file and go to the bottom of the document:
...file is created...

execfile()
poll_now() ; can't hurt!
keypress("^{End}")

Specifics

RISC OS: Use the pushkey() command instead.

Related information
pushkey()


lsl()

lsl( <var>, <num1>, <num2> )

Description

This calculates the result of num1 << num2 and places the result in the specified variable.

Example

A = B << 2:
lsl(A, B, 2)


lsr()

lsr( <var>, <num1>, <num2> )

Description

This calculates the result of num1 >> num2 and places the result in the specified variable.

Example

A = B >> 2:
lsr(A, B, 2)


lvar( )

Description

This will generate a 'report' on the state of the script environment. This report will either (RISC OS) be written to the logfile; or (Windows) to a text file which will be opened in Notepad.

Examples

Here is an example of the RISC OS report, taken from the end of a successful execution of the "weathrtest" script:
LVAR (weathrtest)
=================

Integer variables:
  A = 0
  B = 0
  C = 0
  D = 0
  E = 0
  F = 3
  G = 4
  H = 0
  I = 0
  J = 0
  K = 0
  L = 25
  M = 15
  N = 0
  O = 0
  P = 0

Float variables:
  Q = 0
  R = 0
  S = 0
  T = 0
  U = 0
  V = 0
  W = 0
  X = 0
  Y = 0
  Z = 59

Branch positions:
  frameloop,           266; 17
  lineloop,            315; 21

Miscellany:
  Script file handle   254
  User file handle     253
  Current line number  50

And here is an example of the Windows report, taken from the end of a successful execution of one of the test scripts:

LVAR - Test script: 'Call' system
=================================

Integer variables:            Float variables:
  A = 0                         Q = 0
  B = 0                         R = 0
  C = 0                         S = 0
  D = 0                         T = 0
  E = 0                         U = 0
  F = 0                         V = 0
  G = 0                         W = 0
  H = 0                         X = 0
  I = 0                         Y = 0
  J = 0                         Z = 0
  K = 0
  L = 0
  M = 0
  N = 0
  O = 0
  P = 0

Branch positions:
  Offset  Line  Name
  152       14  one
  242       20  two
  345       27  three
  457       33  four

Call stack:
    4 --> +398   line  30
    3 --> +290   line  23
    2 --> +194   line  17
    1 --> +101   line   6

Miscellany:
  Script file reference  2
  User file reference    No file open
  (Last) User file name  ""

  Last error message     (no errors encounted)

  Current line (content) "lvar()"
  Current line (linenum) 37
  Current line (offset)  510
  Size of script (lines) 39
  Size of script (bytes) 722

  Most recent channel    55
  Most recent page fetch 100

  WinTTX version         1.50r0 (2008/08/08)
  PtrIIC version         0.10
  Cable known connected? Yes

[end of status report]

Specifics

It can sometimes be difficult to work out what exactly a syntax error message is saying. For this reason, WinTTX has an option where you can perform an implicit "lvar" upon a script error, which makes it so much easier to track down errors.

The report files in Windows are stored in your Temp path, with a filename such as "ScrLog_0808082208-3853.txt", which my be broken down as "yy mm dd hh mm ss - tttt" (where 'tttt' is the last four digits of the value of the system ticker so no two files will have the same name).
These files are not currently deleted by WinTTX, you will need to periodically tidy Temp yourself.

Under RISC OS, this command needs a RAMdisc to be active as it writes to "RAM::RamDisc0.$.ttxscrplog" - if the file exists, the report will be appened. If the file does not exist, it will be created.


message()

message( <"message"> [,<type>] )

Description

This prompts the user with the message given, for example:
message("Please select \"BBC World\" (ch. FAV:30).")

On both Windows and RISC OS, script processing will be halted until the user has read the message and clicked the OK button.

There is an optional 'type' value which can be:

  • 0 or not specified, this will report a standard message:
  • 1, this will report an 'informational' message:
  • 2, this will report a 'warning' message:
  • 3, this will report a 'critical' message:

Specifics

RISC OS does not support escaped characters (i.e. the '\"') and it does not support the optional type, this would be ignored.

Related information
userchoice()


mod()

mod( <var>, <num1>, <num2> )

Description

This calculates the modulus of num1 / num2 and places the result in the specified variable.

Example

A = B MOD 2:
mod(A, B, 2)


mul()

mul( <var>, <num1>, <num2> )

Description

This will set the specified var to the result of num1 multiplied by num2.

Example

A = B × 2 (result will be an integer):
mul(A, B, 2)
R = T × Z (result will be a float):
mul(R, T, Z)

Related information
Mathematics


nop( )

Description

This does nothing.


not()

not( <variable>, <number> )

Description

This will set the value of variable to NOT number. The NOT operation simply inverts all of the bits.

In 'human' terms, this usually means:
A positive number becomes negative, less one; i.e. 4 becomes -5.
A negative number becomes negative, less one; i.e. -5 becomes 4.

Example

A = NOT 5
not(A, 5)

Notes

The difference between this and Exclusive OR is that the eor() command takes a mask of bits to invert. This simply inverts all of the bits.

Related information
Mathematics


omitline()

omitline( <line> )

Description

This will blank the line specified (from 1 to 25).

Blanking out lines has significance.
If the document header line (line #1) is blank, then when saving as ASCII text or OvationPro or HTML, any other blank lines encountered will be skipped over, so in this way it is possible to save only specific parts of the frame by 'omitting' the unwanted content.

Notes

Because the append functions load up the requested page/frame, you must call storeframe() after omitting lines, to ensure the cached version of the frame is up to date with your alterations.

Specifics

Under RISC OS, this command replaces the line with spaces. However it has been observed that 'iffy' digital satellite reception can lead to regions of the page being blank. While it is unlikely that the header line will be blank as this is the page/channel ID and the clock and the rolling page counter, it is a possibility.
Therefore, under Windows, the sequence "OMITOMITOMITOMITOMITOMITOMITOMITOMITOMIT" is used instead. At this time, both methods are accepted by the interpreter, in case you write your own blanks, however the next version of the Windows interpreter will probably not accept a line of spaces any longer.


or()

or( <var>, <num1>, <num2> )

Description

This will perform a logical OR as follows:
Take num1 and OR it with num2, write the result to var.

Example

A = B OR 32
or(A, B, 32)

Notes

A quick way to set upper case characters to lower case is to OR them with 32.
65 (capital A) OR 32 is 97 (lower case A).

On the face of it, an OR is an addition; however it actually sets bits instead of adding in a value. 97 OR 32 is still 97, because the bit is already set so there is no change.

Related information
Mathematics


oscall()

oscall( <"command"> )

This command is not available in
the Windows script interpreter.

Description

This command provides access to the RISC OS command line. It is intended for use with user files, to load them into specific software (i.e. %Filer_Run...) and the like.

Specifics

Due to the varied ways a person can mess up a Windows machine... "del \windows\win.com" or "format c: /u /y", it has been decided that command line access is too insecure for inclusion within the script language.

If you require a specific action to be performed that you would normally use the command line for, please contact me and I will add a script command to perform this action for you.


poll_disable( )

This command has no effect in
the Windows script interpreter.

Description

This will suspend polling. It permits computational parts of the script to execute more quickly at the expense of freezing all other applications. Only use this for short sections of script.

Specifics

This command is accepted by, and ignored by, the Windows script interpreter. Because of differences in the operating system, you cannot really suspend task switching... and anyway, there's rarely any need to do so on a reasonably fast PC.


poll_enable( )

This command has no effect in
the Windows script interpreter.

Description

If polling was previously suspended with poll_disable(), this will re-enable polling.

Specifics

This command is accepted by, and ignored by, the Windows script interpreter. Because of differences in the operating system, you cannot really suspend task switching... and anyway, there's rarely any need to do so on a reasonably fast PC.


poll_message()

poll_message( <"message"> )

This command has no effect in
the Windows script interpreter.

Description

This will output the specified message to the status message window; and as a side effect, if the window was hidden (using poll_nomessages(), it will reappear.

Specifics

This command is accepted by, and ignored by, the Windows script interpreter.
If you wish to write custom messages to the status message window, use the info() command.


poll_nomessages( )

This command has no effect in
the Windows script interpreter.

Description

This will remove the status message window from the screen. You can use the iconbar icon to access !Teletext functionality (such as aborting the script, etc).

Specifics

This command is accepted by, and ignored by, the Windows script interpreter. Because there is no 'iconbar' concept, removal of the status window would remove any way of sanely accessing WinTTX while a script is running.


poll_now( )

This command has no effect in
the Windows script interpreter.

Description

When polling has been disabled, you can use this command to force a poll at specific points in the script. This, when used carefully, may be used to balance script execution speed over computationally intensive parts against the multitasking speed of the computer (i.e. how much 'load' it appears to be under).

To be brutally honest, this may only be an issue on older 8MHz ARM2 machines. On anything later, especially getting into the RiscPC generation, there should be plenty of oomph to go around.
And if any Windows readers are strugging over all this polling stuff, I will ask how may 8MHz and 25MHz PCs are still likely to be in use? In fact, how many of them will be physically capable of running a 32 bit version of Windows (even Windows 95!) so that WinTTX may be installed?

Specifics

It is not technically true that WinTTX ignores this command. It actually causes the task message queue to be processed followed by a short 'sleep', this process being performed twice.
On slower machines, or machines being pushed (like a 300MHz box running XP, that sort of thing...), this may permit the status window to be redrawn if Windows itself scheduled something more important instead of the window redraw.


pushkey()

pushkey( <keycode> )

This command is not available in
the Windows script interpreter.

Description

This will send a keycode to the RISC OS WindowManager.
For a list of available keycodes, refer to relevant WindowManager documentation (PRM 3, StrongHelp OS manual, etc).

Example

A typical example is to output to a file and then run it, then force the cursor to the bottom of the document:
...file is created...

oscall("%Filer_Run <System$Temp>.MyDataFile")
poll_now()
pushkey(&1AE)

Specifics

Windows: Use the keypress() command instead.

Related information
keypress()


quit() / terminate()

quit()
terminate( )

Important note for RISC OS users
please read the 'Specifics' section.

Description

These commands end script processing. The difference is:
  • quit()
    If the user file is open, you will be warned.
    If the call stack is not empty, you will be warned.
  • terminate()
    Script processing finishes silently, with no warnings.
The difference is that quit() is the legitimate way to end a script, while terminate() is a drop-out method to be used upon handling an error.

Notes

Reaching the end of the script file is an implicit quit(). Under RISC OS this was considered not the correct way to finish, so you would be given a warning. This rule has been relaxed under Windows.

Specifics

YOU CANNOT USE QUIT() UNDER RISC OS - it quits !Teletext, not the script. You must use terminate() for both instances, and you will receive warnings for file left open, etc. There is currently no alternative.


readvalue()

readvalue( <var>, <x>, <y> )

Description

Given a specified position in the frame, try to read a numerical value, writing it to the specified variable.

Example

In order to read the Euro/Dollar rate from the following frame:
we would issue the command:
readvalue(Z, 27, 8)
and the result of this is that 1.4689 will be written to the float variable 'Z'.

Notes

If you specify a location that is non-numerical, the result should be zero.
If you specify something that is number-like (such as a phone number or a date, see the "15.08.08" at the bottom of the example), the results are undefined.

Specifics

Windows: The 'View -> Show codes' option plots a grid so you can count positions:
In addition, you can click whilst holding Ctrl and WinTTX will report the coordinates of where you clicked:


report_var()

report_var( <"variable"> )

Description

This command pops up a message informing you of the current value of the specified variable. This may be useful when debugging your scripts.

Examples

For integer variables, the reply looks like:

While for float variables, the reply looks like:


return( )

Description

After a call(), use this to return to where you called from.

The return point is the line following the call.

Example / explanation

Consider this example (with line numbers marked on the left for clarity):
--  [...file opened...]
23  set F to 101
24  call("outputpage")
25
26  set F to 102
27  call("outputpage")
28
--  [...file closed...]
35  terminate()
36
37  .outputpage
38    selectframe(F)
39    set B to status(frames)
40    if (B = 0) appendframe(F)
41    if (B ! 0) appendframes(F)
42
43    return()

The first call is line 24, which will cause execution to jump to line 38 (remember, labels record the line following the definition). The code in the subroutine nominally called 'outputpage' will be run, until we reach return at line 43. At this point, execution will be transferred back to line 25, which is the line following the call.

Notes

Obviously every call() must have a corresponding return(). It is valid to have multiple return points (i.e. off of if() statements), so long as logically you will only be able to take one path at a time.

Calling return() with no call stack is an error condition; so is finishing the script with a call stack in place (suggests a missing return()).

Specifics

Under RISC OS, you may only call() to a maximum of 16 levels deep. The Windows script interpreter has no such limitation.
Note, also, that the RISC OS script interpreter only permits up to 16 labels to be defined, which may prove more restictive.


roundcast()

roundcast( <var>, <num> )

Description

This converts the number specified into the variable specified, rounding to the nearest whole number.

Notes

This exists because 'set A to Z' rounds down, so 1.9 would become 1.

Specifics

RISC OS:
  • If you cast a float to a float, 0.5 is added.
    This is incorrect, and does not occur under Windows.
  • If you cast an integer to an integer, nothing is added.
    This is expected behaviour.
  • If you cast an integer to a float, 0.5 is added.
    This is incorrect, and does not occur under Windows.

Related information
Mathematics


selectframe()

selectframe( <page> )

Description

This makes the first located frame of the specified page the current frame.

Notes

For a page with subframes, the first subframe found in the cache will be the one set.
If you wish to specify a particular subframe to load, you should use the selectframes() command.

If the frame cannot be loaded for any reason, the current frame number will be set to 0. Script processing will continue. You should check the status to see if the frame was reloaded from the cache or not.

Related information
selectframes()


selectframes()

selectframes( <page>, <subframe> )

Description

This loads the requested subframe of the specified page and makes it the current frame.

Notes

If you do not wish to specify a particular subframe to load (i.e. you know the chosen page only contains one frame), then use selectframe() to load the first found.

If the frame cannot be loaded for any reason, the current frame number will be set to 0. Script processing will continue. You should check the status to see if the frame was reloaded from the cache or not.

Related information
selectframe()


selfexec()

selfexec( <"command"> )

This command is not available in
the Windows script interpreter.

Description

This will pass the command specified to the OS, with the filename of the current script appended.

Example

The use of this is demonstrated at the top of the textual helpfile, where the command:
selfexec("%Filer_Run")
will Filer_Run the help file, so if you try to execute the help as a script, it'll load itself into an editor after giving you a message. The lines in question are:
; This catches attempts to run this file as a script.
message("This is a help file, not a script!")
selfexec("%Filer_Run")
terminate()

Specifics

Because this implicitly provides access to the command line, and could be quite easy to circumvent (i.e. "format c: /u /y > "), it has been removed from the Windows script.

Related information
File handling


setchar()

setchar( <x>, <y>, <c> )

Description

This sets the specified character location ('x' = 1 to 40, 'y' = 1 to 25) to the specified character value ('c' = 0 to 255).

Notes

You can use the set <var> to char(<x>, <y>) command to read the value of a given character, the logical opposite of setchar().

Specifics

RISC OS: There is a macro that states if a null byte (value = 0) is encountered when exporting the file as ASCII, then the sequence <10><32> will be output. This is supposed to write a newline followed by a space, however it seems to output a newline too many and I've not gotten around to fixing this.
The space, incidentally, is so you can replace a colour code (which would be converted to a space) with this macro, and preserve text alignment.

Windows: The null byte behaviour is not supported.


showcachelist() / showcontrols() / showpreferred() / showviewer()

showcachelist( )
showcontrols( )
showpreferred( )
showviewer( )

These commands have no effect in
the Windows script interpreter.

Description

These open... the cache list, the control panel, the preferred pages list, or the viewer window.
You can use some, or all, of these to open windows prior to ending a script, so !Teletext pops back with the windows you normally have open.

Specifics

Under Windows, when the script has completed, the main viewer will reappear. This behaviour is fixed, hence these commands have no effect in WinTTX.


sign()

sign( <variable>, <number> )

Description

This sets the variable specified to the sign of the given number.

If the number is negative, the result is -1. If the number is zero, the result is 0. If the number is positive, the result is +1.

Related information
Mathematics


smartclear()

smartclear( <line> )

Description

This is indended to replace potentially convoluted code involving lots of loops and calls to setchar().
What this command does is it looks at the line specified (from 1 to 25), and blanks out everything that is marked as 'graphics', no matter where in the line. This, effectively, allows you to strip out graphical logos and 'clean' the page.

Example

Here is a frame before smart clearing:

And here it is after smart clearing:

Specifics

Windows: You can specify line 0 to clean the entire frame in one go.


sqr()

sqr( <variable>, <number> )

Description

This sets the variable specified to the square root of the given number.

Related information
Mathematics


storeframe( )

Description

When you have finished altering a frame (ie, omitline() et al), you should use this command to push the frame back into the cache so that it is available for further processing.
If you do not, then next time you select or otherwise reload the frame, it will pull 'the old copy' from the cache.


sub()

sub( <variable>, <number> )

Description

This will subtract the number given from the variable specified.

Examples

Subtracting a constant to a variable:
sub(A, 25)

Subtracting a variable from another variable (subtract B from A, result written to A):
sub(A, B)

Related information
Mathematics


userchoice()

userchoice( <var>, <"msg"> [,<yesno>] )

Description

This prompts the user with the specified message, to which they have a choice of responses. If the user responds Yes, the given variable is set to 1. If the user instead responds No, the given variable is set to 0.

This prompts the user with the message given, for example:

message(A, "Would you like planet Earth to blow up?")

There is an optional 'yesno' value which specifies which button is highlighted by default:

  • 0 or not specified, this will highlight the 'No' option:
  • 1, this will highlight the 'Yes' option:
This highlighting determines which response will be 'assumed' if the user presses Return.

Specifics

RISC OS does not support escaped characters (i.e. the '\"') and it does not support the optional 'yesno' value, this would be ignored.

Furthermore, the RISC OS buttons are OK (equivalent to 'Yes', and actioned if 'Return' is pressed), and Cancel (equivalent to 'No', and actioned if 'Escape' is pressed).

It is worth keeping this in mind in order to avoid complications such as the following:

Related information
message()


version()

version( <variable> )

Description

This sets the specified 'variable' to the script interpreter version multiplied by 100, hence v1.08 will be 108.

Specifics

The version differences are listed here; at time of writing the current RISC OS script interpreter is 1.07 and the current Windows script interpreter is 1.08.
With Windows/RISC OS technical differences aside, script interpreters carrying the same version number will offer the same command set.


winttx()

winttx( <variable> )

This command is not available in
the RISC OS script interpreter.

Description

This sets the specified 'variable' to 1 if the script is running under WinTTX on Windows (and for RISC OS, the result would be 0).

Specifics

This command is not currently available in the RISC OS interpreter, thus a safer way to detect which script interpreter is being used is to check the current channel, as !Teletext uses presets while WinTTX uses UHF tunings.
Code such as:
set A to status(channel)
if (A ! -1) error("Sorry, this script is not RISC OS compatible.")

or:
set A to status(channel)
if (A = -1) error("Sorry, this script is not WinTTX compatible.")

or:
set A to status(channel)
if (A ! -1) go("riscos")

; code here for WinTTX
go("continue")

.riscos
; code here for !Teletext

.continue
; back to normal...

Related information
set()


xor()

xor( <var>, <num1>, <num2> )

This command is not available in
the RISC OS script interpreter.

Description

This is an alternative to the eor() command, because so many PC things use 'xor' instead of 'eor'.

Refer to eor() for further details.


<var>++

<variable>++

Description

This is a shorthand way to add 1 to a variable.
It is translated internally to be:
add(<var>, 1)


<var>--

<variable>--

Description

This is a shorthand way to subtract 1 from a variable.
It is translated internally to be:
sub(<var>, 1)