TOOLKIT II TUTORIAL
Stephen Bedford

TOOLKIT II is most likely, the widest held product ever
developed for the QL. It can be found on disk interfaces, on
ROM, and a configurable version on disk. It surely is a
"must have" product, as it makes life a whole lot easier. As
with most good things, there is something lacking, in this
case its the documentation. The purpose of this TUTORIAL is
to make additions to the current documentation.

As the section numbers are those used in the TOOLKIT II
manual, numbering may appear inconsistent when a section has
deliberately been left out, this is because it is
sufficiently covered in the manual

INTRODUCTION: Tool kit II (hereafter referred to as TKII) is
a collection of over 120 additions to SuperBasic, these fall
into two categories: those that extend the capabilities of
SuperBasic as a programming language, and those that enhance
SuperBasic's role as the command language of the QL. The
manual supplied with TKII details all of the commands and
functions available, therefore rather than explain every
feature in detail, these notes are written as additions to
the existing documentation.

Tony Tebby divides the facilities of TKII into three
categories: the two alr%adv described above, and the third
being that of development facilities. This latter category
consists of just two commands, which nonetheless transform
the QL. The manual explanation of these commands in section
3 is fairly complete, however brief notes follow.

3.1 ED - SuperBasic Editor

ED is a SuperBasic window-based editor (you can use any
portion of the screen required by setting the size of #2
appropriately or by using another channel, like #3, and
using the command ED #3). Note that such a channel should be
opened as a console device, not a screen device, rather use
OPEN #3, con. This is the case whenever a channel is
required to accept input as well as output to the screen. A
console device is the combination of a screen window and a
keyboard queue.

3.3 Viewing a file

View is used to display a file. It is similar to TYPE as
used in many other operating systems (MS-DOS).

COMMAND LANGUAGE EXTENSIONS: The QL is an exceptional
computer because of its inbuilt software: both the operating
system QDOS, arid its programming language SUPERBASIC. QDOS
even now, has no rival among operating systems found on
affordable micro-computers while many of the advanced
features of SUPERBASIC have yet to be seen in any other
implementation of the language. On a machine like the QL,
BASIC isn't just a programming language, but is actually the
command language of the computer. Without resorting to
machine code, it's possible to run several jobs concurently,
but not possible to alter the priority of these jobs, or to
remove them or to see what jobs are currently on the machine
or to see what state they are in (active, suspended, or
inactive). It's also not possible to see how much free
memory is available on the machine without using PEEK. TKII
rectifies these and manymore deficiencies of SuperBasic.

4. DIRECTORY CONTROL

Directory Control is an area that should be looked at in
greater detail. There are two main difficulties when trying
to understand this. The first is attitude, being that if
something is different from IBM it must be wrong. The second
is the complexities of wildcards, as used in QDOS.

The first can be overcome with time, as you use the features
of QDOS (TKII should be considered an integral part), and
coming to the realization that it's a superior operating
system compared with MS-DOS. The second is best overcome by
use of examples to illustrate the use of wildcards, and by
practice in their use.

4.1 DIRECTORY STRUCTURES

Refer-to the TKII manual, and note examples below.

4.2 SETTING DEFAULTS

QDOS provides the user with the facility to set three
directory defaults, using the commands: DATA_USE, PROG_USE,
and DEST_USE. For an unexpanded machine the defaults when
the machine is booted are: MDV2_, MDV1_,and SER
respectively. On a machine with floppy disk drives the
defaults are: FLP1_, FLP2_ and SER.

The DATA_USE default is used for most filing system commands
such as: LOAD, LRUN, MERGE, LBYTES, SAVE etc. Thus you could
set the default for data as follows: DATA_USE FLP1_BASIC.
Suppose the disk in FLP1_ had the following files on it:

     basic_mandelbrot_bas
     basic_prime_bas
     basic_game_pas
     pascal_trig_pas
     pascal_trig_rel
     pascal_trig_bin
     pascal_game_bas
     pascal_game_rel
     pascal_game_bin
     letter_qjump_txt
     address_qjump_txt

After setting the data default as above, a directory listing
using DIR would look like this:

     basic_mandelbrot_bas
     basic_trig_as
     basic_game_bas

While DIR FLP1_ would show the full contents of the disk, if
you wished to know about all PASCAL associated files, you
would set the default to FLP1_PASCAL_. If you wished to set
only the games related files, you could set the default as
follows: DATA_USE FLP1_GAME_. A DIR then would show the
following:

     basic_game_bas
     pascal_game_bas
     pascal_game_rel
     pascal_game_bin

The data default has been set with WILD CARDS. The string
making up the default may be broken up into four parts:

  - "FLP1_" is the device name.

  - "_" is a wild card that represents any characters up to
the point where the next part of the default matches.

  - "GAME" is the portion that follows an underscore (since
this is where the proceeding wildcard ends). This might be
considered to be the file name.

  - "_" this is a second wild card, and could be considered
to mean, that any extension (conventionally indicating file
type) is valid.

Thus the default is set to FLP1_ followed by any characters
up until a match with the next part of the default (in this
example 'game') by 'game' followed by any characters. That
is any files of any type, called game on any directory on
the disk. The idea of directory, subdirectories, file name
and extension, are used as an analogy with other operating
systems which many people are familiar. Perhaps it's better
to think of these as discrete parts of a file name.
Remember, the first part of a full filename is always the
device name, and it's a good practice to have the last part
(extension) indicate the type (bas for BASIC files pas for
PASCAL etc.).

An underscore therefore represents both a deliminator
between the parts of a default and wildcards. The general
rule being that a single underscore within a default only
acts as a deliminator, two underscores within a default
represent one deliminator and one wild card. A single
underscore at the end of a default may be considered as both
a deliminator and a wild card Thus, in the example, a
default of FLP1_GAMES_ would give the same directory
listing, Whereas FLP1_GAMES would show no files at all. We
haven't supplied a wild card, and there are no file names
that start FLP1_GAMES. Note that an underscore is
automatically appended to a default if it doesn't already
end in one.

If we were to set the default back to FLP1_BASIC_ , we could
load the mandelbrot program simply by typing:

     LOAD MANDELBROT_BAS

It appears that for commands other than DIR, wiidcards
within defaults don't work. That's to say the name appended
to a command such as LOAD is tagged onto the end of a
default rather than replacing a wild card. This avoids
possible ambiguities. Also commands other than DIR need some
part of the file name appended to them. One cannot set the
default to FLP1_BASIC_GAMES_BAS and type LOAD. This will
result in a 'bad parameter error'.

PROG_USE is used to set the directory for executable code
and as such is only used for: EXEC, EXEC_W and the TKII
commands EX ,EW, and ET. Thus continuing the example
used above, you could set the program default as follows:

     PROG_USE FLP1_PASCAL

and then execute one of the programs as follows: EX
TRIG_BIN. Notice that the TKII command EX may be used
exactly as the standard EXEC but as shall be seen later, can
also be used in different ways.

DEST_USE sets the default destination for commands such as
COPY and RENAME (TKII). This is by default, set to SER1 so
that using COPY with only one parameter will result in a
file being printed, if a printer is connected via SER1.

4.3 DIRECTORY NAVIGATION

The commands DDOWN, DUP, and DNEXT provide another method of
changing the data default (and the program default if it's
the same as the data default). These commands allow the
default to be altered relative to the current value as
opposed to setting the default in an absolute manner as with
DATA USE (look at commands LINE and LINE_R page 32 of
Keywords in the QL User Guide for an analogy). Under an
operating system such as MS-DOS with its single default
directory, a single command is used far changing the
directory both relatively and absolutely.

The command DDOWN allows one to move further down the
directory tree. That is, extend the data default. An
underscore is automatically attached to the argument
appended to DDOWN. Assume the machine has just been booted
so that the data default is FLP1_, following the same
example used above, if you wished to look at only PASCAL
files you could set the data default using the command:
DDOWN PASCAL. This is then equivalent to the statement:
DATA_USE FLP1_PASCAL. Now if you wanted to see only PASCAL
source files, you could type the command: DDOWN_PAS. The
underscore is used as a wild card. You wish to see all files
with the _PAS extension in the directory PASCAL.
The data default is now: FLP1_PASCAL_PAS_.

The command DUP doesn't take any arguments, it moves the
data default up one directory level. In this case DUP would
set the default back to FLP1_PASCAL.

DNEXT allows you to move to a different default at the same
level, if the current default is FLP1_PASCAL,PAS and you
used the command: DNEXT REL, the default would become:
FLP1_PASCAL_REL_. You could then list the REL files (output
from compiler). If you wished to set the default for the BIN
files (output from the linker) you couldn't type DNEXT bin.
This is because BIN is an extension provided by TKII for
using binary numbers, therefore you would have to type:
DNEXT 'BIN'. This prevents SuperBasic from evaluating the
argument, and is true of SuperBasic commands in general, not
just those explained here.

4.4 TAKING BEARINGS

One command and three functions are provided to allow you to
find out the current
defaults: DLIST, DATAD$, PROGD$, and DESTD$.

DLIST lists the current defaults in the order data, prog and
dest. As usual a channel number may be appended if onedoesn't wish the output to go to window #1. As with other
commands added or modified by TKII, an implicit channel may
also be used: DLIST #2, DLIST \FLP1_defaults.

The three functions each return the value of the appropriate
directory. For example: PRINT DATA$, might result in
FLP1_PASCAL_BIN being printed to the screen.

5. FILE MAINTENANCE

TKII improves file maintenance procedures in two ways.
First, the existing commands COPY, DELETE, and DIR now use
the default directories and secondly,the addition of wild
card and overwrite operations significantly ease file
handling.

5.1 WILD CARD NAMES

The manual says that wild card characters are not used,
rather any missing section of a name is treated as a wild
card. However, in part one of this tutorial i stated that an
underscore is a wild card character. In fact,these two views
are essentially the same, but considering the underscore to
be a wild card is easier to understand. The use of wild
cards in this section is the same as used for default
directories explained in the first part (section 4.2).
However for the notes to be correct a stricter definition of
what the underscore can represent must be defmed:

AN UNDERSCORE CAN REPRESENT A NULL STRING OR ANY SERIES OF
CHARACTERS THAT DO NOT START WITH A DELIMINATING UNDERSCORE
AND END WITH EITHER AN UNDERSCORE OR THE END OF THE NAME.

This is consistent in many cases with saying that the
missing section is treated as a wild card. The following
example explains the definition. Suppose you have a disk in
FLP1_ with the following files:

     BASIC_MANDELBROT_BAS
     BASIC_GAMES_BAS
     BASIC_JOBS_BAS
     BASIC_PROGRAM_BAS

If the data default is set to FLP1_ (DATA_USE FLP1_) then
DIR BASIC_BAS would show: BASIC_PROGRAM_BAS. The underscore
is representing PROGRAM_. The other files do not match since
the underscore following BASIC is a deliminator, and the
wild card cannot represent a string that starts with an
underscore. However, DIR BASIC_BAS would show all the files.
The first three file names the first underscore in the wild
card name is the deliminator, while the second represents:
MANDELBROT, GAMES, and JOBS_ respectively. For the last file
name, the first underscore is set to a null string, and the
second matches PROGRAM_ as before.

Thus, a wild card name of FLP1_BASIC_BAS could match a file
name of: FLP1_BASIC_MANDELBROT_BAS , and it may be
considered that either MANDELBROT is the missing section of
the filename, or that the second underscore in the
wild card name matches MANDELBROT in the file name.

If a disk contains a file with the name letter on it, then
the command DIR 1_ will result in the file letter being
listed. Yet an underscore does not appear in the filename,
suggesting that the underscore is a wild card matching a
series of characters ending with the end of the file name.
In section 4.2 of the manual it explains that if a default
directory is set that doesn't end with an underscore, then
an underscore is automatically appended. This may be
considered the case for wild card name too. Thus in this
example DIR 1, would also result in the file name letter
being displayed.

It doesn't really matter how wild cards are defined, the
important thing is to realize that they are very useful.
Practice in the use of wild card names will hopefully bring
understanding.

5.2 DIRECTORY LISTING

As well as the standard DIR command TKII also makes
available WDIR, and WSTAT. All use the default data
directory and may be passed wild card names. The output of
the commands may be redirected using implicit channels as
shown in part 1. If you have a disk in drive one with a name
TKII NOTES and the following files:

     TKIIa_DOC
     TKIIb_DOC
     TKIIjob_DOC

Then a DIR FLP1_ would give you the following display:

     TKII NOTES
     1347/1440 sectors
     TKIIa_DOC
     TKIIb_DOC
     TKIIjob_DOC

WDIR FLPI_ would give you:

     TKIIa_DOC
     TKIIb_DOC
     TKIIjob_DOC

WSTAT FLPI_ would give you:

     TKIIa_DOC
          16590 1990 Jul 06 20:25:30
     TKIIb_DOC
          17065 1990 Jul 10 15:53:29
     TKIIjob_DOC
          8412 1990 Jun 23 17:16:57

Notice the amount of space on the disk is shown in sectors
(blocks of 512 bytes). The file sizes are shown in bytes,
however the space for a file is allocated in groups of
three sectors, thus TKIIa_DOC would use 33 sectors,
TKIIb_DOC would use 36, and TKIIjob_DOC would use 18
secto;rs. That is 87 sectors in all, the other 6 sectors
that have been used are for the directory and map (a
directory of a blank disk will show 1434/1440 sectors).
WSTAT is very slow on microdrive.

5.3 DRIVE STATISTICS

The command STAT, shows Just the name and space available on
a disk. In the above example the display would be:

     TKII NOTES
     1347/1440 sectors

To get full information on a disks contents type:

     STAT FLP1_ : WSTAT FLP1_

Note in the contents section of the TKII manual a command
ASTAT is mentioned. This command, which should produce an
alphabetic list of files, is not described elsewhere in the
manual, and is in fact, not implemented in the versions of
TKII that I own (versions 2.12 and 2.13)

5.4 FILE DELETION

THE DELETE command has been modified to use the data default
directory. Thus, for a machine with floppy disks attached,
just after booting, the command: DELETE BOOT would delete
your boot file contained on FLP1_. For a microdrive only
system the same command would try to delete a file named
boot on MDV2_.

A new command has been introduced, WDEL, this command will
accept wild card names as a parameter. Suppose you are using
the same disk as above containing the files:

     TKIIa_DOC
     TKIIb_DOC
     TKIIjob_DOC

Typing the command DELETE TKII would result in the disk
spinning and no error message would be produced, yet nothing
would be done: the file TKII doesn't exist. Whereas the
command, WDEL TKII would produce the following response:
"FLP1_TKIIa_DOC..Y/N/A/Q" meaning, is this file to be
deleted (YES or NO), are ALL files that fit this wild card
to be deleted, or is the operation to be QUIT. So, to delete
all except the first of the files that fits the wild card,
first respond with N then A. It's suggested that the option
of deleting all matching files is not used until familiar
with this command and wild cards. On a machine running
MS-DOS a prompt similar to the one described above, is not
given, DEL TKII would go ahead and delete all files that
match.

5.5 FILE COPYING

The standard COPY command has been modified to use the DATA
and DEST default directories. Thus, the command; COPY BOOT,
will copy FLP1BOOT to SER1. That is, assuming the defaults
have not been altered. So, if a printer is attached, the
file will be printed

A further alteration to the COPY command is that if the
destination file already exists, permission to overwrite is
asked for. Thus typing: COPY TKIIa_DOC to TKIIb_DOC, the
following prompt would result: "FLP1_TKIIb_DOC exists, OK to
overwrite..Y or N" This is very much like the QUILL SAVE
operation.

The COPY command has become more "intelligent". The file
header is automatically either copied (making a copy of an
executable file) or not (printing a file) depending on the
file and devices concerned. I haven't used COPY_N or COPY_H
since having TKII.

5.5.1  SINGLE FILE COPIES

This includes the standard COPY command as described above,
COPY_N and COPY_H which have also been modified to use
default directories, and COPY_O. In my copy of the TKII
manual, a misprint has lead to COPY_O appearing as COPY_.

The COPY_O command will copy a file without asking what to
do if the destination file already exists. This is useful
when copying is performed within a SuperBasic program and
one does not wish to give the user the choice of whether to
overwrite a file or not.

5.5.2. WILD CARD COPIES

The command WCOPY allows you to copy a number of files as a
single operation. As with the commands for single file
copying, WCOPY uses the default directories. The form of the
command is:

     WCOPY #channel, source TO destination

As with standard QDOS commands the channel is optional but
if supplied it is where the prompts will be sent. If a
channel is not specified, then prompts will be sent to
#0.

The following examples illustrate the use of the command.
Assume the data default directory is set to FLP1 _ and the
destination default directory is set to FLP2_ and that the
disk in drive one contains the following files:

     TKIIa_DOC
     TKIIb_DOC
     TKIIjobs_DOC
     LETTER_RICHARDALEXANDER_TXT
     ADDRESS_ALEXANDER_TXT

for all of the examples.

i) WCOPY

