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 onedoesn'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.