SuperBasic Source Book
( Version 1.0 Jan 1999 )
By Timothy Swenson
TABLE OF CONTENTS
Introduction
Credits
Related Documents
QLiberator
Known Bugs
Fixed QLIB Runtimes
Creating Background Hidden Jobs
Reading the Keyboard Buffer
Stuffing the Keyboard Buffer
Using STDOUT (Passing Channels to a Child Job)
Linking in Toolkits
Creating Toolkits (Loadable Extensions)
Overlays
Configuring A Program
Types of Configuration
User Intervention
Config Blocks
Configuration File
Command Line Arguments
Environment Variables
Config Blocks
Definition of Config Blocks
Config Levels
BASCONFIG - Adding Config Blocks to Qlib Programs
Programming with BASCONFIG
Using BASCONFIG to Create Config Blocks
Updated Versions of BASCONFIG
Environment Variables
Freeware Programming Extensions
Adrian Ives Extensions
Display Code
Database Handler
QSEND
DIY Toolkit
Client Server Manager
GetStuffed
Tools to Assist in Programming
Structured SuperBasic
ProcMan
Editors
QED
MicroEmacs
Elvis
(Copyright 1999 by Timothy Swenson. This document may be
freely distributed.)
INTRODUCTION
This Source Book comes from wanting to know how to do different
things while programming in SuperBasic. This Source Book does not
come from expertise (more of a lack of expertise) but from being
willing to sit down and document what others and I have learned.
I have not really done a lot of SuperBasic programing, compared to
many. A fairly big lazy streek, a house, and family make for a
good excuse for not having produced a professional product. (Plus
I have contributed to the QL community via the QL Hacker's Journal
and articles to QL publications) So, I consider myself a relative
beginner at programming really well on the QL, but I do have a
drive to want to know how to programm really well, and a drive to
write down what I have learned. Some of this material may be old
hat to some and competely new to others.
This document was originally going to be called the Qliberator
Source Book, but since most of the information is not directly
related to Qliberator, I decided to change the name.
This document is not meant to be the end-all in covering
SuperBasic and programming SuperBasic. There are many books on
SuperBasic and on general programming. The focus of this document
is on those topics that apply directly to SuperBasic, the QL,
Qliberator, programming tools and toolkits, and creating compiled,
professional programs. For information on programming SuperBasic
in general, there are many other sources. Most QL publications
have had some form of SuperBasic tutorial and other programming
articles. These publications would include QL World, Quanta,
International QL Report (IQLR), QL Today, and many club
newsletters. Another source of programming articles is the QL
Hacker's Journal, a newsletter solely covering QL programming.
All back issues of the QHJ are available electronically. See the
section on RELATED DOCUMENTS for details on where to get these
back issues and other information.
In covering any tools for creating or assisting in the creating of
SuperBasic program, there was a decision to cover only Freeware
tools. As a fan of Freeware and as this document is Freeware, I
wanted to only intially cover the Freeware tools. This was
partially done to limit the initial scope of the document and
because Freeware is easily had and used by programmers.
This document is to be considered a living document. As I have
more time or more material become available, I will be adding to
this document. Some sections may seem a bit thin on helpfull
advice on using the different toolkits. This is mostly due to my
having not used the specific toolkits. As I experiment more with
them or as others pass along helpfull advice, I'll add to those
sections.
CREDITS
The biggest credit for this document goes to Dilwyn Jones, who has
taken the time (many times) to answer many a question. Dilwyn's
anwers were always comprehensive. The section on using the
DISPLAY toolkit comes directly from Dilwyn and is 100% his
writing.
RELATED DOCUMENTS
One of my original ideas for this document was to troll around for
other like documents and include them (limit the amount of stuff I
have to write). Two key documents that I felt really should be
included are either two long or stand well on their own.
Norman Dunbar has written a series of articles, a tutorial, for
QUANTA on programming with EasyPTR II. These articles and
accompanying example programs have been put into one single zip
file and is publicly avaialable via the Internet or through most
QL Freeware sources. If you thinking of using EasyPTR, you really
need to get a hold of this document.
Dilwyn Jones has written a short tutorial on using QMENU for QL
Today. It, too, has been made publicly available through the
Internet or QL Freeware sources. It comes with example programs
also. This tutorial is very helpfull in figuring out how to use
QMENU.
Norman Dunbar has also written an Introductory Guide (Idiot's
Guide) to the Pointer Enviroment (PE). It was created to be
distributed with all PE programs to guide users in learning all
about the PE, its terms, and how to use it. This is another
must-have document.
All of these documents, along with many others, are collected in
my QL Documentation Project. The Project is an attempt to collect
as many pubicly available QL documents and make them available
from one location. The focus in on documents that cover the
operating system, key extensions, and tutorials. This does not
include software/hardware reviews or time sensitive (news)
information. The documents from the Project can be found at my
web site: www.geocities.com/SiliconValley/Pines/5865/.
QLIBERATOR
Qliberator is written by Ian Stewart and the current version is
3.36. At this time there are only 3 known bugs with the 3.36
runtimes. They are:
1. ERNUM/ERLIN Bug.
ERNUM reports the line of the error (ERLIN) instead of the
error number (ERNUM).
2. Passing Channels.
The Channel Passing example in the book (Page 10.4) does not
seem to work with the Pointer Environment loaded. Cycling through
the available jobs (CTRL-C) and back to the example program makes
the example work.
3. Overlay
Make sure all GLOBAL variables are correctly declared in the
main file and the overlay(s). If one is missed, a system crash is
the likely result.
Fixed Qlib Runtimes
A number of individuals have taken the 3.36 runtimes and applied
thier own fixes. I know of 4 different fixed Qlib runtimes.
There are done by:
- Phil Borman
- Thierry Godefroy
- Hans-Peter Recktenwald
- Arvid Borestzen & Pal Monstad
Phil Borman's Fixes
1. Fix the well known ERNUM/ERLIN bug.
2. Add extra debugging messages on Qlib errors ( eg. "String
is not numeric" shows you the sting it was trying to coerce.
3. Add a file for fatal errors instead of the red error
window. Built into the runtimes in a Config block, a fatal error
causes the job to print it's error information to a file and then
force remove itself. This allowed fatal errors from stopping
Phil's BBS. It comes with the PBOX Distribution.
Thierry Godefroy's Fixes
Thierry's version of the runtimes fixed only the ERNUM/ERLIN bug.
It's file name is Qlrun336mod_lzh.
Hans-Peter Recktenwald's Fixes
Hans-Peter has not only fixed a few bugs but has added some
additional functionality to the runtime. Due to my rusty High
School German, I am not able to translate the document that comes
with the runtimes. Below is a list of the keywords that have been
modified or added:
Q_CMPLD - New
Q_ERR
Q_JOB - New
Q_RLIN - New
Q_CURSOFF
Q_CURSON
Q_ERR_ON Name1$[,Name2$[,...]]
Q_ERR_ON Name1$,type1[,Name2$,type2[,...]]
Q_ERR_LIST
Q_ERR_OFF [Name1$ [,Name2$]...]
Q_PIPE
QR
Q_RSET[ernum%]
At the moment I do not have any information about the 4th modified
Qlib runtime.
This version is only available from Hans-Peter (phpr@snafu.de)
Creating Background Hidden Jobs
I have experimented with creating background type jobs. These are
jobs that do not display any information on the screen, but run in
the background and do things. The Hotkey System is a form of
background job. Some jobs have background modes, like Screen
Snatcher, and "pop" up after a specific key stroke. The TKII
command ALARM is a good example of a fully background job.
I wrote a short program to experiment with. I notice that after I
EXECed it, then CTRL-C'ed to another job and back to QDOS, the
screen that was present when I EXECed it was saved and would
appear as I cycled through the jobs. Well, this was not what I
wanted. I puzzled over this until I ran across the page in the
Qliberator manual covering the compile time options. The -winds
option, when turned on, will automatically open a Channel #0, #1,
and #2 for the job. With it turned off, the job must open it's
own windows for output.
By default, Winds is turned on. This means that I had my own
Channels open. When I EXECed the job, the Pointer Environment saw
my Channels open up and saved the screen for me.
I then compiled the job with the Winds turned off (un-highlighted
in the QLib compiler window) and now when I EXEC it, the Pointer
Environment does not save the current screen.
A job can run in the background, open up a window, display output,
close the window, and still continue running in the background.
When the window is closed, the Pointer Environment will not save
the window, but let it disappear.
Reading the Keyboard Buffer
As a continuation of the discussion above, once you have a
background job, you may want it to sit quietly in the background
and wait for a certian keystroke, then pop up and do something.
This means that you need to keep track of what keystrokes are
happening.
One way of doing this is the use the KEYROW command. If you pick
a keyboard combination that is one the same keyrow, say CTRL-V,
then you can keep scanning the keyboard with KEYROW for that key
sequence. Below is a simple program to demonstrate this:
10 x = KEYROW(7)
20 IF X = 20 THEN : REM CTRL-V is value 20 on KEYROW 7
30 ....... do something
40 ....... more something
50 END IF
60 GOTO 10
Doing something could be a simple as a BEEP or more complicated as
open up a window, output some data, and closing it again. The
limitation doing it this way is that the keystrokes are not
captured by your program, but are only looked at, and they get
passed on to the underlying program. In this example, if the
underlying program does not understand the CTRL-V, then everything
is fine.
Another way is to look into the keyboard queue directly. This is
done my PEEKing into the System Variables area of memory. Since
the System Variables area can change location depending on what
version of QDOS is running (JS, Minerva, SMS/QE) you will have to
be carefull. There is a command in the DJToolKit called
SYSTEM_VARIABLES that finds out what version of QDOS is being run
and returns the appropriate location of the System Variables. If
you do not have this command, you will have to do the figuring out
yourself.
Here is a section of code taken from Screen Snatcher that looks
into the keyboard auto repeat buffer, which is similar to the
keyboard queue:
REM System Variables = 163840
REPeat loop
value = PEEK_W(SYSTEM_VARIABLES + 138)
IF value = snatch_key OR value = abort_key THEN EXIT loop
END REPeat loop
The PEEK_W returns the ASCII value of the key in the auto repeat
buffer. In QDOS, all possible key sequences, such as ALT-SHIFT-A,
has a specific ASCII value.
Stuffing the Keyboard Buffer
In a further continuation of the above discussion, now that we
have a background job that can read the keyboard queue, what about
adding characters to the keyboard queue, so that data can be sent
to other programs.
One way to do this would be to POKE some data into the keyboard
queue. There is a system variable that points to the keyboard
queue. You could POKE the text you want into the keyboard queue.
Not being an expert at the low level of QDOS, I do not know if
this would work or is safe.
If you have the HotKey System II, you can use some HotKey commands
to so exactly the same thing. You can add some text to the
Stuffer Buffer by using the command:
HOT_STUFF "Some Text"
or
HOT_STUFF text$
Now the user can use ALT-SPACE to place the information in the
underlying program (stuffing the keyboard buffer/queue). Or you
can do this for the user by using the following command:
HOT_DO ' ' : REM that's a space character
This will do the ALT-SPACE key.
Another way of doing the same thing is to use the QSEND toolkit.
It is discussed below.
Using STDOUT (Passing Channels to Child Job)
On page 10.3 of the Qliberator manual is a section entited
"Passing Channels to Jobs". This section explains how you can
pass a job a set of channels (say an open window) and have it
redirect it's ouput from it's own channels to the channels passed
to it.
On the next page is an example program. After some
experimentation it has been discovered that the example does not
work with the Pointer Enviroment (at least with the more recent
versions of it). The example does not totally fail, the user just
needs to cycle through the running jobs (by using CTRL-C) and when
it gets back to the job that passed the channels, the screen
output is updated.
Where this would be usefull is in creating programs to work well
with C68 programs. A default behavior of a C68 program is to see
if it has been passed any input/ouput channels. If it has not, it
will open it's own Window for its input and output. If it has
been passed channels it will use those. This is very usefull when
running MicroEmacs. From MicroEmacs I can execute a program (say
unzip or mtools). Instead of the unzip or mtools opening up a new
window, the output from it is put in the MicroEmacs window.
It would be nice to write compiled SuperBasic programs that have
this behavior so that they could be run in Adrian Ives' SHELL
along side with C68 programs. I've never been a great C
programmer, but I would like to write programs that work well
under SHELL.
Linking in ToolKits
One little hint that applies to using extensions from the
SuperBasic command line, but it may apply to using them in
programming: When an extension is called it is started with an
EXEC_W. This means that you can't CTRL-C out of it. If you use
an exclamation mark (!) at the end of the name of the extension,
then it will be started with an EXEC.
An example of this would be this: take the following program,
REMark $$external
DEFine PROCedure CAT
DIR flp1_
PAUSE
END DEFine CAT
Compile it with Qliberator, LRESPR it (or OVERLAY it), and run it
from the command line by typing CAT. Now run it by typing CAT!.
Kind of a neat trick and something nice to know. (Thanks to Ralf
Reokoendt)
Creating Toolkits (Loadable Extensions)
One of the things that has always amazed me about the QL was
the ability to load a binary file and have a bunch of new
keyboards available in SuperBasic. In most computers that
had Basic built in, the language was static and had no way to
extend itself. Other languages (like C, Fortran, or Pascal)
used libraries of functions and procedures to extend the
capability of the library.
The first major loadable extention to the QL was ToolKit.
From then on the term toolkit has been used in reference to
loadable extensions. Popular toolkits are ToolKit II (TKII),
DIY ToolKit, and DJToolKit.
I knew that the first of these toolkits were written in
Assembly, but I did not know that they could be created by
Qliberator. It seems that QDOS executables and extensions
are real close in format and when compiled right, they can be
interchangable. This means that an executable can also be
loaded as an extension.
To figure out how to create a toolkit, I grabbed a simple
function, Qliberator, and gave it a try. The function is
included below:
10 REMark $$external
100 DEFine FuNction upper$(up$)
110 LOCal x, temp
120 FOR x = 1 TO LEN(up$)
130 temp = CODE(up$(x))
140 IF temp > 96 AND temp < 123 THEN
up$(x)=CHR$(temp-32)
150 NEXT x
160 RETurn up$
170 END DEFine
The function takes any string and converts it to all upper
case letters. The $$external is a compiler directive to
Qliberator that tells it that the next function or procedure
needs to be available outside of the executable. For each
procedure or function that you want to turn into an
extension, you would have to put the $$external directive in
front of it.
If I was to put an additional line in the program,
180 PRINT upper$("This is a test")
then when I executed the program, line 180 would be executed.
If I LRESPRed the program, the keyword upper$ would be made
available.
When compiling the program it is a good idea to turn WINDS
off, since the extension will have no channels open.
Otherwise 3 channels will be opened for it, wasting them. To
lower the size of the binary file, turning off NAMES and
LINES might be a good idea. Note that the case of the
function or procedure will be maintained in the extension.
In my example, the name that will show up when entering
EXTRAS is "upper$" (all lower case). If I defined the
function a UPPER$, then "UPPER$" would show up in the EXTRAS
command. By convention, extensions should be done in all
upper case.
If you will be running the extension on a system that already
has the Qlib runtimes loaded, then compile the program
without runtimes. If you don't know if the Qlib runtimes
will be available, compile it with the runtimes included. It
is a good idea to compile both ways and let the user decide
which one they need. The example program when compiled
without the Qlib runtimes was 594 bytes. With the Qlib
runtimes it was 11,146 bytes. The runtimes take up a fair
bit of space.
If you load an extension that does not have the Qlib runtimes
on a system where the Qlib runtimes are not loaded, you will
not get an error message when you LRESPR the extension. When
you call the extention is when the error will occur. The
exact error message is:
Error "Runtimes Missing !"
Once you have compiled an extension, all that is needed is to
LREPSR it and test it out. Remember that you can't LRESPR
while any jobs, other than Job 0 (SuperBasic), is running.
Overlays
When I heard a well-known Qliberator user profess that he was not
sure that an Overlay was, I thought it would be a good idea to
discuss it a bit.
We all know what an Extension is; it is a binary file LRESPRed in
a BOOT program that loads some new SuperBasic keywords. This is a
nice feature of QDOS, but LRESPR (or just RESPR) has one key
problem - you can't LRESPR when there are any jobs running. So,
if you start up QDOS, load a BOOT program that at the end starts
the HotKey System II running, you can no longer LRESPR any
extensions. If you want to use an extension, you have to load it
an boot time or you have to kill all jobs to load it. So, most
users had a tendency to load as many extensions as they can in at
boot time. This can really take up bunch of memory, esp. if you
only use the particular extension rarely. Another workaround is
to create a second boot disk that you use only when you want to
use a particular application.
The OVERLAY command is just like LRESPR but it can be used at any
time. Any extension OVERLAYed by SuperBasic can be used by all
programs. If a program calls an OVERLAY then only it can use the
extension. Only 16 overlays can be used and is limited to a
particular process. This means that if SuperBasic uses 2 overlays
and a program uses 3 overlays, they don't count against each
other.
Once an extension is OVERLAYed, it can be removed from memory when
it is not longer needed by using the UNLOAD command. In this way,
OVERLAYs are very similar to Dynamic Linked Libraries, in that
they are called when needed and the released when they are done
being used. This is all very memory efficient, but it does come
at a small cost of the time it takes to load the extension.
The biggest problem with OVERLAYs is that only extension binaries
created with Qliberator (version 3.2 or later) can be OVERLAYed.
This means that if you want to OVERLAY an extension written
directly in assembly, you can't. This is a serious limitation as
most of the extensions available were not created using
Qliberator.
Given this limitation I can see OVERLAYs being used mostly to load
and unload your own extensions. If you compile a number of
functions and prodecures of a program in seperate chunks, then
these chunks can be load in as needed. If you are writing an
especially large program that consists of distinct units, then it
might be wise to load each unit as needed. This can allow the
program to run on systems with limited memory.
CONFIGURING A PROGRAM
Despite what ever settings you define in your programs, at
sometime the user is going to want to change them. Depending upon
the nature of your program, the number and type of settings that
you will let the user change will vary. Based on this and other
programming considerations, how you implment configuring a program
will also vary.
Types of Configuration
There are five different ways of configuring a program:
1] User Intervention.
2] Config Blocks.
3] Configuration File.
4] Command line Arguments.
5] Environment Variables.
User Intervention
This was probably one of the first way of being able to configure
a program. Most of the programs we use today have some sort of
User Intervention configuration. For example, with Quill, I have
menus that let me change the layout of the page. This includes
how many lines per page, how many lines for the upper and lowermargins, etc. When I start Quill, I have to change these settings
as they are only saved if saved in a document.
A lot of times User Intervention does not allow for the savings of
the settings.
Positives:
- Write as much help as necessary
Negatives:
- Lots of additional code to write
Config Blocks
Config Blocks are chunks of data appended to a executable that can
be accessed by the executable and altered by a standard
configuration program. Config blocks are unique to the QL world
and are non-transportable. The biggest feature of using Config
Blocks is that once a user knows how to use the 'config' program,
they can configure almost any executable. There is a simple
one-time learning curve. Config Blocks are good for programs that
a user will configure once or twice to meet there needs. You
would not want to use a Config Block for a program that needs to
be changed fairly often.
Positives:
- Standard Interface
- Easy to Use
- Error Checking Done by Config
Negatives:
- Have to Run a Program to Change
Configuration File
A Configuration File is probably the most flexable and powerfull
form of program configuration. A Configuration File can handle so
many different configuration items. Some programs, like the
editors DME and MicroEmacs, can totally change their behavior
through Configuration Files. The downside to Configuration Files
in the code necessary to read in and check the Configuration File
for errors (parse). This is a fair amount of code and will change
from program to program.
Positives:
- Very Flexible
- Good for Lots of Options
Negatives:
- Error Checking can be Hard to Write (parsing)
Command Line Arguments
Command Line Arguments are probably the quickest and most
transient of all forms of program configuration. They are added
to a command line after the program name. They will only take
effect for the one instance of the program. If a user needs to
make a number of configuration changes frequently, then Command
Line Arguments might be the way to go. A downside is that if you
have more than one command line argument, you have to parse the
different arguments to see which ones the user has typed in.
Positives:
- Quick Configuration Change
Negatives:
- Requires Parsing
- Not Good for Lots of Options
Environment Variables
Environment Variables are in that middle ground between the short
term Command Line Argument and the more perminent Config Block or
Configuration File. They will affect a program for more than one
instance, but they can be changed between program instances. In
other words, they hang around for as long as you need them, but
can be easily changed. Setting Environment Variables in a BOOT
program can make them seem perminate.
Positives:
- Quick to Change
- Easy To Use
Negatives:
- Bad for Lots of Options
- Requires ENV_BIN
- You Do Error Checking
Each of the options have their own place and their own benefits
and faults. Some are more perminate, like Config Blocks and
Config files, while some are very short lived, like User
Intervention and Command line Arguments. Enviroment Variables are
in between as they can be set in a BOOT program, but they can be
changed by just typing in a new command.
Config Blocks
A Config Block is a chunk of data attached to executable files that
have configurable items. The "config" program is used to change these
configurable items in the program, without affecting the actual
executable section of the code.
When writing a program, there are usually some parameters to the
program that are hardcoded. Things like, how big an array should be,
how much memory to allocate, and so on. There are two ways of letting
the user configure these parameters; writing a section of code to do
it, or having a configuration file.
Writing a section of the program to allow the user to change various
parameters is feasable, but it adds complexity to the program and it
takes time. Having a configuration file may seem cleaner but the
program would have to worry about the syntax of the file and how to
handle errors.
Somewhere in the history of the QL someone came up with a third option,
the Config Block. A Config Block is a part of an executable program
that can be edited by "config". It is not part of the actual code of
the program, but resided apart from it in a known location so that
"config" can find it. The data in a Config Block is read by both
"config" and the actual code of the program. The programmer writes the
program so that configurable paramters are read or grabbed from the
Config Block. The Config Block is created seperately and linked to the
program code to create the final executable.
As far as the operating system is concerned there is nothing special
about a program with a Config Block. It is EXECed just like any other
executable.
Definition of Config Block
Each Config Block is comprised of the following elements:
Configuration ID
Configuration Level
Software Name
Software Version
Config Item(s)
The Config Block only has one Configuration ID, one Configuration
Level, one Software Name, one Software Version, and one or more Config
Items. The Configuration ID and Level are preset by the program that
creates the Config Bock. The Software Name and Version is displayed
when using "config" so that the user knows exactly what program they
are configuring and can not be changed by the user.
The key part of the Config Block lies in the Config Items. This is the
actual data that the user can change. There are five different Config
Item types:
String
Long Word
Word
Byte
Select
Code
Char
A String is just that, a string. It can contain anything and is used
for having default devices (FLP1_, WIN1_,), default extensions (_DOC,
_TXT, _EXE), or any other character-based default.
Long Word, Word, and Byte are three different Config Items for storing
numbers of the three different sizes (8, 16, and 32 bit). The each
have attributes of Min and Max values. The value of each item can be
any number within the range of the Min and Max values.
Code is a single byte in length and is set to any number in a list of
numbers. If you want only the number 10, 15, & 20 to be possible
values for an item, Code is what you would use.
Select is the same as Code, but instead of the data being in the Config
Block, the value is a pointer to the actual data.
Char is a single character. It is used when only one character is
needed and not a whole string. One could use a String Config Item when
ever you need a character, but you would have to do the checking
yourself to make sure that only one character is used.
Each Config Item has the following Attributes:
Selection Keystroke
Description Text
Default Value
Option(s)
Selection Keystroke seems to have been designed to access the
Configuration Block from within an application program. When using the
"config" program, the Selection Keystroke has no meaning.
Description Text is what is printed to the user when "config" is
changing that Config Item. You would enter a line or two telling the
user what the Config Item is used for, what values are valid, suggested
values, etc.
Default Value is the value that is originally assigned to the Config
Item.
Options are possible limitations are the Config Items. For String
there is an Option of maximum length of the string. For Long Word,
Word, and Byte there are maximum and minimun limit Options. For Char
there are Options upper or lower case, printable or non-printable, and
cursor characters are allowed. Each Config Item has its own set of
options based on its data type.
Config Levels
There are two different versions or levels of Config Blocks, Level 1
and Level 2, or just called Config 1 and Config 2. Config 1 was
created first and is the most common Config Block. Config 2 is
relatively newer and just starting to be used by software developers.
Config 1 is modified by "config" and Config 2 is modified by
"MenuConfig".
*- Can MenuConfig edit a Config 1 Block?
*- What happens when 'config' tries to edit a Config 2 Block?
BASCONFIG - Adding Config Blocks to Qlib Compiled Programs
There is a utility called BasConfig that allows Config 1 Blocks to be
built for programs compiled by Qliberator. BasConfig creates a file
that has both the Config Block and the BasConfig extensions needed to
get the data out of the Config Block. This file is then linked into
the main program by Qliberator and becomes one executable.
*- Three versions - Oliver Fink, Norman Dunbar, Dilwyn Jones.
Programming with BASCONFIG
Since configuration data is stored in the Config Block there has to be
a way for the SuperBasic program to read it and use it. BasConfig
comes with a number of SuperBasic extensions that read the Config Items
from the Config Block. The extension could possibly be loaded into
memory to be used during program testing, but since there is no Config
Block present, I doubt they would work. There are two Config Item
types that is not supported by BasConfig; Select and Long Word.
The Config Block and BasConfig extensions are linked to the executable
program by Qliberator when it compiles the program. The following
compiler directive is used:
REMark $$asmb=ram1_file_ext,0,10
Because the extensions are not loaded in memory, Qliberator will have a
problem finding them. An EXT_FN line is needed in the program to let
Qliberator know that there are external functions and that they will be
resolved at linktime. The following lines are needed right after the
above REMark statement. You need only EXT_FN those extensions that you
use.
EXT_FN "C_STR$"
EXT_FN "C_WORD"
EXT_FN "C_BYTE"
EXT_FN "C_CODE"
EXT_FN "C_CHAR"
The BasConfig extensions are:
C_STR$(n) - String
C_WORD(n) - Word
C_BYTE(n) - Byte
C_CODE(n) - Code
C_CHAR(n) - Character
Each extension is used to retrieve a different Config Item data type.
The extensions return the Nth Config Item of the specific data type.
As example is:
$var = C_CHAR(2)
This will put the second CHAR Config Item in the variable $var.
Here is an example program:
100 REMark $$asmb=ram1_test_cfg,0,10
110 EXT_FN "C_BTYE"
120 OPEN #3,scr_100x100a50x50
130 PAPER #3,0: INK #3,4: CLS #3
140 item1 = C_BYTE(1)
150 item2 = C_BYTE(2)
160 PRINT #3,"Item #1 =";item1
170 PRINT #3,"Item #2 =";item2
180 PAUSE 500
190 CLOSE #3
The program will take the two Byte Config Items and print them out to
the screen.
Since you can not run a program with the BasConfig extensions in the
SuperBasic interpreter, here is a way to get around this problem and
limit the effect on your code testing. For each BasConfig extension
call, put in a LET statement along with a REMark of the call. The LET
statement works essentually as a definition of a constant. Here is an
example:
100 REMark C_CHAR(1) has a default value of "b"
110 REMark $var = C_CHAR(1)
120 LET $var = "b"
130 REMark C_BYTE(1) has a default value of 30
140 REMark x = C_BYTE(1)
150 LET x = 30
When it comes time to compile the final program, either delete the LET
statements or change them to REMarks, then unREMark the extension
lines. As long as you have the right data in the Config Block, the
program should run exactly as tested without the Config Block.
*- What happens if there is no String Item but a call is made to
C_STR$()?
*- What happens if there a call is made to any of the functions to n+1
items (1 more than the number of config items of a specific type)?
Using BasConfig to Create Config Blocks
Before running BasConfig, the programmer needs to determine the number
of Config Items needed and the type of each item.
Below is a listing of all of the questions asked by BASCONFIG.
Number of Items:
Enter the total number of Config Items that you are putting in this
Config Block.
Enter Software Name:
This is the name of the program that the Config Block will go into.
Enter Software Version:
This is the software version of the program that the Config Block
will to into.
Select Type for Item # :
Use the left and right arrow keys to toggle through the selections
until you reach the one you want. Hit return to accept the selection.
At this point the program changes and asks different questions for each
of the different Config Type.
String
Type Selection Keystroke for Item:
Enter any key as it is not used by "config".
Enter Max Length of the String:
Enter Default String:
Enter Description Text for Item:
This is where you tell the user what this Config Item is used for.
Special Characteristics:
Strip Spaces
Do Not Strip Spaces
The left arrow is used to toggle between the two selections, Strip
Spaces and Do Not Strip Spaces.
Char
Type Selection Keystroke for Item:
Type in Default Character:
Enter Description Text for Item:
Select Possible Characteristics:
Non-Printable Characters Allowed: (Y/N)
Digits Allowed: (Y/N)
Lower Case Letters Allowed: (Y/N)
Upper Case Letters Allowed: (Y/N)
Other Printable Characters Allowed: (Y/N)
Cursor Characters Allowed: (Y/N)
Non-Printable Characters Allowed covers characters that are not
normally printed on the QL. This would included characters like
Control Characters (CTRL-A, CTRL-B, etc.), the ESC character, etc.
Digits Allowed allows you to limit the character to only be a letter.
Lower Case and Upper Case Letters Allowed lets you define the case of
the character. Other Printable Characters Allowed ..... Cursor
Characters Allowed .....
Code
Type Selection Keystroke for the Item:
Enter Default Code Value (0-255):
Enter Description Text for Item:
Allow Selection Keystroke: (Y/N)
Not applicable, as using "config" the Selection Keystroke is not
used.
Enter Code (0-255) for Selection #1
Or Press ESC to Finish Code List
Enter String for this Code:
With Code, you are creating a list of possible values that the Item
can have. For each possible value there is a description string. The
list can be composed of 2 or more possible values. When you have
entered all of the possible values, the ESC key is hit to let BasConfig
know that you are done with the list.
Byte
Type Selection Keystroke for the Item:
Enter Intial Value for Byte (0-255):
Enter Description Text for Item:
Enter Min Value Allowed:
Enter Max Value Allowed:
Word
Type Selection Keystroke for the Item:
Enter Intial Value for Word (0-65535):
Enter Description Text for Item:
Enter Min Value Allowed:
Enter Max Value Allowed:
Updated Versions of BasConfig
Both Norman Dunbar and Dilwyn Jones have updated the BasConfig program.
Norman was the first to update the program and then Dilwyn took
Norman's version and further updated it. The program still remains
public domain.
Norman Dunbar Update
Norman Dunbar fixed a few unnamed software bugs and included the
support for Long Config Items. This includes the C_LONG() function
that returns the Nth Long Config Item. The questions asked by
BasConfig for a Long are:
Type Selection Keystroke for the Item:
Enter Intial Value for Long Word:
Enter Description Text for Item:
Enter Min Value Allowed:
Enter Max Value Allowed:
Dilywn Jones Update
Dilwyn Jones add the two additional functions: C_NAME$ and C_VERS$.
C_NAME$ returns that Software Name from the Config Block. C_VERS$
returns the Version Number from the Config Block. The gives the
programmer the option of getting the program name and version from the
Config Block instead of hard coding it into the program. Remember that
the user can not change either of these values when using the "config"
program.
Environment Variables
The concept of Environment Variables comes from the Unix world.
They are used slightly in MS-DOS, but not at all to the same
extent as UNIX. For the QDOS world, the file ENV_BIN provides a
number of extensions that allow the use of Environment Variables
on the QL.
Essentially an environment variable is a variable that can be
"seen" by exectuable programs. In SuperBasic we can set up all
kinds of variables, but if we execute a program from SuperBasic,
these programs can not "see" these variables and get data from
them.
The purpose of environment variables is to change the
configuration of a program. They function like Config Blocks, but
don't require running a program to make the change.
The ENV_BIN file comes with 4 extensions. They are:
SETENV - Defines an environment variable.
ENV_LIST - Lists all defined environment variables.
ENV_DEL - Deletes an environment variable.
GETENV$ - Gets the value of an environment variable.
The two key commands are SETENV and GETENV$. SETENV is used like
this:
SETENV "VARIABLE=value"
SETENV takes a string argument of the type "XXXXX=YYYYY" where
XXXXX and YYYYY are two strings separated by an equal sigh. Any
space before the equal sign is treated as a part of XXXXX and any
space after the equal sign is treated as a part of YYYYY. The
case of each string is important as "VARIABLE" is different from
"variable". By convention, upper cases is used for variables.
The SETENV is done either in a BOOT or setup program or by the
user. The command for an executable to get the contents of an
environment variable is GETENV$. The command is used like this:
a$ = GETENV$("VARIABLE")
In this case a$ will be assigned the value of "value". This comes
from our previous SETENV command above. If the Environment
Variable "VARIABLE" is not set (does not exist) then the GETENV$
would return a Null string ( "" ).
Now I did say the executables use GETENV$ and not SuperBasic
programs. Since variables are already used in SuperBasic, we
would not gain much in using environment variables. There thecommands are use is in compiled SuperBasic programs, which are
executables.
I see the purpose of using Environment Variables as adding to the
flexibility if programs that are use Config Blocks. Both Config
Blocks and Environment Variables are really designed to change
default program settings. User Intervention and Command Line
Arguments are designed to tell the program what the data is.
Using environment variables allows the user the ability of making
a temporary change to the default options of a program, without
having to go through the trouble of using "config". Environment
variables would be used to change a setting for a single session
and that's it.
Getting Config Blocks and Environment Variables to work together
is not difficult. The program would first get it's default
settings from the Config Block. It would then check to see if
there are any Environment Variables set. If there are, then the
Environment Variable settings would override the Config Block
settings.
FREEWARE PROGRAMMING EXTENSIONS
Adrian Ives Extensions
Adrian Ives has made a number of SuperBasic extentions available
on his web page. Of the four extensions, two are applicable to
programmers. These extensions are freeware and may be
redistributed with your programs. Since these extensions are
rather small, it may be easier just to link them into the final
executable instead of having the user LRESPR them.
IsRes_Rext
ISRES() is used to test for the presence of an extention. With it
you can tell if the QLib or Turbo runtimes are loaded. You can
tell if Environment Variable support is loaded. Once you know if
an extention is loaded, you can alter your program to either
support the extention or not. If a program supports Environment
Variables and, through ISRES(), it finds that ENV_BIN has not been
loaded, it can avoid making any ENV calls and not crash.
OS$_Rext
OS$() returns the a string identifying the version of QDOS
running. OS$() returns the following values:
QDOS - Standard QDOS
SMSQ - Any version of SMSQ
Minerva - Any version of Minerva
Your application can change behavior based upon what version of
QDOS it is being run under. This function allows a program to use
the expanded facilites of SMSQ and Minerva while not requiring it
to be run on SMSQ or Minerva.
Display Code
This is a small suite of 9 basic extensions written in assembler
designed to help SuperBASIC or SBASIC programmers cope with
extended display modes on more recent hardware and emulators such
as Aurora, QPC and QXL.
Although extensions are built into SMSQ allowing easy checking of
such details as screen size and location in memory, programs using
those extensions are limited to running on systems with SMSQ and
SBASIC.
These extensions will work on SMSQ and QDOS, providing a means of
consistently returning the required information, allowing programs
a means of working on all systems. Graphical applications often
need to write direct to memory, or at least to know the screen
size and location details. That's the sort of information this
code will allow you to extract from the system.
Over the years, many programs were written which were later found
not to work on displays other than the original 512x256 QL screen.
The forward-thinking designers of the QL had actually allowed for
the possibility of larger screen sizes by including information in
the system which was available to machine code programs, but not
to SuperBASIC programmers. As the information about this was not
readily documented and available or widely understood in those
early days, many programs just assumed the original QL display and
hence could not work properly when the size and location of the
screen memory changed - I know, I wrote such programs myself! This
set of extensions won't fix those early programs of course, but
does give a simple means of extracting this information for
SuperBASIC and SBASIC programmers so that new programs at least
won't be guilty of the same sins. To be fair, with the benefit of
hindsight it is easy to refer to those old programs as being
sinful, though at the time the necessary information was neither
readily accessible nor widely understood.
The files are on the cover disk - look for DISPLAY_CDE and
DISPLAY_ASM. You can simply LRESPR FLP1_DISPLAY_CDE if Toolkit 2's
LRESPR command is available (remember it may give a 'not complete'
error if there are any jobs running at the time), or add this to
your boot program:
base=RESPR(598):LBYTES FLP1_DISPLAY_CDE,base:CALL base
I hope that the names I have given the extensions don't clash with
anything you already have installed on your system. If there is a
clash, you'll need to either hack the names of the extensions in
DISPLAY_CDE using your preferred editor, or reassemble the source
code file DISPLAY_ASM after altering the names in the dc.b
statements in the table.
There are eight functions and one procedure:
ADDRESS LET adr = ADDRESS(#channel)
This function returns the base address of the display for the
given window channel. Normally you'd use #0. For a 512x256.
Normally, you'd only need this value if you were writing programs
which wrote directly to the screen area, e.g. using LBYTES to load
a screen direct to the video area of memory, using a command such
as LBYTES filename,ADDRESS(#0) assuming the screen being loaded
was the same size as the current display.
BYTES LET bytes_per_line = BYTES(#channel)
The display is organised as a series of horizontal lines, with
each line being a given number of bytes wide. In several display
sizes, the exact width of these lines in bytes happens to be the
number of pixels DIV 4, but this is a dangerous assumption to make
- many programs made this assumption and fell over when the Aurora
came along, as some of its display modes use a fixed line width,
irrespective of the number of pixels on a line, meaning that some
of the bytes used to store each line are actually unused. So if
you are writing individual lines to the screen, as you would for
video effects for example, you need to take account of how many
bytes there are between the start of one line and the next. That's
the purpose of this function - it tells you how many bytes lie
between where one line starts and the next line starts. Users of
version JM or earlier ROMs should note that this information is
not available, as the area which holds this value is used for
something else, so a version JM machine always assumes it has a
128 byte line width.
DMODE LET display_mode = DMODE
Returns the mode number of the current display. This would usually
be 0 for the 4 colour modes, and 8 for the 8 colour modes. As the
routine uses the mt.inf system trap, it ought to handle the
extended colour mode drivers, or monochrome modes on certain
emulators (both cases untested at the time of writing). I am not
sure what will happen if this function is used while one of the
old mixed mode screen displays are used (there are extensions in
Quanta library I think which allow part of the screen to be in
MODE 4 and part in MODE 8, for example)
SYS_VAR LET system_vars = SYS_VAR
Tells you at what address you can find the system variables. Now
you can PEEK and POKE to your heart's content if you really need
to!!!
The FLIM_n extensions return information about the maximum sizes
or limits of a screen window size. As it uses the iop.flim trap,
it means the information can't be extracted if this is not
implemented on your system. But I thinkI'm right in assuming that
if iop.flim is not on the system for whatever reason, the system
can't use extended displays anyhow. If it can't get the required
information, it assumes you're running a 512x256 QL screen rather
than unhelpfully causing an error report. If you supply a primary
channel window, the values returned will be the maximum possible
size for that window (essentially the full display width and
height), whereas if you supply a secondary channel number the
values returned refere to the outline area for the primary. If you
don't know what this means, supply the lowest window channel
number opened, e.g. #0 for BASIC. The first two extensions return
origin details, whereas the other two return the width and height
details.
FLIM_X LET x_origin = FLIM_X(#channel)
FLIM_Y LET y_origin = FLIM_Y(#channel)
FLIM_W LET wide = FLIM_W(#channel)
FLIM_H LET high = FLIM_H(#channel)
MOVEMEM from_address, to_address, number_of_bytes This procedure
lets you move the content of memory around. Simply tell it where
to move from, where to move it to, and how many bytes. Negative
values will cause errors. There is no check on overlaps etc so
with care you can use this to fill memory areas by writing the
first byte value with a POKE, for example, then moving this up to
fill the required number of bytes. It always moves from lower
addresses first - there is nothing particularly intelligent about
this command in terms of working out the best way to move things.
It is quite slow by comparison with similar commands in other
toolkits.
EXAMPLES OF USE
It may be more instructive to list a few simple examples of how to
use these extensions for simple applications. These routines are
on the cover disk, in a file called DISPLAY_bas. Note that they
use the Toolkit 2 extensions ALCHP and RECHP for allocating and
deallocating temporary buffer areas in the common heap area of
memory. Most systems these days have Toolkit 2 or equivalent
commands so this should not be a problem.
1. FULL SCREEN WINDOW
This routine shows you how to set a window to occupy the full
screen, or the full outline area available to it if it is a
secondary window. To make channel #0 occupy the full area of the
screen, enter the command FULL_SCREEN #0.
If you tried the same thing on channel #2 on a VGA display, for
example, #2 would be set to the maximum possible area as covered
by the outline for the primary channel, in this case, #0, which
would normally cover #0 and #1 and #2 in BASIC.
The procedure leaves the actual values in the variables dw and dh
(width and height) and dx and dy (origin co-ordinates). Note that
this routine doesn't actually do anything visibly, you may need to
do a CLS command on the channel concerned, for example, to see its
effect.
2. STORE A SCREEN IN MEMORY
This routine sets up an area in the common heap to store a copy of
the current screen. The address of this area is given by the
variable "area". We work out the start address of where to copy
from the screen using the ADDRESS function, and the total number
of bytes to copy is calculated by the product of the number of
bytes per line (given by the BYTES function) and the height of the
screen (given by the FLIM_H function). Note that when using
512x256 mode on the Aurora, for example, this routine will save
the whole memory used for the screen, not just the visible area,
as Aurora uses a fixed line length unrelated to the actual number
of pixels used on the current display, meaning that although you
only see 512 pixels across, for example, the line used to hold
this diplay is 1024 bytes wide, but only 512 used and visible, so
the calculation is not as obvious as might be thought at first. A
typical application of this little routine might be to store
agraphical screen in memory while a menu is superimposed on the
picture. The variable "screen_length" holds the actual length (in
bytes) of the screen saved.
3. RESTORE A SCREEN FROM MEMORY
This routine restores the screen saved by the previous procedure,
and releases the memory area used to store it, by using the RECHP
command frm Toolkit 2.
4. MERGE SCREEN
There is a large number of clipart screens available for the QL,
mostly as 512x256 QL screens. In the old days, when each QL had
the same size screen, it was easy enough to load these direct to
the screen with a simple LBYTES filename,131072 command. Not only
doesn't this work on modern large displays, it might actually
crash the system in sme cases, since the area of memory previously
used by the screen may now be used by something else. This routine
tackles this problem by loading the 32k (512x256 pixels) screens
into a buffer area in the common heap, then copies it line by lineinto the top left corner of the display. Note how two variables
are used to keep track of where each line starts. With old 512x256
screens, we know they are 128 bytes wide, so it is easy enough to
step through them 128 bytes at a time. The other variable is
incremented by the width of each display line, given by the BYTES
function. Of course, writing direct to the screen is not the done
thing, and the picture may well be ruined if another job is
writing to the screen at the same time! Finally, when the transfer
is complete, the heap memory is released with the RECHP command.
4. FILL MEMORY A task which arises now and again in programming is
to fill a given area of memory with a particular value. This
routine takes advantage of how the MOVEMEM command works. The
command should be issued in this form: FILL_MEM
start_address,how_many_bytes,what_value The routine works by
setting the first byte of the area to be filled, using the POKE
command. Then, it copies this up one byte with the MOVEMEM
command, which repeatedly copies each byte up one address, thus
the byte copied is always the value of the previous byte and the
area is filled with the value of the first byte fairly quickly.
Another example: if you wished to turn the entire display black,
then you could issue the following command. This is quite a
naughty way of doing things, but it serves to illustrate how the
command works: FILL_MEM ADDRESS(#0),BYTES(#0)*FLIM_H(#0),0
5. SYSTEM_VALUE This routine reads a value from the system
variables. You don't need to supply the absolute address, just the
offset as published in several QL technical manuals. The routine
adds the offset to the base address, peeks a value from there and
returns it as the value of the function. LET value =
SYSTEM_VALUE(offset) For example, PRINT SYSTEM_VALUE (140) prints
the value of the auto repeat delay, while PRINT SYSTEM_VALUE(55)
prints the network station number.
6. SET MODE Some programs which need to switch between 4 colour
and 8 colour mode often set the screen mode (causing an irritating
flashing) even if the screen was already in the required mode. A
short routine like this can check the current mode and only change
it if it is the wrong mode, thus preventing the flashing of
windows you get when changing mode to the same mode.
REMark example routines for use with DISPLAY_CDE
REMark written by Dilwyn Jones, June 1997
DEFine PROCedure FULL_SCREEN (channel)
dw = FLIM_W(#channel) : dh = FLIM_H(#channel)
dx = FLIM_X(#channel) : dy = FLIM_Y(#channel)
WINDOW #channel,dw,dh,dx,dy
END DEFine FULL_SCREEN
DEFine PROCedure STORE_A_SCREEN
screen_length = BYTES(#0)*FLIM_H(#0)
area = ALCHP(screen_length)
IF area < 0 THEN PRINT #0,'Unable to reserve memory.' : RETurn
MOVEMEM ADDRESS(#0) TO area, screen_length
END DEFine STORE_A_SCREEN
DEFine PROCedure RESTORE_A_SCREEN
IF area > 0 THEN
MOVEMEM area TO ADDRESS(#0), screen_length
END IF
RECHP area
END DEFine RESTORE_A_SCREEN
DEFine PROCedure MERGE_SCREEN (filename$)
REMark merges a 32K 512x256 screen onto the top left corner of a
larger display
area = ALCHP (32768)
IF area < 0 THEN PRINT #0,'Unable to allocate memory.' : RETurn
LBYTES filename$,area
from_address = area
to_address = ADDRESS(#0)
FOR a = 1 TO 256
MOVEMEM from_address TO to_address,128
from_address = from_address + 128
to_address = to_address + BYTES(#0)
END FOR a
RECHP area : REMark finished with it
END DEFine MERGE_SCREEN
DEFine PROCedure FILL_MEM (addr,no_of_bytes,byte_value)
POKE addr,byte_value
MOVEMEM addr TO addr+1,no_of_bytes-1
END DEFine FILL_MEM
DEFine FuNction SYSTEM_VALUE (what_offset)
RETurn PEEK(SYS_VAR+what_offset)
END DEFine SYSTEM_VALUE
DEFine PROCedure SET_MODE (mode_number)
IF DMODE <> mode_number THEN MODE mode_number
END DEFine SET_MODE
Database Handler (DBAS)
DBAS is a collection of extensions that support Database actions.
Instead of creating a whole new language to support databases, the
DBAS extensions have been created to support databases in
SuperBasic. With DBAS a programmer has all of the tools for
creating a database application, including creating and editing a
database and report generation.
DBAS is not to be used by a general user, as Archive is, but to be
used by a programmer to contruct an application based around a
database. The DBAS extensions are designed to let the programmer
handle databases as channels (or files).
PROCEDURE SUMMARY
ADD_FIELD Add a new field
APPEND Add a new record
COPY_DATA(_O) Copy a database
CREATE(_O) Create a database
CLOSE_DATA Close a database
EXCLUDE Deselect records
EXCLUDE Deselect all records
EXPORT(_O) Export a database
FIND(C) Find by INSTR
IMPORT(_O) Import a database
INCLUDE Select records
LOAD_NAMES Reload name list
LOCATE Find by ORDER parameters
OPEN_DATA Open database - modifyable
OPEN_DDIR Open database - directory
OPEN_DIN Open database - read only
ORDER Unorder a database
ORDER Order a database
REMOVE Delete a record
REMOVE_FIELD Remove a field
REMOVE_NAMES Remove field names
RESET Reset record selection
RPOSAB Goto absolute position
RPOSRE Goto relative position
SAVE_NAMES Save field names
SCPTR Set compare table
SEARCH Find by INCLUDE parameters
SET Set a field
SEXTRA Set extra information
SUBF_ADD Add subfields
SUBF_REM Remove subfields
SUBF_SET Set a subfield by number
SUBF_SETO Set a subfield by offset
SORDKEY Set order key length
STNAME Set a field name
UPDATE Update a record
FUNCTION SUMMARY
COUNT Get record count
DBADDR Get the control address
FETCH Get field contents
FEXTRA Get extra information
FLLEN Get field length
FLNAME Get a field name
FLNFIND Get number of field name
FLNUM Get field count
FLTYP Get field type
FOUND Get found flag
RECNUM Get current record number
SUBF_FETCH Get subfield
SUBF_FCURR Get subfield by offset
SUBF_FNEXT Get next subfield
SUBF_NUM Get subfields count/number
DBAS is a very complex package with lots of power. A tutorial on
using it is beyond the scope of this document and does require a
whole book of it's own. It has been added here to bring awareness
to it and for completeness. DBAS is probably one of the most
powerfull and under utilized extension packages in QDOS.
QSEND
QSEND is a package of functions created by Hans-Peter Recktenwald
that allows one program to control another program by simulating
keyboard input. With QSEND you could have a program automate
another program like Quill.
The QSEND package consists of the following functions:
KEYQ(jobnumber) - Get "QDOS-Channel" of a job
QKEYQ - Get "QDOS-Channel" of active job
QSEND([#]channel,text$) - Send string to job at channel
PCONNECT([#]send_chan,[#]recieve_chan) - Pipe between jobs
Before sending any data from one job to another, you have to get
the "QDOS-Channel" of the job you want to send the data to. KEYQ
takes an argument of a QDOS job number and returns the
"QDOS-Channel" number. It is used like this:
LET qchan = KEYQ(2)
If you are writing a program that another user may use, you may
not want to have the user find out what job number the recieving
job is. The best way to do this is to find the job number via the
job name. Unforturnely I am not aware of an extension that will
return a job number given a job name.
QKEYQ works similar to KEYQ but it returns the "QDOS-Channel" of
the currently active job. This means that when QKEYQ is called
and Quill is the program with the cursor, then Quill's
"QDOS-Channel" will be returned.
Now that you have the "QDOS-Channel" of the job you want to send
data to, the next step is to use the QSEND function to send the
data. QSEND is used like this:
LET text$ = "This is a test"
LET result = QSEND(qchan,text$)
The variable 'result' will return either an error code or how many
bytes where sent. The return codes are:
result > LEN(text$) - all data was sent
result > 0 - the amount of bytes sent
result = 0 - no data was send
result < 0 - a QDOS error occured
Using QSEND with the comma (,) seperating the "QDOS-Channel" and
the string, not all of the string is guarenteed to be sent. So,
to make sure that all data is sent, the following construct can be
used:
sent = 1
length = LEN(text$)
REPeat loop
result = QSEND(qchan,text$( sent TO))
sent = sent + result
IF result < 0 OR sent > length THEN EXIT loop
END REPeat loop
IF sent < 0 THEN PRINT "ERROR #";sent
Another way is to use QSEND with a exclamation mark (!) seperator
instead of the comma. This will tell QSEND to use an unlimited
timeout and not return until all of the data is sent. Using QSEND
will look like this:
QSEND(qchan ! text$)
One thing to remember with QSEND, any programs that are not the
current job will not have thier screens output updated until they
become the current job. If you run a quick test with QSEND and
Quill, you will notice that the text sent to Quill will not show
up in Quill until you CTRL-C to Quill, where it will quickly
appear. If Quill is the current job, and the QSEND program is
running in the background, then the text will show up immediately.
A string sent via QSEND can be any string, including control
characters. To control Quill and send an F3 key (to get to the
menu), you can put the F3 key (code 240) into a string by doing
the following:
F3$ = CHR$(240)
Now if you send F3$ to Quill via QSEND, it would be just like
hitting the F3 key. In this manner, all keystroke combinations
can be sent via QSEND.
PCONNECT is used to connect two pipes or pipe sender with a
CONsole reciever. An example is using it to also send data to
Quill.
pipe_chan = FOPEN("PIPE_200")
qsend_chan = KEYQ(quill_job_number)
pcon_chan = PCONNECT(#pipe_chan,qsend_chan)
IF pcon_chan < 0 THEN error
PRINT #pcon_chan,text$
This routine opens a QDOS pipe. It then gets the "QDOS-Channel"
of Quill. It then connects the QDOS pipe channel to the Quill
"QDOS-Channel". Now you can treat Quill as another other channel.
Now instead of using QSEND to send data to Quill, you all you have
to do is use PRINT.
What good is QSEND? You can use it to write some fairly complex
macros for programs that don't have a macro language. You can use
it to write a program to create an auto-running program demo.
DIY Toolkit
The DIY Toolkit comes from a long running series of articles from
"QL Word" magazine by Simon Goodwin. The toolkit comes with
extensions from each article in a seperate file and with seperate
documentation. The whole toolkit is fairly large.
1. ALIAS and DEF$
Lets you add extra names for a given extension and choose
procedures and functions by name from a menu, for editing or
programming.
2. Basic Tools
Explore SuperBasic interpreter memory; ten demos e.g. FORGET (for
keywords), POP (RETurns), and WHY, for structured debugging.
Extensions: BPOKE, BPOKE_W, BPOKE_L, BPEEK%, BPEEK_W%, BPEEK_L%.
3. Channels
USE sets SuperBasic default channel; CHAN functions access window
settings. Extensions: CHAN_B%, CHAN_W%, CHAN_L%, USE.
4. Error Control
Full editing of default in limited space; avoid coercion errors;
zap all tasks. Extensions: PURGE, CHECK%, CHECKF, EDLINE$.
5. File Tools
CustomKit builds toolkits from _CODE & _BIN files. EPROM compiler
makes ROM images. Task Commander turns compiled tasks into
multi-threaded SuperBasic extensions. File Header extensions:
GetHEAD, SetHEAD.
6. Graphics
Faster & more precise, to suit all QLs and Thor MODE 12 bonus, as
well as several decorative demos. Extensions: PLOT, DRAW, PIXEL%.
7. Heap and Horology
Four 20ms stopwatches; SHOW_HEAP RAM explorer and info. MAPper
for memory. Extensions: LINKUP, RESERVE, DISCARD, T_ON, T_OFF,
T_START, T_STOP, T_COUNT.
8. Serial Mouse
Routines to support a two or three button Microsoft or Mouse
Systems "PC" serial mouse. Compatible with the Amiga QDOS 'bus'
mouse driver at the SuperBasic keyword level.
9. Jobs
Multi-tasking the DIY way, with excellent compatability without
gobbling RAM; Task Control toolkit plus TASKFORCE ( names task
taking input ), PSION_PATCH, TASK_RENAME, and ADDNAME programs.
10. Hewlett Packard PCL Printer Routines
Adjustable resolution shaded dump routines for the HP PCL printers
(Deskjet, Laserjet, etc.). Also documents PACKBITS compression
and color separations. Plus routines to do interesting things
with text printed on an HP printer.
11. MultiBasic
MultiBasic compatible multiple SuperBasics for any QDOS sytem.
The new version 4.0 can swap screens as well as programs and
variables. Extensions: UNLOAD, RELOAD, RESAVE, REMOVE, SCR_SAVE.
12. Networking
Three improved NETPALs issue commands remotely on QL, Minerva, or
Thor. MEM - a new QDOS device to share memory between tasks or
computers.
13. Pipes and Parameters
Machine code power from SuperBasic extensions, plus SEARCH_PROG
and CAT columnar directory demos. Extensions: PARTYPE, PARSEPA,
PARHASH, PARNAME$, UNSET, QLINK, QCOUNT%, QSPACE%, QSIZE%.
14. Queues and QDOS
QUEUE% types into programs; QLIST scans keyboard queues; CHLIST
name all open channels. Extensions: CHBASE, SYSBASE, QUEUE%.
15. Replace
Exchange variable, array and device names, or look up details;
case converters. Extensions: LOWER$, UPPER$, NEWCHAN% LOOKUP%,
REPLACE.
16. Qlipboard
Scan characters in any size or color into SuperBasic strings or
type them into any other task. Full task including text editor.
17. Traps
QDOS, Minerva, and Argos system calls ('traps') documented and
demonstrated with easy-to-use SuperBasic extensions and assembly
code.
18. Environment Variables
Share strings and numbers between concurrently running tasks and
SuperBasic. Also includes documentation and a demonstration of
'User Heap' management.
19. More
Page through files or memory quickly and easily, with indication
of your current position.
20. Windows
How to save, restore, and move images in QDOS windows.
21. Msearch & Vocab
Look through the vocabulary of your SuperBasic interpreter for
variables, resident commands and functions, or SuperBasic
DEFinitions. MSEARCH is a fast, flexible search routine.
22. Flexynet
A simple replacement drive for QLAN (the Sinclair network) which
can go faster than the original and adjust to mis-matched system
speeds.
23. Array Search Routines
SuperBasic numeric array and string array search routines in
assembler, with source code and explanations.
The DIY toolkit and it's accompanying articles is a great place
for exploration and learning.
Client Server Manager
Client Server Manager is a toolkit from Jonathan Hudson that
supports true client/server communications on a single QL. The
traditional view of client/server consists of a server process
(program) that waits to handle requests from client processes
(other programs). The client does not necessarily need to be on
the same computer as the server. A web server and web browser are
examples of client/server programs.
Jonathan has use CSM in the creation of his applications (QEM,
QFAX, QTPI, etc.). All of these have a CSM server component. The
user can then send CSM client requests to control the
applications. A combination of SuperBasic with CSM client
commands form a macro language for these applications. This saved
Jonathan the time and effort in writing a macro language
(including a parser) for each application.
How CSM works is like of like this: Before CSM can be use, the
CSM toolkit is loaded (LRESPRed). Part of the toolkit is a Thing.
When a server program is started it registers itself with the CSM
Thing. When a client program starts, it declares which server it
wants to talk to. The CSM Thing handles the message passing
between the client and server, since it knows where both are. The
client makes a request to the server, the server gets the request,
figures out what to do with it, and send a reply. The actual
contents of the request and the reply are up to the programmer and
is not defined in CSM.
The following keywords are added by CSM:
SERVER 'name' [,buffer] - Declares program as server 'name'
CLIENT 'name' [,buffer] - Delcares program as client 'name'
LISTENER 'name' [,buffer]
- Declares program as listener 'name'
REQUEST 'name','command' [,res$]
- Client request to server 'name' of type 'command'.
LSTNPOLL ('name', bro$ [,timeout])
- Listener polls for a broadcast message from server.
SRVPOLL ('name',req$ [,timeout])
- Server polls for request from client 'name'.
SRVREPLY context,res$ - Server reply.
SRVBRO 'name', bro$ - Server broadcast to LISTENERs.
FREECLIENT 'name' - Releases client from server.
FREELSTN 'name' - Releases listener from server.
FREESERVER 'name' - Terminates server.
FINDSERVER ('name') - Check for presence of server 'name'.
SVRPEND ('name') - Check for pending requests.
GetStuffed
With tongue firmly in cheek, Jonathan Hudson has written a one
function toolkit that does one thing, it gets the contents of the
Hot Key System II Stuffer Buffer. The function is a called
GET_STUFFED, hence the tongue in cheek. The function is used like
this:
a$ = GET_STUFFED
Now a$ will contain whatever was in the Stuffer Buffer. If the
buffer was empty, then a$ will contain the empty string ("").
That is all that the function does. As simple as it is, it is a
very handy tool and may be one of these functions that can make a
program work.
Tools To Assist in Programming
Structured SuperBasic
Structured SuperBasic (SSB) is a tool that was originally designed
to add line numbers to a SuperBasic program created using a text
editor. It has progressed to allow a number of options in writing
SuperBasic programs. SSB takes a program, written in the SSB
style and converts it into a form that can be loaded into
SuperBasic. SSB processes the code and depending on commands in
the code does a variety of things. For those familiar with the
term, SSB can be thought of as a form of preprocessor.
SSB supports the following options:
Include Statements - Add in code from another file.
Conditional Compilation - Depending on Define statements,
different code parts can be either passed through SSB or not.
Blank Lines - Blank lines between statements. No longer a need
for lines with just colons (:) on them.
Labels - Since lines are not numbered, labels are used for GOTO
and GOSUB statements.
Conditional Remarks - Some Remark statements are not passed
through SSB.
Long Lines - A single SuperBasic line can extend across two
lines.
With Structured SuperBasic you don't need to worry about line
numbers, esp. when adding code from other sources. If you like to
create libraries of SuperBasic code in seperate files, with SSB
you don't need worry about what line number are in each file. You
just use the Include statements to add the code to a program. SSB
takes care of the rest.
Because SSB allows you to easily not use line numbers, other tools
can then be used in maintaining your code. A good tool is the
Revision Control System (RCS), a tool for keeping track of
different versions of source code.
ProcMan
This programs allows you to extract selected procedures or
functions from SuperBasic programs. It requires the Pointer
Environment and the QMENU extensions.
The program can be configured using the standard program "config".
You can change the default drive for loading, saving, default file
extension for SuperBasic programs, and the default printer device.
When you first execute the program, you are given three choices;
Continue, Quit, or Button. If you choose Button, the program will
become a button in the Button Frame. Continue goes on with the
program.
Once into the program, a file select menu pops up. From here you
choose which SuperBasic program you want to extract some code
from. The program will then read the SuperBasic file, collecting
all of the names of the Procedures and Functions. The next step
is to select which Procedure or Function you wish to extract from
the file. You may select one or more items. Once you are done
selecting, click on OK to continue.
Now you can either print the selected Procedures and/or Functions
or send them to a file. If you select File, you need to enter a
file name. The program will now extract the source code you
selected and put it into the new file.
Once this is done, you can either Continue (and do it all over
again) or Quit.
Editors
SuperBasic (and QDOS) has a built in editor (albeit limited) for
editing SuperBasic programs. Toolkit II expands the editing
capabilities with the ED command, giving a full screen editing
capability to SuperBasic. One of the biggest advantages of the
built-in editing capabilites of SuperBasic is its automatic syntax
checking. As you enter each line, SuperBasic checks the syntax
and complains about an error if the syntax is bad.
As usefull and handy the built-in editing is, for longer
SuperBasic programs, it leaves much to be desired. A number of
programmers have turned to text editors to make the creating of
SuperBasic programs easier. Each editor approaches the task of
editing differently, thereby giving each editor its own
personality, just like each programmer has their own personality.
Sometimes these personalities match, making a good working
relationship between programmer and editor, and sometimes they
don't. Fellings toward editors are almost as strong as feelings
toward languages.
When using text editors, the idea is to type in as much of the
program as you can before you need to actually test the code.
Since most programmers code on the fly, using an editor allows you
to move quickly in the code, adding in lines where ever necessary.
It also allows you to write some of the program in pseudo-code,
coming back later to fill it in will real code. At this stage,
your program could be consider a rough draft. Only when it is
nearer its final draft stage is it ready to be loaded in to
SuperBasic and run.
When writing SuperBasic code using an text editor, you have the
option of including the line numbers youself, having the editor do
it, or using another utility (like Structured SuperBasic) to do it
for you. Some editors have a macro language that will allow you
to write a sort routine to automatically put line numbers in each
text line.
QED
QED, by Jan Bredenbeck(sp?), is a close of Metacomco's editor ED.
It is a fairly quick little editor that has a limited macro
ability. QED commands are entered on a command line at the bottom
of the screen. Besides having commands for moving the cursor, it
also has commands for Searching (Find) and handling Blocks of
text. A number of commands can be entered on the command line
including a repeat command. This can automate some simple
funcions, making for a form of macros. QEDs biggest advantage is
that it is small, quick, and fairly simple to use.
MicroEmacs
MicroEmacs comes from the Unix and MS-DOS worlds with ports to
other operating systems (Amiga, Atari ST, etc.). It is a very
powerfull editor with a full set of commands and a built in macro
language, including most of the control constructs of regular
languages. The command set is a bit on the complex side and can
take a while to learn. Fortuntely, the commands can be changed by
the user in a configuration file. The user can totally remap all
commands to new keyboard combinations. There is even a
configuration file to make MicroEmacs work like the popular MS-DOS
editor, BRIEF.
MicroEmacs allows cut-n-paste, editing more than one file (via
multiple windows), and some complex editing commands. Another
advantage is that, because it is available on different operating
systems, you don't have to learn a new editor for each different
OS. Thierry Godefroy has added Pointer Environment support
(including PE menus) and a link to QTYP II.
If you want more power in your editor that QED, then MicroEmacs is
a good choice. There can be a stiff learning curve, but you will
befenit in having more power with the editor.
elvis
Elvis is a clone of the standard Unix editor, VI (pronounced
vee-eye). Elvis is almost as powerfull as MicroEmacs, but it is a
whole lot more obtuse. The commands can look like gibberish and
be hard to learn. It is an editor built by Unix hackers for use
by Unix hackers. It's key advantage is that once learned, you can
use it on any Unix system and any other system have has a VI
clone. There is even a number of different books covering VI,
including one "Learning the VI Editor" that covers Elvis and a few
other VI clones. I see this editor as being on the QL to be used
by those that already know VI or those persons that want to learn
VI as they learn Unix. I don't recommend it for an average user.
               (
geocities.com/siliconvalley/pines/Pines)                   (
geocities.com/siliconvalley/pines)                   (
geocities.com/siliconvalley)