This is the equivalent to WCOPY #O, FLP1_ TO FLP2_ That is,
copy all files from FLP1_ to FLP2_. However, as with the
WDEL command a prompt is given:

     FLP1_TKIIa_DOC TO FLP2_TKIIa_DOC.. Y/N/A/Q

Responding with A would lead to all files being copied from
the first to second disk drive individual flies may be
selected for coping by responding - YES or NO as each
filename is presented. The operation maybe QUIT at any time.

ii) WCOPY #1, TKII_ TO NOTES_

This is the equivalent to WCOPY #1, FLP1_TKII_ TO
FLP2_NOTES_ Thus a selective copy of only files that are
notes on TKII is performed, arid would therefore produce the
prompt:

     FLPI_TKIIa_DOC TO FLP2_NOTESa_DOC..Y/N/A/Q?
The part of the name represented by the wild card is
appended to the destination wild card name. For the files
that match this specification on the disk in FLP1_ the wild
card will have in turn the values a_DOC b_DOC, and Jobs_DOC.
The prompt will appear in #1 unless the windows have been
changed, at the top of the screen.

iii) WCOPY TO FLP1_BACKUP_

This is the equivalent to WCOPY #O, FLP1_ TO FLP1_BACKUP_
and allows copies of all files to be made on the same disk
but with a prefix added to the file name ie copy files to a
subdirectory.

iv) WCOPY TO SER1

This is equivalent to WCOPY #O, FLP1_ TO SER1, and will
result in an error: BAD NAME, because SER1_TKIIa_DOC is not
a valid name. If at any time the resulting destination file
exists already, a prompt asking if the file should be
overwritten is produced.

5.5.3 BACKGROUND COPYING

The command SPL is provided to allow background copying in
the same manner as COPY_O. The copying is performed by a
spooler which is an independent Job. The primary use for the
spooler is to print files. SPL uses the data and destination
defaults and so if the QL has Just been booted then you can
print a file as follows:

     SPL TKIIa_DOC

The command doesn't accept wild card names. So that a file,
FLP1_PRINT_CMD (the extension_cmd shows that the file
contains a series of commands rather than a numbered
SuperBasic program - the use of sensible and consistent
extensions can greatly assist with file management. The
extension _bat may be chosen as with MS-DOS) could be
created containing the following lines;

     SPL TKIIa_DOC
     SPL TKIIb_DOC
     SPL TKIIjobs_DOC

The command LRUN PRINTCMD would then allow the three files
to be printed withoit intervention while the machine can be
used for other things. Three separate Jobs would be created
all named SPL and all running at priority O. At the default
priority the background printing will have little effect on
ones main Job whether it be editing or playing a game.
However, if the destination is a file rather than the serial
port, this will not be the case. When spooling to a file,
keyboard response will fluctuate considerably no matter at
what priority the spooler is running. Spooling to a file
will obviously be much quicker than spooling to a printer,
but offers no real benefits over copying to a file.

The output for the spooler is selected using the command
SPLUSE. This is in fact, the same as DEST_USE except that an
underscore is not appended to the name - an underscore at
the end would indicate a wild card name and SPL doesn't
accept wild cards.

SPL_USE FLP1_DUMP would set the destination default to
FLP1_DUMP and all subsequent uses of SPL would write to that
file automatically overwriting the previous version. A
variant of SPL, SPLF will spool a file and place a form feed
at the end. This will ensure that individual files are
printed on separate sheets of paper. Both of these commands
may be supplied with channel numbers rather than filenames
as explained in the TKII manual.

At this point it is worth mentioning one of the many
wonderful features of TKII that I don't think appears
explicitly in the manual. Although not directly connected
with spooler it is to do with printing. If, on a QL without
TKn fitted, there are two (or more) Jobs running, both of
which are trying to access the printer, the result will be a
printout which is a mess the output of the two Jobs
interleaved. With TKII fitted, your Job's output will be
sent to the printer while the other's is buffered in memory.
Once the printer is free, the buffered output is copied from
memory to the printer.

5.5.4 RENAMING FILES

As explained in the TKII manual the remaining commands
follow the same form as the equivalent copying commands, but
merely alter the filename ie RENAME has similar syntax to
COPY and WREN has similar syntax to WCOPY.

6.   SUPERBASIC PROGRAMS

6.1  DO

DO is a command for an executed SuperBasic command file,
which is a file containing unnumbered BASIC statements.
Thus, using the example from 5.5.3, the command: DO
PRINT_CMD, would perform the three spooler commands
contained within the file. The advantage of the DO command
being that the current SuperBasic program is unaffected. It
would be lost if you used LRUN. Any block commands within a
command file must appear on a single line, for example:

     FOR n = 1 TO 10: PRINT n
     REPeat read: INPUT a$: PRINT a$, CODE (a$)

would be an acceptable file, whereas the following would
not:

     FOR n = 1 TO 10
       PRINT n
     END FOR n
     REPEAT read
       INPUT a$
       PRINT a$, CODE (a$)
     END REPeat read

An attempt to LRUN such a file would lead to the error "not
found". This refers to loop control 'a' which only exists in
the line of the definition. It is of course, acceptable to
use either upper or lower case for keywords, and use normal
abbreviations. Note the warnings at the end of 6.1 in the
TKII manual.

6.2 DEFAULT DIRECTORIES

The normal BASIC filing commands have been modified to use
the default directories. In addition the LOAD command will
look for a file in the PROGRAM default, if it doesn't locate
it in the DATA default directory. An overwrite variant of
the SAVE command, SAVE_O has been introduced that works in
the same manner as other overwrite commands.

7.  LOAD AND SAVE

This section refers to the loading and saving of binary
files, i.e. LBYTES and SBYTES for resident procedures and
EXEC, EXECW, and SEXEC for transient programs. SBYTES and
SEXEC have been modified in the same way as other commands
that write to files prompt appears if file already exists),
and the overwrite variants have been introduced.

A new command, LRESPR, has been added that combines the
functions of RESPR, LBYTES, and CALL. Thus: base = RESPR
(file_length): LBYTES file, base: CALL base, can simply be
performed by typing: LRESPR file. With the latter it's not
necessary to explicitly find out the length of the file. As
with RESPR, LRESPR may only be used if no other jobs, other
than BASIC are running on the QL.

8.  PROGRAM EXECUTION

This section deals with the commands for executing compiled
programs which run on the QL as jobs. This formerly
consisted of two commands EXEC and EXEC,W. These have been
modified and made synonymous with new versions: EX and EW.
Another command, ET has been introduced which loads a
program into memory but returns control to BASIC before
starting the job. The EX command is explained further to
illustrate the new facilities provided by all of these
commands.

8.1  SINGLE PROGRAM EXECUTION

EX may be used in the same way as the standard EXEC command
in order to start a job on the computer: EX filename. The
command will look for the file on the program default
directory. In addition, the program may be passed a
parameter string. As an example of use I'll refer to a
commercial program 'MASTER SPY EDITOR'. This program
can be invoked as follows: EX MS, FLP1_BOOT. This command
executes MASTER SPY (which I've renamed to MS on my working
copy) which loads the file FLP1_boot and presents it ready
for editing. This feature was made available on MASTER SPY
(version 1.7 and onwards) as a result of my writing to ARK
to ask if it were available.

A further feature of the EX command is that filename (or
channels) may be passed to a program for use as it's
standard input and output. BASIC programs compiled using
SUPERCHARGE cannot be passed input and output files, perhaps
TURBOCHARGED programs can, I don't know. But it is easy to
write a PASCAL program to accept filenames for input and
output channels, and is a standard feature of PASCAL. Below
is an example PASCAL program which should be quite easy to
follow for anyone familiar with SuperBasic. Comnients are
enclosed between curly brackets.

     PROGRAM mu12 (input, output);
     VAR
       param : string [20];   { like DIM param$(20) }
       in_num, out_num : real;
     BEGIN
       REPEAT
         getcomm (param);  { read the parameter string }
         writeln @aram)
         readln (in_num)   { equivalent to INPUT a }
         out num:= in num * 2
         writeln (2 * in_num);  { equivalent to PRINT 2*a }
       UNTIL in_num = 0;
     END

This program simply reads in numbers and writes out double
the number. If the program was invoked using EX MUL2_BIN
(the file mul2pas is passed to the compiler which produces
mul2rel [the extension .obj would be used on MS-DOS systems]
and then the linker processes this file and produces mul2bin
[.exe under MS-DOS]) then the numbers could be typed in at
the keyboard, and the answers would be printed to the
screen. Because no parameter has been passed only the
numbers would be displayed on screen, however the same
program could be invoked as follows:

     EX MUL2_BIN, IN_DAT< OUT_DAT;'IN_DAT * 2'

MUL2 would have to be located in the program default and
IN_FILE in the data default directory. If IN_FILE contained
the following lines:

     2.7
     -3.34
     10.6
     O

Then the file OUT_DATA would be produced in the data default
directory containing the following lines:

     IN_DAT * 2
     5 .4000000E+00
     -6.6800000E+00
     2.1200000E+01
     0.0000000E+00

The file OUT_DAT would be overwritten automatically if it
already exists. Note the numbers may be easily formatted so
as not to use scientific notation, this is merely the
default. The same results could be achieved by passing
channel numbers instead of file names:

     OPEN_IN #3, IN_DAT
     OPEN_NEW #4, OUT_DAT
     EX MUL2, #3, #4;'IN_DAT * 2'
     CLOSE #3: CLOSE #4

The Propero PASCAL compiler and the GST LINKER also accept
parameter strings. The compiler uses the parameter string to
pass the name of the PASCAL program and flags indicating
various options for the compilation. Likewise with the
linker one passes the program name and the name of the file
containing the linker directives. The parameter need not be
a string constant, it could be a variable:

     FILES = FLP1_BOOT : EX MS;FILE$
8.2 FILTERS

EX also allows a series of programs to be executed that work
together to process a stream of data, the output from one
program being passed to the input of the next. The situation
is analogous to a production line. In the TKII manual it
explains that a series of programs (or filters) could be
executed as follows:

     EX UC, FRED, TO LNO TO PAGE, SER;'FILE FRED' & DATES

Such a series of programs could be easily written in PASCAL
but the string handling is sufficiently different from
SuperBasic so as to make the example of little use. Instead,
consider a simpler set of programs:

     EX ADD3_BIN, IN_DAT TO MUL2_BIN, OUT_DAT;'NUMBERS'

MUL2 is the same program as listed above. The output from
ADD3 goes to the input of MUL2 and the output goes to the
file OUT DAT. The file OUT DAT will have the heading
'NUMBERS'. The program ADD3 is as simple as MUL2:

     PROGRAM ADD3 (input, output);
     VAR
       in_num, out_num : real;
     BEGIN
       REPEAT
         readln (in_num);
         out_num := in_num + 3;
         writen (out_num);
       UNTIL in_num = -3;
     END

This program reads a series of numbers and writes the values
plus three. It stops when it reads the number -3, this will
have three added and be passed to MUL2 which stops when it
reads the number O. So they stop properly together. If any
program in the chain failed, then the whole series of jobs
involved would be removed.

Suppose that IN_DAT now contains the following lines:

     2.3
     -3.6
     10
     -3

The ADD3 (the job name is derived from the name on the
PROGRAM statement in the PASCAL program) will read this file
and pass the following numbers to MUL2:

     5.3000000E+01
     -6.0000000E+01
     1.3000000E+01
     0.0000000E+00

MUL2 will read the numbers, and produce the file OUT_DAT:

     NUMBERS
     1.0600000E+01
     -1.2000000E+00
     2.6000000E+01
     0.0000000E+00

The means of communications between these two programs is
via a pipe. If the IN_DAT is a much bigger file say, a
thousand lines, then while these programs are executing
inspection of the channels menu in QRAM shows that there is
a pipe associated with both of the programs.

Each of the programs in the chain may have many other
channels open and use the screen and keyboard as well as
other files and devices. However, if using software like
QRAM, it is important to remember that if the programs in
the chain are competing for the screen, then one will be
suspended, this will cause the chain of programs to fail
(the first program in the chain may be suspended, and this
will suspend the chain of jobs once the pipes have been
emptied). With the PASCAL programs as described, the
programs will fail even though output is not sent to the
screen. This situation may be remedied by using the UNLOCK
utility supplied with QRAM.

I would think that it would be possible to write similar
programs in FORTRAN, in which case unit 6 of one program
would be attached via a pipe to unit 5 of the next. 'C' also
has standard input and output, which I'm sure would accept
pipes (on a full implementation of the language).

9. JOB CONTROL

The QL was the first affordable computer to allow
multitasking. It's one of the many features that still sets
it apart from the herd, and yet, is one of the most
difficult to control satisfactorily on a standard machine.
It is also one of the areas that most interests 'Tinkerers'
like myself.

The extensions for job control are documented in section 9
of the Toolkit II manual. There are four commands (JOBS,
RJOB, SPJOB, and AJOB) and four functions (PJOB, OJOB, JOB$,
and NXJOB) provided.

9.1 JOB CONTROL COMMANDS

JOBS lists the currentjobs. By default the output will go to
#0, but as with standard SuperBasic procedures, the output
may be sent to any other channel by simply appending # and
the channel number. Thus JOBS #2 will display a list of jobs
in #2.

Toolkit II also allows implicit channels. That is, if you
wish to send the output to a device, you need not open a
channel to that device, send the the output to the channel
(as stated above) then close the channel, but you may append
the command with \ and the device name. The following will
create a file JOB_TXT on flpl_ that contains the list of
jobs on the system:

     JOBS \flp1_job_txt

You can just as easily print out the list of jobs with one
command:

     JOBS \ser1

With SuperBasic as the only job in the machine, the JOB
command would display a table as follows:

     Job  tag   owner priority
      0    0      0     32

SuperBasic does not have a job name. Names are normally
displayed after the job priority. If a job is suspended (see
SPJOB below) then an 's' would be shown immediately to the
left of the job priority.

RJOB allows you to remove a job (other than SuperBasic) from
the machine. RJOB is followed either by the job name or by
the job id. The job id is a combination of two parameters,
the job number and the job tag. These values are displayed
by using the JOB command. If you execute a program,
mandelbrot, using the command ex flpl_mandelbrot, the JOB
command would produce a list as follows:

     Job   tag   owner priority
      0    0     0      32
      0    0     0      8       mandelbrot

Note that a job activated by SuperBasic will start with a
priority of 8. Some jobs will not have names. The job
mandelbrot may be removed as follows by the command RJOB
mandelbrot.

There is a further parameter that may be added to the
command. This is an error code which through the use of
machine code could be read by the parent job (that job that
started the job being removed). Thus you could type RJOB
mandelbrot,-l. This isn't relevant to the user of SuperBasic
except that it appears when you follow RJOB with the job id
instead of the job name, the error code must also be used.
Thus you would type RJOB 1,0,-1. The reason for using the
job id as a parameter is that some jobs do not have names.
Another reason is that it is possible to have many jobs with
the same name. If the job name is used, then QDOS will
remove the first of that name.

SPJOB allows you to set a jobs priority. As stated earlier,
a job started by SuperBasic is given a priority of 8. If the
job is required to run faster or slower then you must raise
or lower its priority. Like RJOB the first parameter is
either the job name or job id. If a job id of -1 is used
then the current jobs priority is altered. (If you type
SPJOB as a direct command it would be SuperBasic, however,
if SPJOB is used in a SuperBasic program that is then
compiled an argument of -1 would refer to the compiled
program). The second parameter is the priority. This is an
integer between O and 127. A priority of O means the job
will become inactive (it will not get a share of cpu time).

Thus, if you wished to alter the priority of the job
mandelbrot (as used in the example above) you could type
either of the following:

     SPJOB mandelbrot,l6
     SPJOB 1, 0, 16

We would then expect the job to run approximately twice as
fast. Note the speed of execution of a job not only depends
upon its priority, but also upon the availability of
resources it wishes to use. For example, only one job may
use the keyboard at a given time, so if a job requires input
and the keyboard is already in use, then it will be
suspended by QDOS until the keyboard is available (either
because the first job has finished or control-C is used).

AJOB is used to activate a program which has been loaded
into memory but not previously started. (If a job has
previously had its priority set to 0 it could be reactivated
either by setting its priority to a positive value or by
using AJOB. A job executed with the command ET would be in
an inactive state until activated by further commands such
as AJOB).

9.2 JOB STATUS FUNCTIONS

PJOB returns the priority of a job, as with the commands
above, the job may be specified either by its name or by its
id. Since it is a function the job name or id must be
enclosed in brackets. Thus you might type PRINT PJOB
(mandelbrot). From within a program you might wish to double
a jobs priority:

     150 PRINT 'Do you wish to speed up mandelbrot?'
     160 answer$ = INKEY$ (-1)
     170 IF answer = 'Y' THEN
     180 priority = PJOB (-1)
     190 priority = 2 * priority
     200 SPJOB -1,priority
     210 END IF

If mandelbrot is a SuperBasic program the inclusion of a
section similar to the above would allow you to speed up the
job. Of course, this only has an effect if other jobs are
running, if only one job is active on the computer it will
take the same amount of time to run, if its priority is 1 or
127.

OJOB returns the id of a jobs owner (ie. the job from which
it is activated). In our example, PRINT OJOB (mandelbrot)
would print 0, the id of SuperBasic.

JOB$ returns the name of a job given its id. Thus, PRINT
JOB$ (1, 0) would print 'mandelbrot'. This is useful in any
programs that refer to other jobs: you may wish to job ids
in calculations but when it comes to displaying information
it is better to convert to the job name.

NXJOB returns the id of the next job in the job tree. In our
example NXTOB (0) would have a value of 1 ie. the next job
after SuperBasic is mandelbrot. As more jobs are activated
on the machine the job tree becomes more complex. Jobs may
be activated by SuperBasic or by another job.

Super Toolkit II thus provides a set of commands and
functions for controlling jobs and finding out information
about jobs. It would be nice to have more functions for
example, a function that returned the location of a job in
memory, its length, the location and length of data it is
using etc., etc. Much of this information can be found using
machine code.

    Source: geocities.com/svenqhj